How to convert dynamic proxy to POCO?

I tried to serialize a domain model and ran into a problem when I needed to convert a dynamic proxy to POCO. The problem I ran into was that circular references exist through virtual properties in the model. Although I tried using [ScriptIgnore] so that the serializer does not parse these properties, it still does. I believe this is because objects are dynamic proxies, and there are still leftovers in the properties that force the parser to enter (which in turn causes a circular reference recursion error) - I tried to limit recursion 3 steps, but I got the error "Recursive steps exceeded").

How to convert an object from a dynamic proxy to POCO so that it can be serialized?

Edit: simple example

 public class One : BaseViewModel { public int OneId { get; set; } public virtual ICollection<Two> Two { get; set; } } public class Two { public int TwoId { get; set; } public int OneId { get; set; } [ScriptIgnore] public virtual One One { get; set; } } public abstract class BaseViewModel { public string AsJson() { var serializer = new JavaScriptSerializer(); return serializer.Serialize(this); } } 
+6
source share
3 answers

This is a known issue.

We fixed a problem in ScriptIgnoreAttribute that did not extend to derived classes. Because POCO proxy types are created by getting the POCO class provided by the user, JavaScriptSerializer was not able to see the [ScriptIgnore] attributes that you have in your playback.

The hotfix will not be included in the next preliminary release of .NET 4.5.

(so you probably have to wait for the next preview or final version)

http://connect.microsoft.com/VisualStudio/feedback/details/723060/ef-4-2-code-first-property-attributes-not-honoured

which is fixed in .NET 4.5

From the comments on this problem, it seems you can get around using NonSerializedAttribute instead of ScriptIgnoreAttribute if you are using the current version of JSON.Net

+3
source

As an alternative to the Jim Automapper solution, I had some success with the “Mapping” (small copy) POCO proxy to an instance of the same POCO. An easy way to do this is to modify the template file that POCO generates to enable the ToSerializable () method, so the POCO classes look like this:

 public partial class cfgCountry { public cfgCountry() { this.People = new HashSet<Person>(); } [Key] public int CountryID { get; set; } public string Name { get; set; } public int Ordinal { get; set; } public virtual ICollection<Person> People { get; set; } public cfgCountry ToSerializable() { return new cfgCountry() { CountryID = this.CountryID, Name = this.Name, Ordinal = this.Ordinal, }; } } 

Here is the function that I added to the POCO (tt) template file to create the ToSerializable function (such an ugly syntax.):

 <#+ void WriteToSerializableMethod (CodeGenerationTools code, IEnumerable<EdmProperty> primitiveProperties, EntityType entity) { #> public <#=code.Escape(entity)#> ToSerializable() { return new <#=code.Escape(entity)#>() { <#+ foreach(var edmProperty in primitiveProperties) { #> <#=edmProperty.Name#> = this.<#=edmProperty.Name#>, <#+ } #> }; } <#+ } #> 

This is not ideal, since you need to remember to return foo.ToSerializable (), not foo, whenever you expect the result to be serialized, but I hope it is useful to someone.

+4
source

Travis, I know that you have your accepted answer here, but I wanted to talk a little about it. Recently, I ran into very similar problems and couldn’t make it work for me, tried all the attributes [scriptignore], etc. Etc.

What ultimately worked for me was using Automapper and creating a map from a proxy object to a slimmed down poco object. This allowed me to solve all my problems within 2 minutes. All this after a 36-hour siege that prevailed when trying to force a proxy to play ball-shish :-)

Another approach to thinking in the interim.

[Change] - using Automapper (this is a small test application that refers to automapper)

ref: http://automapper.codeplex.com/

nuget: Install-Package AutoMapper

Classes:

 public sealed class One : BaseViewModel { // init collection in ctor as not using EF in test // no requirement in real app public One() { Two = new Collection<Two>(); } public int OneId { get; set; } public ICollection<Two> Two { get; set; } } public class Two { public int TwoId { get; set; } public int OneId { get; set; } [ScriptIgnore] public virtual One One { get; set; } } public abstract class BaseViewModel { public string AsJson() { var serializer = new JavaScriptSerializer(); return serializer.Serialize(this); } } public class OnePoco : BaseViewModel { public int OneId { get; set; } public virtual ICollection<TwoPoco> Two { get; set; } } public class TwoPoco { public int TwoId { get; set; } public int OneId { get; set; } } 

test controller code:

 public ActionResult Index() { // pretend this is your base proxy object One oneProxy = new One { OneId = 1 }; // add a few collection items oneProxy.Two.Add(new Two() { OneId = 1, TwoId = 1, One = oneProxy}); oneProxy.Two.Add(new Two() { OneId = 1, TwoId = 2, One = oneProxy}); // create a mapping (this should go in either global.asax // or in an app_start class) AutoMapper.Mapper.CreateMap<One, OnePoco>(); AutoMapper.Mapper.CreateMap<Two, TwoPoco>(); // do the mapping- bingo, check out the asjson now // ie oneMapped.AsJson var oneMapped = AutoMapper.Mapper.Map<One, OnePoco>(oneProxy); return View(oneMapped); } 

give it a try and see how you do it, it certainly worked for me, the earth has moved :)

+3
source

Source: https://habr.com/ru/post/919792/


All Articles