I am using Azure Mobile App Services and in the PATCH method I receive as body an object of type Delta (see MSDN).
I receive some fields with null values that I would like to remove from the Delta input object: how can I do this action?
e.g. I have a JSON input like
{
"Content":"test",
"CreatedAt":null
...
}
this maps an Entity that inherits from Microsoft.Azure.Mobile.Server.EntityData
e.g.
public class MyBean : EntityData
{
public MyBean() { }
public string Content { get; set; }
}
I would like to remove the field "CreatedAt", which by the way is declared in the EntityData parent object, part of the Microsoft library (therefore I don't have direct access to it).
I don't think you should try to remove the CreatedAt, but instead, take the incoming Delta and create a new one. You could either include the fields you wanted or exclude the ones you don't want.
var newDelta = new Delta<MyBean>();
foreach(var fieldName in patchDelta.GetChangedPropertyNames()){
if(fieldName != "CreatedAt"){
if(patchDelta.TryGetPropertyValue(fieldName, out object fieldValue)){
newDelta.TrySetPropertyValue(fieldNAme,fieldValue);
}
}
}
If you are using the Newtonsoft.Json to serialize the Entity then you can use conditional serialization of a property.
To conditionally serialize a property, add a method that returns
boolean with the same name as the property and then prefix the method
name with ShouldSerialize. The result of the method determines whether
the property is serialized. If the method returns true then the
property will be serialized, if it returns false then the property
will be skipped.
public class MyBean : EntityData
{
public MyBean() { }
public string Content { get; set; }
public bool ShouldSerializeCreatedAt()
{
return false;
// Or you can add some condition to whether serialize the property or not on runtime
}
}
Related
I have requirement in a custom class where I want to make one of my properties required.
How can I make the following property required?
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
If you mean "the user must specify a value", then force it via the constructor:
public YourType(string documentType) {
DocumentType = documentType; // TODO validation; can it be null? blank?
}
public string DocumentType {get;private set;}
Now you can't create an instance without specifying the document type, and it can't be removed after that time. You could also allow the set but validate:
public YourType(string documentType) {
DocumentType = documentType;
}
private string documentType;
public string DocumentType {
get { return documentType; }
set {
// TODO: validate
documentType = value;
}
}
.NET 7 or newer
Syntax
public class MyClass
{
public required string Name { get; init; }
}
new MyClass(); // illegal
new MyClass { Name = "Me" }; // works fine
Remarks
The required properties must declare a setter (either init or set).
Access modifiers on properties or setters cannot be less visible than their containing type, as they would make impossible to initialize the class in some cases.
public class MyClass
{
internal required string Name { get; set; } // illegal
}
Documentation
Official documentation here
Feature demo here
.NET 6 or older
See this answer
If you mean you want it always to have been given a value by the client code, then your best bet is to require it as a parameter in the constructor:
class SomeClass
{
private string _documentType;
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
public SomeClass(string documentType)
{
DocumentType = documentType;
}
}
You can do your validation – if you need it – either in the property's set accessor body or in the constructor.
With the release of .NET 7 and C# 11 in November 2022 you can now use the required modifier this way:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName) => FirstName = firstName;
public required string FirstName { get; init; }
public int Age { get; set; }
}
And when you don't have the required properties it will throw an error when you try to initialize an object.
For more information refer to:
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#required-members
https://learn.microsoft.com/en-us/dotnet/csharp/properties#init-only
Add a required attribute to the property
Required(ErrorMessage = "DocumentTypeis required.")]
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
For custom attribute detail Click Here
I used an other solution, not exactly what you want, but worked for me fine because I declare the object first and based on specific situation I have different values. I didnt want to use the constructor because I then had to use dummy data.
My solution was to create Private Sets on the class (public get) and you can only set the values on the object by methods. For example:
public void SetObject(string mandatory, string mandatory2, string optional = "", string optional2 = "")
This one liner works in C# 9:
public record Document(string DocumentType);
new Document(); // compiler error
new Document("csv"); // correct way to construct with required parameter
This explains how it works. In the above code, Document is the name of the class or "record". That first line of code actually defines an entire class. In addition to this solution essentially making a required DocumentType property (required by an auto implemented constructor), because it uses records, there are additional implications. So this may not always be an appropriate solution, and the C# 11 required keyword will still come in handy at times. Just using record types doesn't automatically make properties required. The above code is a special syntax way of using records that essentially has this effect as well as making the property init only and causes a deconstructor to be automatically implemented.
A better example would be using an int property instead of a string since a string could still be empty. Unfortunately I don't know of any good way to do extra validation within the record to make sure the string is not empty or an int is in range, etc. You would have to go deeper down the TOP (type driven development) rabbit hole, which may not be a bad thing. You could create your own type that doesn't allow empty strings or integers outside your accepted range. Unfortunately such an approach would lead to runtime discovery of invalid input instead of compile time. There might be a better way using static analysis and metadata, but I've been away from C# for too long to know anything about that.
I'm using the Options service to bind hierarchical configuration data.
But suppose I have a class like this:
public class PersonOptions
{
public string Name { get; set; }
public int Age { get; set; }
public bool Foo { // <--- I want binder to ignore this
get {
// ... do stuff
}
}
public bool IgnoreMe => // <--- I want binder to ignore this
throw new Exception();
}
Because the Foo property is public, the binder runs it and triggers some code that throws exceptions.
My design requires it to be public, and I prefer not to change it to a method.
Is there some attribute or override I can use to tell the binder to ignore that property?
The docs state:
All public read-write properties of the type are bound
If the property is public, then for some reason the binder runs it. Also, [JsonIgnore] isn't respected.
So unless I'm missing something obvious, this cannot be done.
The workarounds are:
use a non-public property
use a method instead of a property
I've added a feature request to the repo to support an "ignore" attribute.
UPDATE:
They've added the feature request to the backlog, so I assume what I wanted cannot be done, currently.
I am wondering if there is a way to set default value for a property in relation to other property of the same class in Json.NET e.g like this:
public class JsonsoftExample
{
[JsonProperty(Required = Required.Always)]
public DateTime Start { get; set; }
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue(Start.AddHours(1))]
public DateTime End { get; set; }
}
What I am trying to accomplish here is to populate End with DateTime value that is one hour later than Start in cases e.g when deserializing json to domain model and End value is missing or null. Like this:
string json = "{\"Start\": \"2017-01-01T08:00:00+01:00\"}";
var deserialized = JsonConvert.DeserializeObject<JsonsoftExample>(json);
The way I am doing it now is just inspecting later in code if End value is null in my domain object and if it is - populating it with desired value.
Is it feasible the way proposed in code sample or is there maybe a better simpler way except for the manual checking as in paragraph above?
As specified in the JSON standard, a JSON object is an unordered set of name/value pairs, so in general Json.NET does not allow one property to be set relative to another. Json.NET is a streaming, single-pass deserializer and there's no guarantee which will appear first in the JSON.
However, when your object specifies use of a parameterized constructor via, e.g., the [JsonConstructor] attribute, Json.NET will pre-load the JSON properties and their values then construct the object with the deserialized values. This affords an opportunity to set the End property relative to the Start property:
public partial class JsonsoftExample
{
public JsonsoftExample() { }
[JsonConstructor]
JsonsoftExample(DateTime start, DateTime? end)
{
this.Start = start;
this.End = end ?? Start.AddHours(1);
}
[JsonProperty(Required = Required.Always)]
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
Notes:
The names of the constructor arguments must be the same as the names of the properties, modulo case. This is how Json.NET matches constructor arguments with JSON properties.
Note that the End property is of type DateTime while the end constructor argument is of type DateTime?. When "End" is missing from the JSON, Json.NET will pass in a null value into the constructor, which can be checked for to properly initialize the End time relative to the Start.
If you don't want to serialize the End property when it is exactly one hour later than the start, you can use conditional property serialization:
public bool ShouldSerializeEnd()
{
return End != Start.AddHours(1);
}
The constructor does not need to be public when marked with [JsonConstructor]. Properties not passed into the constructor will be populated after construction as per usual deserialization.
Sample fiddle.
If you are using C# 6 then probably you can do like [* Not sure if this is what you are looking to achieve]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public DateTime End { get; set; } = Start.AddHours(1);
I am trying to use the Highrise Api with the .NET 4.5 wrapper by scottschluer in order to post a new Person to our Highrise account along with any custom data that they enter.
The issue that I am running into is with the custom data. The person object gets posted just fine, but the subject data fields are not being included with the post.
I did come across this post: Highrise Custom Fields. It looked like the thing that was missing was the type="array" attribute from the subject_datas field. I tested this hypothesis by manually creating a request using the serialized value of the object I was trying to post. The result of this test, was a successful post to the server with all custom data fields filled.
I've tried extending the classes from the wrapper assembly to add that missing attribute to the list, but that still didn't seem to work. The Person object has a property for a List of SubjectData objects, I overwrote that property in a child class to use a custom class instead. This way I could add a property to use as the attribute. This custom class still didn't seem to work.
After looking at the code for RestSharp's XmlSerializer, it appears that it will only add a list of items when that object implements IList. That wasn't an issue, i was able to get that working, but the code does not seem to allow for adding attributes to the list element. It only looks at the children of the list class and ignores any other properties on the object.
So my question is this:
Is it possible to apply attributes to a list property in RestSharp, or is there another way to add the type="array" attribute to the data_subjects xml node before the request is sent?
I eventually solved the problem myself by creating a new request class that would create a RestRequest using a custom XmlSerializer.
I then extended the Person class and hid the property behind a custom list object property
Before:
[SerializeAs(Name = "subject_datas")]
public List<SubjectData> SubjectDatas { get; set; }
After:
[SerializeAs(Name = "subject_datas")]
public new SubjectDataList SubjectDatas { get; set; }
The SubjectDataList class is just a wrapper for List<SubjectData>.
SubjectDataList implements an interface called ISerializeList<SubjectData>
which is defined as:
interface ISerializeList : IEnumerable {}
interface ISerializeList<T> :IEnumerable<T>, ISerializeList {}
SubjectDataList also has a type property to render the type attribute onto the subjectdatas node of the rest request.
[SerializeAs(Name = "type", Attribute = true)]
public string Type { get; set; } = "array";
I then made a class called XmlListSerializer which implements ISerializer. I copied the implementation of XmlSerializer, but i made a few modifications. In the Map method, there is a part that checks if the variable rawValue is an IList. I changed this part slightly, and added a clause for my XmlListSerializer class.
So it now looks like this:
if (propType.IsPrimitive || propType.IsValueType || propType == typeof(string)) {
//...
} else if (rawValue is IList) {
ProcessIList((IList) rawValue, element);
} else if (rawValue is ISerializeList) {
ProcessISerializeList((ISerializeList) rawValue, element);
} else {
Map(element, rawValue);
}
Where ProcessIList and ProcessISerializeList are defined as:
private void ProcessIList(IList list, XElement element) {
ProcessIEnumerable(list, element);
}
private void ProcessISerializeList(ISerializeList list, XElement element) {
ProcessIEnumerable(list, element);
Map(element, list);
}
private void ProcessIEnumerable(IEnumerable list, XElement element) {
var itemTypeName = "";
foreach (var item in list) {
if (itemTypeName == "") {
var type = item.GetType();
var setting = type.GetAttribute<SerializeAsAttribute>();
itemTypeName = setting != null && setting.Name.HasValue() ? setting.Name : type.Name;
}
var instance = new XElement(itemTypeName.AsNamespaced(Namespace));
Map(instance, item);
element.Add(instance);
}
}
I hope this answer will be able to help anyone else having issues with this problem.
Update 1: for reasons I won't go into, I want to avoid having anything other than the properties to be persisted in my entity objects. This means no extra properties or methods...
I have an entity called Entity1 with (say) 10 public properties. In
one place in my code I want to output serialized JSON with (say) 3 of
those fields, in a second place I need to output 7 fields and in a
third place I might need to output (say) all 10 fields. How do I do
this using Newtonsoft's JSON library?
I can't use [JsonIgnore] or [DataMember] as that will apply to all
cases, so I won't be able to create "custom views" of the data (my own
terminology :-).
I tried to achieve this using an interface:
public interface Entity1View1
{
string Property1;
string Property2;
string Property5;
}
had Entity1 implement Entity1View1 and I passed an
IList<Entity1View1> to the JSON serializer (the objects were
actually just Entity1 objects). Didn't work: the serializer output
all the 10 public properties of Entity1.
The only other way I could think of was to implement
Entity1Wrapper1, Entity1Wrapper2 etc. type of classes where each
object would hold a corresponding instance of Entity1 and in turn
expose only those public properties that correspond to the properties
I want to show in "View1", "View2" etc. Then I pass lists of these
wrapper objects to the serializer (should work, haven't tried it yet).
Is there a better way?
If it matters, here's my configuration:
.Net 4.5
MVC 5
Don't know it that's the best way... but that's one.
One good point is that it will work either with json serialization or xml serialization, for example (which you may don't mind at all).
You can use ShouldSerialize<yourpropertyName> to manage what is serialized or not. <yourpropertyName> must match exactly the name of the property you wanna manage.
For example
public class Entity {
//assuming you want the default behavior to be "serialize all properties"
public Entity() {
ShouldSerializeProperty1 = true;
ShouldSerializeProperty2 = true;
ShouldSerializeProperty3 = true;
}
public string Property1 {get;set;}
public bool ShouldSerializeProperty1 {get;set;}
public string Property2 {get;set;}
public bool ShouldSerializeProperty2 {get;set;}
public int Property3 {get;set;}
public bool ShouldSerializeProperty3 {get;set;}
}
Then you could do, before all your serialization (of course, this could / should be extension methods).
var list = myListOfEntity;
//serialization1
foreach (var element in list) {
element.ShouldSerializeProperty3 = false;
}
//or serialization2
foreach (var element in list) {
element.ShouldSerializeProperty2 = false;
element.ShouldSerializeProperty3 = false;
}
I just wanted to make sure that this was the final step in processing.
You can create anonymous objects to serialize based on circumstance:
var json1Source1 = new {
Property1 = entityView1.Property1,
Property3 = entityView1.Property3
};
var json1Source2 = new {
Property2 = entityView1.Property2,
Property3 = entityView1.Property3
};
You can create jsonSource1 (or 2, 3, 4 etc) as anonymous objects that capture just what you need and then serialize them. The serializer will not care that they are anonymous.
Update 1:
To conditionally serialize a property, add a method that returns boolean with the same name as the property and then prefix the method name with ShouldSerialize..
This means that the solution suggested by Raphaël Althaus doesn't work as it relies on properties, whereas the serializer's documentation mentions that it has to be a method. I have verified that only a method returning a bool works as expected.
Original:
I finally went with a mix of Wrapper classes and the methodology suggested by Raphaël Althaus (with modifications): use Wrappers where some amount of sophistication may be required and use Raphaël's suggestion when simplicity will do.
Here's how I am using wrappers (intentionally left out null checks):
public class Entity1View1
{
protected Entity1 wrapped;
public Entity1View1(Entity1 entity)
{
wrapped = entity;
}
public String Property1
{
get { return wrapped.Property1; }
}
public String Property2
{
get { return wrapped.Property2; }
}
public String Property3
{
get { return wrapped.Property3.ToUpper(); }
}
}
This allows me to modify properties as their values are returned (as done with Property3 above) and lets me leverage inheritance to create new ways of serialization. For example, I can flatten the structure/hierarchy:
public class Entity1View2 : Entity1View1
{
pulic Entity1View2(Entity1 entity) : base(entity) { }
public long? SubEntityID
{
get { return wrapped.SubEntity.ID; }
}
}
For simpler cases where complexity/transformation of this sort is not required, I can simply use the ShouldSerialize* methods.
Same entity classes, different serialization outputs.