How to check if a value was specified when using DataContractSerializer? - c#

I have a class member marked as [DataMember(IsRequired=false)], and I'd like to know if a value for this particular member was specified inside the original message. For example,
[DataContract]
public class Person
{
[DataMember]
public String Name { get; set; }
[DataMember(IsRequired=false)]
public DateTime BirthDate { get; set; }
}
If I deserialize a the following message using the DataContractSerializer, how can I know that the optional member BirthDate was not specified?
<Person>
<Name>Carlos</Name>
</Person>
I know for the XmlSerializer there is the Specified pattern for flagging if a member was included inside the message being deserialized. Is there any equivalent for DataContractSerializer?

First of all, you don't need to set IsRequired to false explicitly. By default, it's already false.
Another issue is that EmitDefaultValue is -- by default -- set to true. As a result, a value for DateTime will always be emitted, even if you never set it on serialization time. This value will be default(DateTime.) Similarly, a value for DateTime will always be set on deserialization time, even if it's not even on the wire!
As a result, you can't even tell if something was on the wire or not, at all, out of the box.
But you have several options here. It's extra work but worth it.
Check if the date time is deserialized and set to default(DateTime.) If you know for sure that your application will never set the date to default(DateTime), this lets you know that the date wasn't actually present on the wire.
Another option you have is to encapsulate the DateTime in a reference type. Since reference types are null if not present, that lets you know right away if a DateTime was present or not (because the encapsulating reference type would be either non-null or null.)
Yet another option is to use a nullable date time DataMember (i.e., the type would be "DateTime?" instead of "DateTime".)
A final option you have is to add an extra complementary variable (perhaps a boolean) that is set on OnDeserializing/OnDeserialized/OnSerializing/OnSerialized and use this to track whether or not something was actually present on the wire. You might, for example, set this complementary variable to true only when you're actually serializing out a date time.

Related

REST in ASP.NET Core: validate a missing value type field on a PUT object

For example you have a class that you intend to expose via your public RESTful API:
public class MyExposedType
{
[Required]
public bool MyExposedValueType { get; set; }
}
Consider a PUT operation with the body {}. In this situation I would expect the API to return a BadRequest, but instead the object is accepted.
Since MyExposedValueType is a value type, it cannot be null and defaults to false. However, typically for a PUT operation, you must provide values for all the fields in the object to replace.
I know I could expose a DTO with a [Required] nullable bool on it. Is there a better way to handle this situation?
The problem here is that the exported model is protocol-agnostic. In some cases it can be explicitly stated, that the default values can be omitted in the request. For the bool the default value is false, so it may be even expected that in case of false there is nothing in the request.
To specifically require the value in the request, you need to either change the default value to null (by changing the property to nullable), or to adjust the model specifically for some protocol. For example, newtonsoft.json has a JsonRequiredAttribute (https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonRequiredAttribute.htm). But it will only work in case of JSON deserialization, and only if you use newtonsoft.json.
Making the type nullable as you suggest should be fine? It's only a DTO after all - not a domain object which is more likely to enforce 'proper' types, if appropriate.

How to ignore invalid enum values during xml deserialization?

I want to deserialize an xml document to a class, which is genereated by the concerning xsd files. I don't have control over the contents of the xml-file.
During deserialization I run into an exception, because an enum value in the xml document does not meet the requiremnts of the xsd. Instead of breaking, i would like the deserialization to continue and just take the default value for any such errors. Is there any way to accomplish this behaviour?
edit:
For clarification, what i am trying to achieve: I want to read data from digital invoices. So the creation of the xml file is some kind of blackbox and can contain possibly flase values, even if the structure meets the standards. But that does not mean, that every value is flawed in that way. The exception prevents me from reading the correct values so i just want the deserialization to finish by somehow inserting the default values if such an error occurs.
Neither marking the values as obsolete, nor flagging them with XmlIgnore won't work, because the next xml i receive could contain correct values.
I hope that helped clarifying the problem.
Right now, im using the System.Xml.Serialization dll, but im willing to implement any library which can help me achieve the wanted behaviour.
The exception im getting:
"System.InvalidOperationException: Instance validation error: 'x' is
not a valid value for xType.."
The code that throws the exception:
XmlSerializer serializer = new xml.XmlSerializer(typeof(MyType));
MyType invoice = serializer.Deserialize(memoryStream) as MyType;
I know the code does not help very much, so I'll add the enum, that is currently problematic:
public enum PaymentMeansCodeContentType
{
[System.Xml.Serialization.XmlEnumAttribute("10")]
Item10,
[System.Xml.Serialization.XmlEnumAttribute("20")]
Item20,
[System.Xml.Serialization.XmlEnumAttribute("30")]
Item30,
[System.Xml.Serialization.XmlEnumAttribute("48")]
Item48,
[System.Xml.Serialization.XmlEnumAttribute("49")]
Item49,
[System.Xml.Serialization.XmlEnumAttribute("57")]
Item57,
[System.Xml.Serialization.XmlEnumAttribute("58")]
Item58,
[System.Xml.Serialization.XmlEnumAttribute("59")]
Item59,
ZZZ,
}
These are autogenerated from using the xsd command line tool:
https://learn.microsoft.com/de-de/dotnet/standard/serialization/xml-schema-definition-tool-xsd-exe
The xml i need to deserialize provides me with a '1', so clearly an invalid value. Still i need to access the other valid values from the xml and provide means for indicating which values are flawed.
You can mark the member Obsolete
public enum TypeEnum
{
Temperature,
Pressure,
[Obsolete]
Humidity
}
More info - docs
I still wasn't able to find the simple answer I was hoping for but managed to find a work around that worked for me. I ended up validating every enum in the XML file beforehand against the possible values. If the XML did not match the enum i saved the wrong value and node to a validation result set and overwrote the xml with the enum default value.
As Martin mentioned, it's a bit difficult to answer without proper context or sample code. However, you may want to look at the XmlIgnoreAttribute decorator on the property for the model. See the URL & code sample below for more details on how to use:
https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlattributes.xmlignore?view=netframework-4.8
using System;
using System.IO;
using System.Xml.Serialization;
// This is the class that will be serialized.
public class Group
{
// The GroupName value will be serialized--unless it's overridden.
public string GroupName;
/* This field will be ignored when serialized--
unless it's overridden. */
[XmlIgnoreAttribute]
public string Comment;
}
You can use Extended Xml Serializer library (avaliable via nuget) instead of the default XmlSerializer, with a custom converter that will set the default value in case of an error.
I suggest you store the value of the Enum as a string, and then parse it yourself. This is relatively simple to implement, here's an example:
public enum MyEnum
{
Default, //The default value to apply in the event of an invalid Enum value
[XmlEnumAttribute("10")]
Item10,
[XmlEnumAttribute("20")]
Item20
}
public class MyClass
{
public string Value { get; set; }
public MyEnum EnumValue => (MyEnum)(typeof(MyEnum).GetFields().FirstOrDefault(f =>
f.GetCustomAttribute<XmlEnumAttribute>()?.Name == Value)?
.GetValue(null) ?? MyEnum.Default);
}
Or if you prefer it you can also set a nullable Enum
public enum MyEnum
{
[XmlEnumAttribute("10")]
Item10,
[XmlEnumAttribute("20")]
Item20
}
public class MyClass
{
public string Value { get; set; }
public MyEnum? EnumValue => (MyEnum?)typeof(MyEnum).GetFields().FirstOrDefault(f =>
f.GetCustomAttribute<XmlEnumAttribute>()?.Name == Value)?
.GetValue(null);
}

Class model - setting default value

When defining the default value, what is the difference between
[DefaultValue("member")]
public string Role { get; set; }
and
public string Role { get; set; } = "member";
The first is an attribute which can be useful for meta-programming. For example, you might want to remember what the default value is if someone clears an input. It has nothing to do with the C# language itself. It does not modify the value of Role.
The second actually sets the property's value to 'member' in memory.
From the documentation:
A DefaultValueAttribute will not cause a member to be automatically initialized with the attribute's value. You must set the initial value in your code.
In other words, your first example helps tools (like the Windows Forms Designer) to know what the intended default value for a property is. But it does nothing at run-time.
If you want a property to be assigned a default value at run-time, you have to do it yourself, as in the second example you show.

Whats better design/practice: Nullable property or 1 value property and 1 bool "has" property?

I'm working on an ASP.NET MVC app, designing the domain models, using (testing) the new EF Code First feature.
I have an Activity entity that may or may not have a Deadline, what is the best way to approach it?
1 property:
public DateTime? Deadline {get; set;}
and check vs null before using
or
2 properties:
public DateTime Deadline {get; set;}
public bool HasDeadline {get; set;}
At first I thought of the first option, but then I started thinking that maybe the second option would be better regarding the DB...
Is there any best practice regarding this?
I'd go with the first option. After all, it's exactly an encapsulated form of the second.
The encapsulation makes it clear that you've only got one logical value (or lack thereof). In the second form you can treat the properties as if they were entirely independent, which they're logically not.
In terms of the database, I'd expect the first form to be just as easy too... presuambly you'll have a nullable DATETIME field in the database, won't you? It should map directly.
How about a combination of both just for the sake of making your code more readable?
public DateTime? Dealine{get; set;}
public bool HasDeadline
{
get
{
return (Deadline != null);
}
}
Its easy to read and does exactly the same thing that the consumer would have to do anyway. Besides...
if(HasDeadline)
doStuff();
is easier to read than
if(Dealine != null)
doStuff();
:)
I would use the first option. In the long run the second option will probably cause some maintenance problems because you have to remember to check and use both of the properties.
Also one option is to use one property but instead of making it nullable, you could return a Null object (also known as Special Case).
The database is used to storing NULL values - storing a Min value in the databsae, and then having a flag to indicate if you should trust that value makes queries complicated.
I like nullable types since the reflect the domain's intent - there is no date, not 'there isn't a date, so pretend the first of January 1970 means no date'.
There is also an overhead of maintaining the HasDealine value - you need to set it each time the corresponding property is updated. Also how do you clear it? If you set the Deadline to a date, it will set the HasDeadline to true. How do I 'unset' it? Would you set HasDeadline to false, but leave the Deadline field intact with the previous value?
Overall icky.
You should use the nullable, as it does exactly what you want. Using two separate properties means that you lose the connection between them, and you need to explain with documentation that they have a relation.
The nullable type should also fit better against a database type, however you should first design your object for how it works as an object, not for how you will store it in the database. If the use of a database generation tool causes you to make bad decisions when designing the code, it's contra-productive.

XML Serialization and empty collections

I have a a property defined as:
[XmlArray("delete", IsNullable = true)]
[XmlArrayItem("contact", typeof(ContactEvent)),
XmlArrayItem("sms", typeof(SmsEvent))]
public List<Event> Delete { get; set; }
If the List<> Delete has no items
<delete />
is emitted. If the List<> Delete is set to null
<delete xsi:nil="true" />
is emitted. Is there a way using attributes to get the delete element not to be emitted if the collection has no items?
Greg - Perfect thanks, I didn't even read the IsNullable documentation just assumed it was signalling it as not required.
Rob Cooper - I was trying to avoid ISerializable, but Gregs suggestion works. I did run into the problem you outlined in (1), I broke a bunch of code by just returning null if the collection was zero length. To get around this I created a EventsBuilder class (the class I am serializing is called Events) that managed all the lifetime/creation of the underlying objects of the Events class that spits our Events classes for serialization.
I've had the same issue where I did not want an element outputted if the field is empty or 0.
The XML outputted could not use xsi:null="true" (by design).
I've read somewhere that if you include a property of type bool with the same name as the field you want to control but appended with 'Specified', the XMLSerializer will check the return value of this property to determine if the corresponding field should be included.
To achieve this without implementing IXMLSerializer:
public List<Event> Delete { get; set; }
[XMLIgnore]
public bool DeleteSpecified
{
get
{
bool isRendered = false;
if (Delete != null)
{
isRendered = (Delete.Count > 0);
}
return isRendered;
}
set
{
}
}
If you set IsNullable=false or just remove it (it is false by default), then the "delete" element will not be emitted. This will work only if the collection equals to null.
My guess is that there is a confusion between "nullability" in terms of .NET, and the one related to nullable elements in XML -- those that are marked by xml:nil attribute. XmlArrayAttribute.IsNullable property controls the latter.
First off, I would say ask yourself "What is Serialization?".
The XmlSerializer is doing exactly what it is supposed to be doing, persisting the current state of the object to XML. Now, I am not sure why the current behaviour is not "right" for you, since if you have initialized the List, then it is initialized.
I think you have three options here:
Add code to the Getter to return null if the collection has 0 items. This may mess up other code you have though.
Implement the IXmlSerializable interface and do all the work yourself.
If this is a common process, then you may want to look at my question "XML Serialization and Inherited Types" - Yes, I know it deals with another issue, but it shows you how to create a generic intermediary serialization class that can then be "bolted on" to allow a serilization process to be encapsulated. You could create a similar class to deal with overriding the default process for null/zero-item collections.
I hope this helps.
You could always implement IXmlSerializer and perform the serialization manually.
See http://www.codeproject.com/KB/cs/IXmlSerializable.aspx for an example.

Categories