9

In my design I have a class that has a property whose type can be inherited from:

public class Feed
{
    ...
    [JsonProperty(TypeNameHandling = TypeNameHandling.Auto)]
    public FeedSource Source { get; set; }
    ...
}

public abstract class FeedSource { ... }

public class CsvSource : FeedSource { ... }

public class DbSource : FeedSource { ... }

I'm using the Entity Framework to load and store this object to a database and I'm using Json.NET to serialize this object into JSON for further processing.

The problem I stumbled on is that the $type property is containing the typename of the EF proxy instead of the "real" typename. So instead of:

$type: "System.Data.Entity.DynamicProxies.CsvSource_0B3579D9BE67D7EE83EEBDDBFA269439AFC6E1122A59B4BB81EB1F0147C7EE12"

which is meaningless to other clients, I would like to get:

$type: "MyNamespace.CsvSource"

in my JSON.

What's the best way to achieve this?

Dejan
  • 9,150
  • 8
  • 69
  • 117
  • 2
    Is disabling the use/creation of proxy objects an option for this code path? Read-only / eager-load use of EF doesn't seem to need it AFAICT? – James Manning Jun 06 '14 at 12:43
  • 1
    Avoiding proxy generation (or disabling it by setting `ProxyCreationEnabled` to false) might be one strategy that applies in certain cases. However, there will be other cases where this is not applicable and my question remains open. – Dejan Jun 06 '14 at 13:26
  • 1
    possible duplicate of [Serialization of Entity Framework objects with One to Many Relationship](http://stackoverflow.com/questions/13077328/serialization-of-entity-framework-objects-with-one-to-many-relationship) – Erik Philips Jun 07 '14 at 00:29
  • For people late to the show, the accepted answer is pretty lame; check out this one instead: https://stackoverflow.com/a/36621185/398630 – BrainSlugs83 Oct 29 '18 at 04:41

2 Answers2

13

Another way which doesn't require you to make changes to your EF configuration is to use a custom SerializationBinder, e.g.:

class EntityFrameworkSerializationBinder : SerializationBinder
{
    public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        assemblyName = null;

        if (serializedType.Namespace == "System.Data.Entity.DynamicProxies")
            typeName = serializedType.BaseType.FullName;
        else
            typeName = serializedType.FullName;
    }

    public override Type BindToType(string assemblyName, string typeName)
    {
        throw new NotImplementedException();
    }
}

Usage:

string json = JsonConvert.SerializeObject(entityFrameworkObject, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, Binder = new EntityFrameworkSerializationBinder() });
bambam
  • 331
  • 3
  • 8
  • Although functional, I'd suggest that anyone trying this take some performance measurements with this approach. I found it to be extremely slow. – Nate Jackson Oct 06 '18 at 17:35
  • 1
    @NateJackson Testing here shows the performance difference with and without the binder is negligible. I suspect the issue lies with EF. Is lazy loading enabled on your data context? If it is, the serialization process may be triggering round trips to the database which in turn will cause extremely slow performance. Try disabling lazy loading and use `Include()` to fetch related data before serializing. – bambam Oct 08 '18 at 09:50
  • 1
    This should be the correct answer! -- Turning off useful EF features is silly when we can just correct the undesired behavior. – BrainSlugs83 Oct 29 '18 at 04:40
3

You can do two things:

  • disabling tracking proxies, by setting ProxyCreationEnabled to false. You can find this property in your context's Configuration property. If you use a context for a single GetXxx method, you can do it without interfering other context instanced.

  • using the AsNoTracking() extension method when you recover your entity, like this:

    MyContext.MyTable.AsNoTracking(). // rest of the query here

This indicates that you don't want a tracking proxy for your entity, so you'll get the entity class. This has no interference with the afore mentioned configuration.

JotaBe
  • 38,030
  • 8
  • 98
  • 117
  • 1
    I guess you right. Although I could envision Json.NET to simply take the base class instead of the proxy when serializing. – Dejan Jun 09 '14 at 09:26
  • Does anybody know a reference to a good documentation about side-effects of disabling proxy generation? – Dejan Jun 09 '14 at 09:27
  • Here you have a great explanation: http://stackoverflow.com/questions/7111109/should-i-enable-or-disable-dynamic-proxies-with-entity-framework-4-1-and-mvc3 – JotaBe Jun 09 '14 at 10:15
  • I had the same problem but it behaves wierdly.. xml serialization alone fails complaining the dynamic proxy stuffs but the json serialization works fine.. any thoughts – TechQuery Oct 07 '15 at 17:57
  • Please, open a new question, and explain it a little better. The behaviors and configuration of XML and JSON serializer are different, so it can be a different problem. If you do so, let me know, and I'll try to help you. – JotaBe Oct 07 '15 at 19:07