Serialize JSON object from pre-compiled class in MVC application - c#

I am trying to serialize a JSON object to send it from the Controller to the View. Despite reading plenty of similar questions, I did not find a solution that works well.
In my case, I have a List<MyType> object, where is a pre-compiled class. But when I tried to serialize the data by means of:
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(MyType));
I got the following error:
Additional information: Type MyType cannot be
serialized. Consider marking it with the DataContractAttribute
attribute, and marking all of its members you want serialized with the
DataMemberAttribute attribute.
However, since it is a pre-compiled class, I cannot mark the members. How can I solve this?

The DataContractJsonSerializer uses opt-in semantics, which means that you must mark the class(es) to be serialized with a [DataContract] attribute, and mark all members of those classes that you want serialized with [DataMember]. If you cannot change the classes (because they are precompiled or you don't otherwise control the source code), then there's not much you can do with this serializer short of copying the data into another class that can be serialized. But, with ASP.NET MVC you shouldn't really be using DataContractJsonSerializer anyway-- this serializer was created for WCF and is not very flexible or user-friendly, IMO.
The ASP.NET MVC framework has a Json method built into the base controller, which uses the JavaScriptSerializer behind the scenes to serialize your model objects. This serializer does not require marking up classes with attributes, and because it is baked-in you don't have to put any special serialization code into your controller methods to use it. Just change your method to return JsonResult instead of ActionResult, then pass your object to the Json method as a last order of business.
For example:
[HttpGet]
public JsonResult GetItem(int id)
{
PrecompiledClass pc = RetrieveObjectFromDatabaseOrWhatever(id);
return Json(pc, JsonRequestBehavior.AllowGet);
}
The JavaScriptSerializer does have some limitations that I won't go into here, which you probably won't hit in most normal circumstances. But if you do find that the JavaScriptSerializer does not suit your needs, you can switch to a robust third-party serializer like Json.Net. See ASP.NET MVC and Json.NET and Using JSON.NET as the default JSON serializer in ASP.NET MVC - is it possible? to learn more about that option.

I would not recommend using a precompiled class as your view model. Separation of concerns and whatnot.
Create a new class, MyTypeViewModel, which will have only the properties that the UI needs to know about, and map the properties from MyType to MyTypeViewModel. Then return like this in your controller method if you're returning this result as part of an API call:
return Json(myTypeViewModel, JsonRequestBehavior.AllowGet);
or return View(myTypeViewModel) if you want to render an entire view.

Related

Json Deserialization and controlling the instantiation

I am converting code that was written using NewtonSoft.JsonNet. This is actually a custom Json Media Type Formatter. I have to change it because Json.Net has proven that its performance is very poor under load. Many comparison on the Internet is also proving this.
Anyway, I have a base type called CatalogueItem. Three types are derived from this type and are called ContainerItem, SectionItem, and RefresherItem. Based on a property in the Json object which is called itemType we decide which sub-class must be instantiated.
var type = (string)jsonObject.Property("itemType");
switch (type)
{
case "Container":
return new ContainerItem();
case "Section":
return new SectionItem();
case "Refresher":
return new RefresherItem();
}
We used to do this with creating a custom CustomCreationConverter, and adding it to Serializer.Converters collection of Json.Net.Serializer. Trying to get rid of Json.Net, I am using ServiceStack.Text, but I don't know how can I control the type that is being generated using it. Can anyone please help me with this?
p.s. I found this post on StackOverflow in which similar issue has been answered. However, I get the json from a third-party web service so I cannot include type names in it. Plus, I cannot use the generic version of JsConfig because MediaTypeFormatter does not have any generic methods.
I recommend avoiding trying to coerce your JSON Serializer to your models and just use DTO's that map 1:1 to the wire format than use plain C# to map the typed DTO's to your desired domain models.
With that said, depending on what the JSON and DTO's look like you may be able to use one of:
JsConfig<CatalogueItem>.RawDeserializeFn
JsConfig<CatalogueItem>.DeSerializeFn
JsConfig<CatalogueItem>.OnDeserializedFn
Otherwise you can parse JSON dynamically using JsonObject, here's an example.

Json.net used in Web API but not when calling Json.Encode in Razor Template

I am building a MVC 4 application with both traditional and Web API controllers. Since I'm also using EF5 with code-first I have navigation properties that lead to circular references. I am using JsonIgnore attributes on these navigation properties to avoid running into circular reference loops when serializing to Json.
This approach works flawlessly for my Web API controllers, however, when using Html.Raw(Json.Encode(Model)) in a traditional controller's Razor template, I get an exception due to the circular references:
A circular reference was detected while serializing an object
This exception occurs in System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal. Am I interpreting this correctly in that Json.Encode seems to use a different Json encoder (not json.net)? How can I use the configured Json.Net formatter used in Web API from inside Razor templates?
I came up with a workaround where I use the following class
namespace MyMVCProject.Globals
{
public class Helper
{
public static string ToJson(object obj)
{
return JsonConvert.SerializeObject(obj, GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings);
}
}
}
so I can use it inside the template: #Html.Raw(MyMVCProject.Globals.Helper.ToJson(Model))
This still feels awkward for something I'd expect to be default behaviour of Json.Encode
You're right, when you call Json.Encode you're using a method from the class System.Web.Helpers.Json.
If you want to use a different Json encoder, just use it. You can do it just like you've done it, with a helper class that wraps the call to JsonConvert, and configures it (including the deisred formatter).
You can include the namespace of your wrapper class so that you can avoid writing the namespace. (You can do it in web.config fro the views, it you frequently use it).
What you cannot do is change the behavior of Json.Encode because is an static class member, and its namespace is always included in razor views (because you need more things from the same namespace).
You can also implement it as an extension method to the objects you want to serialize. Only the syntax changes.
Remember that you can also customize the serialization with [DataContract] attribute, as you can see in this page.
You can also customize the way each member is serialized using other Json.Net attributes attached to the properties of interest in the class definition.

JSON.NET - exclude properties of a specific type at runtime

I'm wondering how to exclude/strip certain properties of given type(s) (or collections of those) from being serialized using Json.NET library?
I tried to write my own contract resolver (inheriting from DefaultContractResolver) with no luck.
I know that I could be done using DataAnnotations, decorating the excluded properties with ScriptIgnoreAttribute, but it's not applicable in my scenario. The objects serialized can be virtually anything, so I don't know which properties to exclude at design-time. I know only the types of properties that should not be serialized.
It looks like a rather simple task, but unfortunately I couldn't find a decent solution anywhere...
BTW - I'm not bound to Json.NET library - if it can easily be done with default/other .NET JSON serializers it'd be an equally good solution for me.
UPDATE
The properties has to be excluded before trying to serialize them. Why?
Basically, the types of objects I'm receiving and serializing can have dynamic properties of type inheriting from IDynamicMetaObjectProvider. I'm not going to describe all the details, but the DynamicMetaObject returned from GetMetaObject method of these objects doesn't have DynamicMetaObject.GetDynamicMemberNames method implemented (throws NotImplementedException...). Summarizing - the problem is those objects (I need to exclude) doesn't allow to enumerate their properties, what Json.NET serializer tries to do behind the scenes. I always end up with NotImplementedException being thrown.
I have tried both the WCF JSON serialization as well as the System.Web.Script.Serialization.JavaScriptSerializer. I have found if you want solid control of the serialization process and do not want to be bound by attributes and hacks to make things work, the JavaScriptSerializer is the way to go. It is included in the .NET stack and allows you to create and register JavaScriptConverter subclasses to perform custom serialization of types.
The only restriction I have found that may cause you a problem is that you cannot easily register a converter to convert all subclasses of Object (aka, one converter to rule them all). You really need to have knowledge of common base classes or preregister the set of types up front by scanning an assembly. However, property serialization is entirely left up to you, so you can decide using simple reflection which properties to serialize and how.
Plus, the default serialization is much much much better for JSON than the WCF approach. By default, all types are serializable without attributes, enums serialize by name, string-key dictionaries serialize as JSON objects, lists serialize as arrays, etc. But for obvious reasons, such as circular trees, even the default behavior needs assistance from time to time.
In my case, I was supporting a client-API that did not exactly match the server class structure, and we wanted a much simpler JSON syntax that was easy on the eyes, and the JavaScriptSerializer did the trick every time. Just let me know if you need some code samples to get started.
Create your own contract resolver, override the method that creates the properties for an object and then filter the results to only include those that you want.
Have you considered using the ShouldSerialize prefix property to exclude the property of your specific type at runtime?
public class Employee
{
public string Name { get; set; }
public Employee Manager { get; set; }
public bool ShouldSerializeManager()
{
return (Manager != this);
}
}

Designing Classes With Interface In C# (JSON.NET)

I am in the process of designing an itemization system for a game. I am creating a bunch of interfaces (IItem, IConsumable, IEquipable, IWeapon, etc...) to define what type of functionality is possible with items and then a number of classes (Weapon, Potion, etc...) the define the actual item types.
Now when saving out the player, the data is going to be stored as a JSON file (using the JSON.NET library) and will included the players inventory which will include these items. The issue is that when I try to deserialize the JSON file to an object when reading in the file, how will I be able to tell the JSON.NET library what type of class this is?
One thing I thought of and have not had time to try yet is that all my objects that get serialized into JSON have a DTO version of the object that is used in conjunction with the JSON.NET library. What I though about trying is maybe I could add in a property to the DTO called ClassType and then when reading the file into the application, I would first read the object in as an anonymous type. Then based on the ClassType property, I would convert it to the proper type. The 2 issues I have with this is that 1. it seems like a very ugly solution and 2. I am not even sure if that is possible.
(Copied from this question)
In cases here I have not had control over the incoming JSON (and so cannot ensure that it includes a $type property) I have written a custom converter that just allows you to explicitly specify the concrete type:
public class Model
{
[JsonConverter(typeof(ConcreteTypeConverter<Something>))]
public ISomething TheThing { get; set; }
}
This just uses the default serializer implementation from Json.Net whilst explicitly specifying the concrete type.
The source code and an overview are available on this blog post.
You should know the concrete type when you are serializing. So you can use TypeNameHandling of JSON.NET.
http://james.newtonking.com/archive/2010/08/13/json-net-3-5-release-8-3-5-final.aspx?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+jamesnewtonking+%28James+Newton-King%29

JSON serializer and CSLA objects

We just started a new ASP.Net project that uses web services to serialize some CSLA business objects into JSON data for our client javascript/JQuery code. After reviewing the JSON data in the client browser(Firebug in Firefox) we notices that there are a significant number of properties from the business object that we do not need downloaded to the browser.
Is there a way to exclude properties (other than marking them private) from getting serialized by the JSON serializer? We are not calling the JSONSerializer directly, but instead just included a ScriptMethod declaration on the WebMethod.
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
<WebMethod()> _
Public Function getQuestions()
UPDATE
We tried the suggestion of adding the attribute on the public property but received an error:
Error 25 Attribute 'NonSerializedAtrribute' cannot be
applied to 'Name' because the attribute is not valid
on the is declaration type.
Now if we add NonSerialized to the class then it works but not on the property. However, we do want some properties to be serialized.
Any ideas?
You should use ScriptIgnore attribute for all properties which should be not serialized.
If you decide to make more customization of data serialization, for example, replacing one properties name with another one or converting some properties in an array and so on you can write a small JavaScriptTypeResolver which do it.
ScriptIgnore should do the job for you as sugested by Oleg. Check out this link for a detailed sample
you could try to place a NonSerializedAttribute on the properties not sure if it works with the Json serializer...
Edit: if you are using .net 4.0 you could try to use the ISerializable interface...

Categories

Resources