SerializationException将虚拟添加到属性

tra*_*m_3 3 c# entity-framework asp.net-web-api

Report我的web api项目中有一个类:

[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; }
}
Run Code Online (Sandbox Code Playgroud)

如果virtual在方法签名中,我会得到以下异常:

输入数据合同名称为"System.Data.Entity.DynamicProxies.Report_1FFC700B8A805A61BF97A4B9A18D60F99AAA83EE08F4CA2E2454BADA9737B476"的数据为"Report_1FFC700B8A805A61EEF97A4B9A18D60F99AAA83EE08F4CA2E2454BADA9737B476:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies ".考虑使用DataContractResolver或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型列表中.

如果不是一切都行得通.我错过了什么?


编辑包括对象检索代码

ApiController

[ResponseType(typeof(IEnumerable<Report>))]
public IHttpActionResult GetLogs([FromUri] string id)
{
    return Ok(_loggingService.GetReportsByEmployeeId(id));
}
Run Code Online (Sandbox Code Playgroud)

服务

public IQueryable<Report> GetReportsByEmployeeId(string employeeId)
{
    return _reports.GetAll().Where(x => x.ManagerId.Equals(employeeId) || x.EmployeeId.Equals(employeeId));
}
Run Code Online (Sandbox Code Playgroud)

知识库

public IQueryable<T> GetAll()
{
    return _dbSet;
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*lis 6

据推测,您正在使用实体框架或类似的ORM检索此对象.

当您没有任何虚拟属性时,ORM可以安全地使用您的Type实例.但是,当你有虚拟属性时,ORM必须使用它自己的Type才能支持延迟加载,这就是为什么你看到序列化程序抱怨它无法序列化Type'DynamicProxies'.

为避免这种情况,请将域模型与序列化模型分开,并在调用Select时返回序列化模型的实例.

或者,关闭ORM中的延迟加载(不推荐)

编辑:添加注释中讨论的示例

如上所述,您的域模型(用于与数据库交互的数据的对象表示)和业务模型(您为业务逻辑操作的数据的对象表示)理想情况下应该分开.此外,服务之外的任何内容都不应直接触及域模型,因为这样做可能会触发意外的延迟负载,模糊代码库中的责任或其他令人讨厌的结果.

顺便说一句,这种分离将避免您遇到的问题.下面的示例当然可以根据需要随意更改名称空间和类型名称.

商业模式

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

领域模型

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

服务

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.
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用获取对象的代码更新问题,我将在桌面上更新答案 (2认同)