C# 如何将动态代理转换为POCO?
我试图序列化一个域模型,但遇到了一个问题,需要将动态代理转换为POCO。我遇到的问题是,循环引用通过模型中的虚拟属性存在。虽然我试图使用C# 如何将动态代理转换为POCO?,c#,asp.net-mvc-3,serialization,entity-framework-4.1,dynamic-proxy,C#,Asp.net Mvc 3,Serialization,Entity Framework 4.1,Dynamic Proxy,我试图序列化一个域模型,但遇到了一个问题,需要将动态代理转换为POCO。我遇到的问题是,循环引用通过模型中的虚拟属性存在。虽然我试图使用[ScriptIgnore]使序列化程序不解析这些属性,但它仍然会解析这些属性。我认为这是因为对象是动态代理,并且属性中仍然存在一些导致解析器进入的残余(这反过来会导致递归错误“循环引用”-我尝试将递归限制为3个步骤,但我得到了一个错误“超过递归步骤”) 如何将对象从动态代理转换为POCO,以便可以序列化 编辑:简单示例 public class One : B
[ScriptIgnore]
使序列化程序不解析这些属性,但它仍然会解析这些属性。我认为这是因为对象是动态代理,并且属性中仍然存在一些导致解析器进入的残余(这反过来会导致递归错误“循环引用”-我尝试将递归限制为3个步骤,但我得到了一个错误“超过递归步骤”)
如何将对象从动态代理转换为POCO,以便可以序列化
编辑:简单示例
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);
}
}
公共类一:BaseViewModel
{
public int OneId{get;set;}
公共虚拟ICollection二{get;set;}
}
公共二班
{
public int TwoId{get;set;}
public int OneId{get;set;}
[脚本忽略]
公共虚拟一{get;set;}
}
公共抽象类BaseViewModel
{
公共字符串AsJson()
{
var serializer=新的JavaScriptSerializer();
返回序列化程序。序列化(此);
}
}
这是一个已知的问题
我们修复了ScriptIgnoreAttribute中的一个问题,该问题没有传播到派生类。由于POCO代理类型是通过从用户提供的POCO类派生而创建的,因此JavaScriptSerializer无法看到复制中的[ScriptIgnore]属性
下一个.NET 4.5预览版本中将不包括该修复程序
(因此,您可能需要等待以下预览版本或最终版本)
这在.NET4.5中是固定的
从对该问题的评论来看,如果您使用的是当前版本的JSON.Net,那么您似乎可以使用NonSerializedAttribute而不是ScriptIgnoreAttribute来解决这个问题。Travis,我知道您在这里得到了公认的答案,但我想在这一点上传递一点横向思考。我最近遇到了一个非常类似的问题,我找不到任何适合我的东西,尝试了所有的[scriptignore]装束等等 最终对我有用的是使用Automapper并创建一个从代理对象到精简的poco对象的映射。这在2分钟内解决了我所有的问题。这一切都是在36小时的围攻之后发生的。在试图让代理人打球时,精神状态占了上风——嘘:——) 另一个需要考虑的过渡方法 [编辑]-使用Automapper(这是一个引用Automapper的小测试应用程序) 参考: nuget:安装包自动映射器 课程:
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; }
}
公共密封一级:BaseViewModel
{
//在测试中未使用EF时初始化ctor中的集合
//在real app中没有要求
公共一号
{
二=新集合();
}
public int OneId{get;set;}
公共ICollection二{get;set;}
}
公共二班
{
public int TwoId{get;set;}
public int OneId{get;set;}
[脚本忽略]
公共虚拟一{get;set;}
}
公共抽象类BaseViewModel
{
公共字符串AsJson()
{
var serializer=新的JavaScriptSerializer();
返回序列化程序。序列化(此);
}
}
公共类OnePoco:BaseViewModel
{
public int OneId{get;set;}
公共虚拟ICollection二{get;set;}
}
公共类TwoPoco
{
public int TwoId{get;set;}
public int OneId{get;set;}
}
测试控制器代码:
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
// i.e. oneMapped.AsJson
var oneMapped = AutoMapper.Mapper.Map<One, OnePoco>(oneProxy);
return View(oneMapped);
}
public ActionResult Index()
{
//假设这是您的基本代理对象
一个oneProxy=newone{OneId=1};
//添加一些集合项目
Add(newtwo(){OneId=1,TwoId=1,One=oneProxy});
Add(newtwo(){OneId=1,TwoId=2,One=oneProxy});
//创建一个映射(应该放在global.asax中
//或在应用程序中(启动类)
AutoMapper.Mapper.CreateMap();
AutoMapper.Mapper.CreateMap();
//做映射-宾果,现在检查asjson
//即oneMapped.AsJson
var oneMapped=AutoMapper.Mapper.Map(oneProxy);
返回视图(oneMapped);
}
试一试,看看你的进展如何,这对我来说确实有效,“地球”移动了:)作为Jim的Automapper解决方案的替代方案,我已经成功地将POCO代理“映射”(浅拷贝)到同一POCO的实例。执行此操作的简单方法是修改生成POCO的模板文件,使其包含ToSerializable()方法,因此POCO类如下所示:
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,
};
}
}
公共部分类cfgCountry
{
公共CFG国家()
{
this.People=newhashset();
}
[关键]
public int CountryID{get;set;}
公共字符串名称{get;set;}
公共整数序号{get;set;}
公共虚拟ICollection人员{get;set;}
公共CFG国家可串行化()
{
返回新的cfgCountry()
{
CountryID=this.CountryID,
Name=this.Name,
序数=这个。序数,
};
}
}
下面是我添加到POCO模板(tt)文件中的函数,用于创建ToSerializable函数(如此难看的语法):
公共可串行化()
{
返回新的()
{
=这个。,
};
}
这并不完美,因为每当您希望序列化结果时,您需要记住返回foo.ToSerializable(),而不是foo本身,但我希望它对某些人有用。代理是它们所代表的POCO的一个子类。通常,您应该能够很好地序列化它们。你能发布一个你无法序列化的类的小而完整的例子吗?@EricJ。-正常构造时,该类将序列化。我可以发布一个例子,但我不确定它会有多大帮助,因为
<#+
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#>,
<#+
}
#>
};
}
<#+
}
#>