0

I'm trying to add a field to an existing datacontract in our system. (EF code first, POCO's with attribute hell :P)

However, when serializing the contract to the razor view (to stuff into an Angular.js model) the serializer omits the new field. If I step through in debug mode, the Model object in the view contains the field, but after I use JsonConverter.SerializeObject(Model) the output model does not include the new field.

I have recycled the apppool, restarted the website and restarted IIS without resolution. I have also inspected the data flow with fiddler to avoid any caching issues on the browser side.

The following workaround does actually work, so the property does exist on the model:

    var model = @Html.ToJson(Model);
    model.NewProperty = @Model.NewProperty;
    return {
        model: model
    };

...where Html.ToJson(Model) is an extension method that just calls JsonConvert.SerializeObject(Model) and stuffs it into a MvcHtmlString.

Does anyone know what is going on? According to this answer there is some form of type information caching in json.net but it's hard to find any more information about it.

Christian Wattengård
  • 5,543
  • 5
  • 30
  • 43
  • 1
    Are you checking this using an HTTP request? My guess is your browser is caching the response. –  Nov 05 '18 at 14:37
  • Other parts of the page are updating fine, the model is inserted as part of the Razor render cycle, before the page is even sent to the browser. – Christian Wattengård Nov 05 '18 at 14:40
  • Well, your browser and ASP.Net caches are where I would focus, not on JSON.Net's schema caching. –  Nov 05 '18 at 14:42
  • Maybe you have some pointers on where to start then. Especially with "ASP.Net caches". – Christian Wattengård Nov 05 '18 at 14:43
  • 1
    Restart your ASP.Net server to clear that cache, and in your browser, check the box in your dev tools' "Network Tab" to "Disable Cache" to disable the client-side cache. And verify the caching headers are behaving as desired in both the request and response. –  Nov 05 '18 at 14:45
  • Yes. Recycling and restarting were among the first things I tried. And fiddler tells me that the browser is not caching anything on it's side. Why are you so certain that the schema caching has nothing to do with it? – Christian Wattengård Nov 05 '18 at 14:49
  • 1
    I never said I was certain it wasn't JSON.Net. I consider this *far* more likely, and a more fruitful line of inquiry. There is a difference. I still think this. I am very dubious this has anything to do with JSON.Net. –  Nov 05 '18 at 14:51
  • 1
    It's unlikely that Json.NET contract caching is causing the problem. The contract is runtime only and cached in a static variable, which persists only as long as the `AppDomain` in which it was instantiated. Are you sure you marked your new member with `[DataMember]`? Remember that data contract serialization is opt-in. – dbc Nov 05 '18 at 14:58
  • 1
    Well no... I didn't actually. I was not aware that datacontracts was handled specially in the serializer. I wasn't going to add the attribute until all the scaffolding was done with because I didn't want to create a migration right now. That's probably it, but I won't be able to test it until tomorrow. If you add it as an answer I'll give it to you. – Christian Wattengård Nov 05 '18 at 15:03
  • https://www.newtonsoft.com/json/help/html/NullValueHandlingIgnore.htm. Is this set correctly? – Fran Nov 05 '18 at 15:03
  • @ChristianWattengård - if adding `[DataMember]` doesn't solve the problem, then I think we will need to see a [mcve] to help you. In particular the source code for `Html.ToJson()` would be useful. The version shown [here](https://stackoverflow.com/a/8502797) uses `JavaScriptSerializer` not Json.NET. – dbc Nov 05 '18 at 15:40

1 Answers1

0

I'm trying to add a field to an existing datacontract in our system. Json.NET supports data contracts, and data contract serialization is opt-in:

Apply the DataContractAttribute attribute to types (classes, structures, or enumerations) that are used in serialization and deserialization operations by the DataContractSerializer...

You must also apply the DataMemberAttribute to any field, property, or event that holds values you want to serialize. By applying the DataContractAttribute, you explicitly enable the DataContractSerializer to serialize and deserialize the data.

Thus if your model is marked with [DataContract], then you need to mark your new member with [DataMember]:

[DataContract]
public class Model : SomeBaseClass
{
    [DataMember]
    public string NewProperty;
}

Note that, even if your Model class is not marked with [DataContract], Json.NET still requires that serializable members be marked with [DataMember] as long as some base class of Model is marked with [DataContract]. For details see caliburn.micro serialization issue when implementing PropertyChangedBase.

dbc
  • 104,963
  • 20
  • 228
  • 340