【问题标题】:Asp.Net Web API Error: The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'Asp.Net Web API 错误:“ObjectContent`1”类型无法序列化内容类型“application/xml”的响应正文;字符集=utf-8'
【发布时间】:2012-12-07 04:45:53
【问题描述】:

最简单的例子,我得到一个集合并尝试通过 Web API 输出它:

// GET api/items
public IEnumerable<Item> Get()
{
    return MyContext.Items.ToList();
}

我得到了错误:

对象类型
'System.Data.Objects.ObjectQuery`1[Dcip.Ams.BO.EquipmentWarranty]' 无法转换为类型
'System.Data.Entity.DbSet`1[Dcip.Ams.BO.EquipmentWarranty]'

这是一个与新代理有关的非常常见的错误,我知道我可以通过设置来修复它:

MyContext.Configuration.ProxyCreationEnabled = false;

但这违背了我正在尝试做的很多事情的目的。有没有更好的办法?

【问题讨论】:

  • 关闭代理是如何破坏序列化对象的?
  • 它是一个代理对象,而不是实际的 POCO
  • 全局关闭代理意味着您无法使用延迟加载的导航属性。我同意如果您需要导航属性,这不是一个合适的解决方案。仍在为这个问题寻找答案。

标签: entity-framework entity-framework-4 asp.net-web-api


【解决方案1】:

如果您有导航属性,请将它们设为非虚拟。映射仍然有效,但它会阻止创建无法序列化的动态代理实体。]

在 WebApi 中没有延迟加载很好,因为您没有持久连接,并且无论如何您都运行了 .ToList()。

【讨论】:

  • 我遇到了同样的问题,并且将导航属性设置为非虚拟可以解决问题,但我很想知道这种技术是否有任何缺点?谢谢!
  • @Robert 将它们标记为 vitual 将允许在内部覆盖该类。 EF 将覆盖以允许延迟加载,例如,它只会在请求时获取内部列表或属性。对于 MVC 或存在断开连接的架构的情况,它确实没有什么区别,因为您立即需要所有数据。
【解决方案2】:

我建议仅在您不需要或给您带来麻烦的地方禁用代理创建。您不必全局禁用它,您只需通过代码禁用当前数据库上下文...

    [HttpGet]
    [WithDbContextApi]
    public HttpResponseMessage Get(int take = 10, int skip = 0)
    {
        CurrentDbContext.Configuration.ProxyCreationEnabled = false;

        var lista = CurrentDbContext.PaymentTypes
            .OrderByDescending(x => x.Id)
            .Skip(skip)
            .Take(take)
            .ToList();

        var count = CurrentDbContext.PaymentTypes.Count();

        return Request.CreateResponse(HttpStatusCode.OK, new { PaymentTypes = lista, TotalCount = count });
    }

这里我只在这个方法中禁用了 ProxyCreation,因为对于每个请求都会创建一个新的 DBContext,因此我只在这种情况下禁用了 ProxyCreation。 希望对你有帮助

【讨论】:

    【解决方案3】:

    如果您有导航属性并且不想将它们设为非虚拟属性,则应使用 JSON.NET 并将 App_Start 中的配置更改为使用 JSON 而不是 XML!
    从 NuGet 安装 JSON.NET 后,将此代码插入 WebApiConfig.cs 中的 Register 方法

    var json = config.Formatters.JsonFormatter;
    json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
    config.Formatters.Remove(config.Formatters.XmlFormatter);
    

    【讨论】:

    • 在配置中添加代码有效。假设 VS15 上的新 webapi 项目默认添加 JSON.NET
    【解决方案4】:

    在我的情况下,返回的对象中有一个属性,其类型没有无参数/默认构造函数。通过向该类型添加零参数构造函数,可以成功序列化对象。

    【讨论】:

      【解决方案5】:

      我只是根据需要禁用了代理类:

          // GET: ALL Employee
          public IEnumerable<DimEmployee> Get()
          {
              using (AdventureWorks_MBDEV_DW2008Entities entities = new AdventureWorks_MBDEV_DW2008Entities())
              {
                  entities.Configuration.ProxyCreationEnabled = false;
                  return entities.DimEmployees.ToList();
              }
          }
      

      【讨论】:

        【解决方案6】:

        Global.asax.csApplication_Start函数中添加如下代码:

        GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
            .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        GlobalConfiguration.Configuration.Formatters
            .Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
        

        这指示 API 将每个响应序列化为 JSON 并删除 XML 响应。

        【讨论】:

          【解决方案7】:

          禁用代理创建后,使用预加载(Include())加载代理对象。

          【讨论】:

            【解决方案8】:

            在从 WebApi 操作方法返回的我的项目 EntityCollection 中。 Configuration.ProxyCreationEnabled = false 不适用。我已经尝试了以下方法,它对我来说效果很好。

            1. 控制面板。 2.打开或关闭 Windows 功能
            2. 选择互联网信息服务
            3. 检查所有万维网组件最好检查 IIS 中的所有组件。
            4. 安装组件。
            5. 在命令提示符中转到 (IIS) 类型 inetmgr。
            6. 在虚拟目录中选择已发布的代码。
            7. 转换成应用程序
            8. 浏览它的应用程序。

            【讨论】:

              【解决方案9】:

              我遇到了同样的问题,我的 DTO 缺少一个无参数构造函数。

              public UserVM() { }
              
              public UserVM(User U)
                  {
                      LoginId = U.LoginId;
                      GroupName = U.GroupName;
                  }
              

              第一个构造函数丢失。

              【讨论】:

                【解决方案10】:

                我收到此错误消息,结果发现问题是我不小心将我的类设置为对两个属性使用相同的序列化属性名称:

                public class ResultDto
                {
                    //...
                    [JsonProperty(PropertyName="DataCheckedBy")]
                    public string ActualAssociations { get; set; }
                    [JsonProperty(PropertyName="DataCheckedBy")]
                    public string ExpectedAssociations { get; set; }
                    //...
                }
                

                如果您收到此错误并且您没有直接通过 API 发送实体,请将无法序列化的类复制到 LINQPad 并在其上调用 JsonConvert.SerializeObject(),它应该会为您提供比这更好的错误消息废话。我一尝试,它就给了我以下错误消息:A member with the name 'DataCheckedBy' already exists on 'UserQuery+ResultDto'. Use the JsonPropertyAttribute to specify another name.

                【讨论】:

                  猜你喜欢
                  • 2015-06-27
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-12-13
                  • 2012-10-07
                  • 2020-02-28
                  • 2017-07-17
                  • 1970-01-01
                  • 2017-02-01
                  相关资源
                  最近更新 更多