c# - EF TPH inheritance lost in Web Api JSON -


i've set classes use tph ef inheritance, mybaseclass, mysubclass1, mysubclass2 etc.

when querying using linq context.mybaseclasses.where(...), objects returned correctly use subclass specified discriminator field in database. (so might end list containing mix of objects of mysubclass1, or mysubclass2.)

however, when pass these objects wpf application, via json web api call, objects received of mybaseclass, rather correct sub class started off at.

the object property returned via of type public virtual list<mybaseclass> mythings, guess makes sense end type, want retain correct sub class type each object.

how achieve this? need force ef discriminator field sent along other data somehow?

edit

1.

at client end, i'm attempting deserialize json (including $type data) (with no luck, items still converted base class)

httpresponsemessage response = getclient().getasync(url).result;  if (response.issuccessstatuscode) {     string jsonmessage;     using (stream responsestream = response.content.readasstreamasync().result)     {         jsonmessage = new streamreader(responsestream).readtoend();     }       list<my.domain.models.mybaseclass> thingstoreturn;      //new method         thingstoreturn = jsonconvert.deserializeobject<list<my.domain.models.mybaseclass>>(jsonmessage);      //previous method     //thingstoreturn = response.content.readasasync<list<my.domain.models.mybaseclass>>().result;      return thingstoreturn; } 

2.

following anish's advice re serializersettings.typenamehandling, i've got $type information appearing in json, of type system.data.entity.dynamicproxies.subclass1_5e07a4ce2f037430dc7bfa00593.... ok client end deserialize subclass1 successfully?

this serialization concern.

you can customize json.net's serializer settings include type information json objects.

add httpconfiguration:

config.formatters.jsonformatter.serializersettings.typenamehandling = typenamehandling.auto; 

where config httpconfiguration instance use configure , initialize asp.net webapi.

this tell json.net add type information each json object has type ambiguity. such object this:

{     "$type":"myprojectcontainingmytypes.mysubclass1, myprojectcontainingmytypes",     "name": "tyrion lannister",     "displayname": "the imp",     "traits": ["funny", "awesome", "clever"] } 

json.net know how deal when deserialize on wpf side.

this should work, in wpf app:

var things = jsonconvert.deserializeobject<list<mybaseclass>>(jsonstring); 

then can cast objects in things list respective derived types.

of course, wpf application need have reference project define mybaseclass , mysubclass1.

edit

thanks anish, that's sorted it. can see correct $type data in json, i'm being dunce, , i'm not sure how webapi response jsonstring? @ minute i'm doing response.content.readasasync>().result; auto deserialize data.

in response comment, can read content string this:

var jsonstring = response.content.readasstringasync().result; 

edit 2

anish, input. can see, i've managed json string now, using jsonconvert.deserializeobject i'm still getting same issue. think (as mention in edit 2) $type being returned service incorrectly (as ef proxy type)?

in response comment, yes not able deserialize ef proxy type type want. issue needs resolved on webapi side.

the proxy classes created allow lazy load entities. proxies used represent referenced/nested entities. allows fetching of referenced entities database deferred until required, if required @ all.

here link documentation around lazy , eager loading entities ef.

solution

you want hydrate list of objects in webapi controller action , return it, tell ef load entities database , new instances of classes.

you have few options here:

option 1

call tolist() on query hydrate collection:

var result = (from t in dbcontext.things select t).tolist(); 

or

var result = dbcontext.things.tolist(); 

naturally, don't want return unbounded result set add range:

var result = (from t in dbcontext.things select t).skip(0).take(10).tolist(); 

or

var result = dbcontext.things.skip(0).take(10).tolist(); 

bear in mind method have explicitly hydrate nested objects this:

var result = dbcontext              .things              .include(t => t.somepropertythatrepresentssomenestedobject)               .skip(0)              .take(10)              .tolist(); 

option 2

turn off lazy loading dbcontext.

personally, i'd go option 1, think better know entities , have control on when , hydrate.


Comments