我的Web api项目中有一个Report
类:
[KnownType(typeof(Employee))]
[DataContract]
public class Report
{
[DataMember]
public int Id { get; set; }
public string ManagerId { get; set; }
public string EmployeeId { get; set; }
[DataMember]
public virtual Employee Manager { get; set; }
[DataMember]
public virtual Employee Employee { get; set; }
}
如果
virtual
在方法签名中,则会出现以下异常:类型为'System.Data.Entity.DynamicProxies.Report_1FFC700B8A805A61BF97A4B9A18D60F99AAA83EE08F4CA2E2454BADA9737B476'的数据合约名称为'Report_1FFC700B8A805A61BF97A4B9A18D60F99AAA83EE08F4CA2E2454BADA是not考虑使用DataContractResolver或将任何静态未知的类型添加到已知类型的列表中-例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型的列表中。
如果不是,那么一切正常。我想念什么?
编辑以包括对象检索代码
ApiController
[ResponseType(typeof(IEnumerable<Report>))]
public IHttpActionResult GetLogs([FromUri] string id)
{
return Ok(_loggingService.GetReportsByEmployeeId(id));
}
服务
public IQueryable<Report> GetReportsByEmployeeId(string employeeId)
{
return _reports.GetAll().Where(x => x.ManagerId.Equals(employeeId) || x.EmployeeId.Equals(employeeId));
}
资料库
public IQueryable<T> GetAll()
{
return _dbSet;
}
最佳答案
大概是使用实体框架或类似的ORM检索此对象。
当您没有任何虚拟属性时,ORM可以安全地使用Type的实例。但是,当您具有虚拟属性时,ORM必须使用其自己的Type才能支持延迟加载,这就是为什么您看到序列化程序抱怨它无法序列化'DynamicProxies'类型的原因。
为避免这种情况,请将您的域模型与序列化模型分开,并在对Select的调用中返回序列化模型的实例。
或者,关闭ORM中的延迟加载(不推荐)
编辑:添加示例,如注释中所述
如前所述,理想情况下,应将域模型(用于与数据库交互的数据的对象表示形式)和业务模型(用于业务逻辑的数据对象表示形式)分开。此外,服务之外的任何事物都不应直接接触域模型,因为这样做有可能引发意外的延迟负载,跨代码库的职责模糊或其他不良后果。
顺便说一句,这种分离将避免您遇到的问题。下面的示例当然可以随意更改名称空间和Type名称。
商业模式
namespace MyCompany.MyProject.BusinessModels
{
[KnownType(typeof(Employee))]
[DataContract]
public class Report
{
[DataMember]
public int Id { get; set; }
[DataMember]
public virtual Employee Manager { get; set; }
[DataMember]
public virtual Employee Employee { get; set; }
}
}
领域模型
namespace MyCompany.MyProject.DomainModels
{
// this separation may seem like overkill, but when you come to
// want different business models than your domain models, or to decorate
// this model with Entity Framework specific attributes, you'll be glad
// for the separation.
public class Report
{
public int Id { get; set; }
public virtual Employee Manager { get; set; }
public virtual Employee Employee { get; set; }
}
}
服务
public IQueryable<BusinessModels.Report> GetReportsByEmployeeId(string employeeId)
{
return _reports // _reports is a collection of Type DomainModels.Report
.GetAll()
.Where(x =>
x.ManagerId.Equals(employeeId)
|| x.EmployeeId.Equals(employeeId))
.Select(s =>
new BusinessModels.Report
{
Id = s.Id,
Employee = s.Employee,
Manager = s.Manager
})
.ToList();
// We don't want database access happening outside of the service.
// ToList() executes the SQL *now* rather than waiting until
// the first time you enumerate the result.
}