We consume a WCF service using C# code. The client was generated in Visual Studio by right-clicking "Add Service Reference" and pointing it at the WSDL.
Recently, the WCF provider adding some properties to one of the objects they serialize. The class went from
public class MyClass
{
public string Foo { get; set; }
public string Baz { get; set; }
public string Zed {get; set; }
}
to this:
public class MyClass
{
public string Foo { get; set; }
public string Bar { get; set; } //<= New Property
public string Baz { get; set; }
public string Zed {get; set; }
}
On our end, this caused Baz and Zed to suddenly start being null when deserialized, until we updated the service reference. In fact, the real object had some ~20 properties alphabetically after Bar, and they were all null (or 0 for ints, false for bools, etc).
It seems an odd way for the deserialization to fail. It didn't throw an exception or ignore the new properties it didn't know anything about.... it just made every property that appeared alphabetically after the new one deserialize to the default value.
So my question is, what's going on here and how do I prevent it? Preferably, I'd like some kind of setting for the client to tell it to "ignore new properties," but telling the service provider how they can prevent future breaking changes would be fine too.
MSDN has an article which lists the serialization ordering of the datamembers. One key point from that document:
current type’s data members that do not have the Order property of the
DataMemberAttribute attribute set, in alphabetical order.
So if you add a new property, without the Order-property of the DataMemberAttribute, the property is alphabetically ordered.
Based on discussion here, your only options are:
Change the serializer to something else
Make sure that the order of the elements in XML matches the order of your properties. Maybe you can always use the Order-property of the DataMemberAttribute?
Make sure that your dll's line up, I've seen some pretty funky issues in the past where one side of a service was pointing to an outdated dll
also remember the fundamentals of data contracts
Related
I'm trying to use Json.NET as my default serializer/deserializer in an ASP.NET MVC5 environment. I already use it to serialize my JsonResult. This works fine. But I'm having issues on using it as my ValueProviderFactory.
I have made some tests with complex objects and everything works, except for enumerators on deeper levels on my model (not direct root level properties).
Like in the code below:
public class MyModel
{
public string Property1 { get; set; }
public MyEnum FirstLevelEnum { get; set; }
public MyDetailModel Detail { get; set; }
}
public class MyDetailModel
{
public string Property1 { get; set; }
public IEnumerable<MyEnum> DeeperLevelEnumList { get; set; }
}
public enum MyEnum
{
Enumerated1,
Enumerated2
}
If I deserialize an object like MyModel, all properties will bind correctly, except for the items inside the DeeperLevelEnumList, which will turn to the default value 0.
Back in time, I used to also have a CustomModelBinder, to surpass issues with enums in MVC2~3. I noticed that in MVC5 that is no longer a problem and using the MVC serializer with all the default behaviors works fine (except for really large JSON, which is one of the reasons to use Json.NET).
I compared, side by side, the results in the Dictionary of objects that are generated after the deserialization and they are the same, in both cases, the DeeperLevelEnumList brings the correct value. But, when the ModelBinder GetPropertyValue method is called, with MVC deserializer, the bind is correctly made and with Json.Net it's not.
Am I missing something? I really looked into this on many posts and threads and didn't find an answer.
If you define the following class:
public class Test
{
public string Something { get; set; }
public string AnotherThing { get; set; }
public string DefaultStringValue { get; set; }
}
then, when you list the properties with IntelliSense, DefaultStringValue appears first in the list, despite this not being in alphabetical order:
If you change the property name to anything else, normal service is resumed:
Anyone know why this is? I'm curious...
(Note: I'm also using Resharper Ultimate 2018.1.2)
This is IntelliSense (and/or ReSharper) being, well, intelli-gent, and trying to help you re-use things you've used previously. If you start again from nothing, you'll find that things are alphabetical:
I'm betting that at some point in the past, you've made use of the DefaultStringValue property, and not the others, so it's suggesting it first:
Having renamed it, if you enter the line t.DefaultStringValu = "x";, then delete it again, next time you enter t. and invoke IntelliSense, DefaultStringValu will now be top of the list:
In a tool project, I generate meta files for Unity3D assets. As all unity asset meta start with the same properties, I created a base type :
public class MetaBase {
public int fileFormatVersion { get; set; }
public Guid guid { get; set; }
public long timeCreated { get; set; }
public string licenseType { get; set; }
}
Serializing an instance of a type inheriting from MetaBase generates a file that unity accepts, but the fileFormatVersion, guid, timeCreated and licenseType are written at the bottom of the file whereas Unity writes them at the top. As I said, it works, but whenever Unity decides to overwrite the meta file, it generates some differences that need to be committed on my project repository, and I would prefer to avoid that if possible.
So, my first idea (after upgrading to YamlDotNet 4.0.0) was to add a TypeInspectorSkeleton which would sort the _IPropertyDescriptor_s depending on the declaring types of the property. But the IPropertyDescriptor does not provide access to the actual Property, nor does it provide access to its baseDescriptor property (for PropertyDescriptor/OverridePropertyDescriptor).
Shouldn't there be some way to access a Property owner type ? Or maybe there is a better may to achieve what I'm trying to do ?
Environment for this situation:
asp.net mvc 3
c#
Entity Framework 4.3.1
JavaScriptSerializer
I have come across a situation where it would be nice to include a field which has been marked up as [ScriptIgnore]. The field, if left without the attribute, would constitute a circular reference and cause an exception to be thrown. The reason is something similar to this:
public class Foo
{
public int FooId { get; set; }
[ScriptIgnore]
public virtual Collection<Bar> Bars { get; set; }
}
public class Bar
{
public int BarId { get; set; }
public int FooId { get; set; }
public virtual Foo Foo { get; set; }
}
So you can see here, a Foo can have many associated Bars. And a Bar has an associated Foo.
Back to the situation. I am loading this association in a controller using an include statement:
.Include( foo => foo.Bars );
There are no errors thrown because include is not affected by the [ScriptIgnore] annotation. Upon debug, the association is properly constructed when inspected. There is a list of foos, and each foo has an associated list of Bars.
Now I want to serialize this constructed list. I have a view model that gets filled with data, it looks like this:
public class FooView
{
public List<Foo> Foos { get; set; }
public string AsJson()
{
var serializer = new JavaScriptSerializer();
return serializer.Serialize(this);
}
}
So I pass this viewmodel into the view and serialize it:
#model FooView
<script type="text/javascript">
var fooViewModel = #( Html.Raw( Model.AsJson() ) );
</script>
No exceptions are thrown, however, the serialization properly skips the field (Bars) marked with [ScriptIgnore]. Upon consol.log(fooViewModel) inspection it is clear that there is an array of Foo, however, there is no associated array of Bar in any of the Foos.
Is there a way that I can skip this [ScriptIgnore] tag just the one time? I realize that if it skipped every time then the serializer would serialize Foo, look and see a collection of type Bar, serialize each Bar, notice that Bar had an associated Foo, serialize Foo, notice that Foo had a collection of type Bar...etc. I only want to grab the collection of Bar the first time. Is there any way to accomplish this? I realize it will try to serialize Foo from Bar, but it will be empty. This is all done with eager loading and the entire object graph is already constructed.
When I ran into this, what I ended up doing was replacing the serializer with the Json.NET serializer, which has settings, specifically
_jsonSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
Json.NET will ignore objects in reference loops and not serialize them. The first time an object is encountered it will be serialized as usual but if the object is encountered as a child object of itself the serializer will skip serializing it.
The info for the settings is http://james.newtonking.com/projects/json/help/index.html?topic=html/SerializingJSON.htm
and I used http://blogs.msdn.com/b/henrikn/archive/2012/02/18/using-json-net-with-asp-net-web-api.aspx
to replace the serializer, and then I add it as default to the global.asax.cs.
configuration.Formatters.Insert(0, new JsonNetFormatter(serializerSettings));
I realize this is a workaround (not actually dealing with scriptignore), however, I had so many circular references from the supplied database, that it seemed to be the best solution at the time.
I want to implement a simple attribute that is used to map Database Columns to Properties.
So what i have so far is something that attached like so:
[DataField("ID")]
public int ID { get; set; }
[DataField("Name")]
public String Name { get; set; }
[DataField("BirD8")]
public DateTime BirthDay { get; set; }
Is there a way that I can make the attribute "aware" of the field it is on, so that for the properties where the name is the same as the ColumnName I can just apply the attribute without the name parameter, or would I have to deal with that at the point where I reflect the properties. I want to end up doing just this:
[DataField]
public int ID { get; set; }
[DataField]
public String Name { get; set; }
[DataField("BirD8")]
public DateTime BirthDay { get; set; }
The attribute itself won't be aware of what it's applied to, but the code processing the attributes is likely to be running through PropertyInfo values etc and finding the attributes associated with them. That code can then use both the property and the attribute appropriately.
To make things simpler, you might want to write a method on the attribute to allow it to merge its information with the information from the property, so you'd call:
DataFieldAttribute dfa = propertyInfo.GetCustomAttributes(...); // As normal
dfa = dfa.MergeWith(propertyInfo);
Note that for the sake of sanity this should create a new instance of the attribute, rather than changing the existing one. Alternatively, you might want a whole separate class to represent "the information about a data field":
DataFieldAttribute dfa = propertyInfo.GetCustomAttributes(...); // As normal
DataFieldInfo info = dfa.MergeWith(propertyInfo);
That way you could also construct DataFieldInfo objects without any reference to attributes, which might be a nice conceptual separation - allowing you to easily load the config from an XML file or something similar if you wanted to.
If you don't mind using postsharp you can look Here, at a previous question I have asked which was close. I ended up using the compile time validate to do what I wanted, although there are other options, like CompileTimeInitalize.
public override void CompileTimeInitialize(object element)
{
PropertyInfo info = element as PropertyInfo;
//....
}