Skip [ScriptIgnore] just once - c#

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.

Related

Issue with model binding enums with Json.NET ValueProviderFactory

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.

Adding Property to Object in WCF Service Breaks Client

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

Produce different serialized JSON for a given class in different scenarios

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.

How to use Json.NET with standard (like) OData service

I try to use Json.NET for consuming an OData (like) service. My data structures have collection properties.
However all those properties are wrapped in a property called 'results' by my service. Even the main query which returns with a collection of the entities are wrapped into a root property called results.
Although I am not an OData expert I think this is pretty much a standard because if I try to send an object graph for update, and omit this 'results' wrapper around say a int collection type property then I got an error message from the server "A collection was found without the 'results' property. In OData, each collection must be represented as a JSON object with a property 'results'"
So I understand the server error message, and I also know how to workaround this. Of course I can mimic this object graph in my C# object model, but after writing the 101st wrapper in my object model it tends to be boring, and I do not want to reinvent the wheel.
My question is there an out of the box solution how to deal with this result property, and make it transparent? If this is a 'standard' I suppose not I am the first who are facing this task.
Thanks in advance
you can just write one and use it everywhere
public class OData<T> where T : IEnumerable
{
public T results { get; set; }
}
public class X
{
public string Prop { get; set; }
public OData<List<int>> List { get; set; }
}
class Program
{
static void Main(string[] args)
{
var x = new X()
{
Prop = "test",
List = new OData<List<int>> {results = new List<int>() {1, 2, 3}}
};
Console.WriteLine(JsonConvert.SerializeObject(x));
}
}

Why isn't my public property serialized by the XmlSerializer?

This is one i struggled with for ages so thought I'd document somewhere. (Apologies for asking and answering a question.)
(C# .net 2.0)
I had a class that was being serialized by XmlSerializer, I added a new public property however it wasn't being included in the output XML.
It's not mentioned in the docs anywhere I could find, but public properties must have a set as well as a get to be serialized! I guess this is because it assumes that if you're going to serialize then you'll want to deserialize from the same file, so only serializes properties that have both a set and a get.
As mentioned, most properties must have both a getter and setter; the main exception to this is lists - for example:
private readonly List<Foo> bar = new List<Foo>();
public List<Foo> Bar {get { return bar; } } // works fine
which will work fine; however, if XmlSerializer finds a setter - it demands that it is public; the following will not work:
public List<Foo> Bar {get; private set;} // FAIL
Other reasons it might not serialize:
it isn't public with get and set (or is readonly for a field)
it has a [DefaultValue] attribute, and is with that value
it has a public bool ShouldSerializeFoo() method that returned false
it has a public bool FooSpecified {get;set;} property or field that returned false
it is marked [XmlIgnore]
it is marked [Obsolete]
Any of these will cause it not to serialize
The point about getter+setter is made in the 3rd paragraph on the "Intro to Xml Serialization" page. It's actually in a call-out box. Can't miss it!
Intro-to-XML Serialization http://www.freeimagehosting.net/uploads/2f04fea2db.png
(having a little too much fun with Freeimagehosting.net)
Also properties that return null are not serialized!
if you don't want to implement proper Setters (because maybe you are neither wanting to deserialize or change an objects value) you can just use dummy setters like this set { }, so that the XMLSerializer works, but nothing happens if you use the Setter...
i.E.
public string ID { get { return _item.ID.ToString(); } set { } }
And if your class inherits a list and also has its own members, only the elements of the list get serialized. The data present in your class members is not captured.
Took some time figuring out this!
One more thing to add about serialization of collections:
The XmlSerializer ignores collections of interfaces!
And by that I mean ignore. While you will get an exception for a line like:
public IFoo Foo { get; set; }
you will not get an exception for:
public ICollection<IFoo> LotsOfFoos { get { return this.fooBackingField; } }
You can implement the IXmlSerializer and do the serialization manually, and benefit from serializing properties, and vice versa, deserializing them using constructors / private field assignment.

Categories