C# 无法使用Json序列化Web API中的响应

C# 无法使用Json序列化Web API中的响应,c#,asp.net,json,asp.net-web-api,C#,Asp.net,Json,Asp.net Web Api,我正在使用ASP.NETMVC5WebAPI。我想咨询我所有的用户 我编写了api/users,收到了以下信息: “ObjectContent`1'类型未能序列化内容类型'application/json;charset=utf-8'的响应正文” 在WebApiConfig中,我已经添加了以下行: HttpConfiguration config = new HttpConfiguration(); config.Formatters.XmlFormatter.SupportedMediaTyp

我正在使用ASP.NETMVC5WebAPI。我想咨询我所有的用户

我编写了
api/users
,收到了以下信息:

“ObjectContent`1'类型未能序列化内容类型'application/json;charset=utf-8'的响应正文”

在WebApiConfig中,我已经添加了以下行:

HttpConfiguration config = new HttpConfiguration();
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 
但它仍然不起作用

我的返回数据功能如下:

public IEnumerable<User> GetAll()
{
    using (Database db = new Database())
    {
        return db.Users.ToList();
    }
}
public IEnumerable GetAll()
{
使用(Database db=new Database())
{
返回db.Users.ToList();
}
}

当涉及到从Web Api(或任何其他Web服务)将数据返回给消费者时,我强烈建议不要传回来自数据库的实体。使用能够控制数据外观而不是数据库的模型更可靠、更易于维护。这样,您就不必在WebApiConfig中过多地处理格式化程序。您只需创建一个以子模型作为属性的UserModel,并去掉返回对象中的引用循环。这使序列化程序更加快乐

另外,如果您只是在请求中指定“Accepts”头,通常不需要删除格式化程序或支持的媒体类型。玩弄这些东西有时会让事情变得更加混乱

例如:

public class UserModel {
    public string Name {get;set;}
    public string Age {get;set;}
    // Other properties here that do not reference another UserModel class.
}
public HttpResponseMessage Get()
{
    var item = new List<dynamic> { new TestClass { Name = "Ale", Age = 30 } };

    return Request.CreateResponse(HttpStatusCode.OK, item);
}

public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}
[Serializable]
public class UserModel {
    public string Name {get;set;}
    public string Age {get;set;}
}

还有一种情况会产生相同的错误:

如果返回的是
列表
到web api方法

例如:

public class UserModel {
    public string Name {get;set;}
    public string Age {get;set;}
    // Other properties here that do not reference another UserModel class.
}
public HttpResponseMessage Get()
{
    var item = new List<dynamic> { new TestClass { Name = "Ale", Age = 30 } };

    return Request.CreateResponse(HttpStatusCode.OK, item);
}

public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}
[Serializable]
public class UserModel {
    public string Name {get;set;}
    public string Age {get;set;}
}

这对我有用

如果您正在使用EF,除了在Global.asax上添加下面的代码之外

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
    .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters
    .Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);          
别忘了进口

using System.Data.Entity;
然后您可以返回自己的EF模型


就这么简单

我不喜欢这个代码:

foreach(db.Users中的var user)

另一种选择是,你可以这样做,这对我很有用:

var listOfUsers = db.Users.Select(r => new UserModel
                         {
                             userModel.FirstName = r.FirstName;
                             userModel.LastName = r.LastName;

                         });

return listOfUsers.ToList();
var allShops = context.shops.Where(s => s.city_id == id)**.ToList()**;
return allShops;
然而,我最终使用了Lucas Roselli的解决方案

更新:通过返回匿名对象简化:

var listOfUsers = db.Users.Select(r => new 
                         {
                             FirstName = r.FirstName;
                             LastName = r.LastName;
                         });

return listOfUsers.ToList();

要补充jensendp的回答:

我会将实体传递给用户创建的模型,并使用该实体中的值来设置新创建的模型中的值。例如:

public class UserInformation {
   public string Name { get; set; }
   public int Age { get; set; }

   public UserInformation(UserEntity user) {
      this.Name = user.name;
      this.Age = user.age;
   }
}

然后将返回类型更改为:
IEnumerable

给出正确答案是一种方法,但是,如果您可以通过一个配置设置来修复它,这将是一种过度使用。

最好在dbcontext构造函数中使用它

public DbContext() // dbcontext constructor
            : base("name=ConnectionStringNameFromWebConfig")
{
     this.Configuration.LazyLoadingEnabled = false;
     this.Configuration.ProxyCreationEnabled = false;
}

使用AutoMapper

public IEnumerable<User> GetAll()
    {
        using (Database db = new Database())
        {
            var users = AutoMapper.Mapper.DynamicMap<List<User>>(db.Users);
            return users;
        }
    }
public IEnumerable GetAll()
{
使用(Database db=new Database())
{
var users=AutoMapper.Mapper.DynamicMap(db.users);
返回用户;
}
}

我收到此错误的另一种情况是,我的数据库查询返回空值,但我的用户/视图模型类型设置为不可空。例如,将“我的用户模型”字段从
int
更改为
int?
已解决。

将此代码添加到
全局。asax
下面的
应用程序\u Start

.Ignore
更新为
。序列化
。它必须起作用

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

我个人的最爱:只需将下面的代码添加到
App\u Start/WebApiConfig.cs
。默认情况下,这将返回json而不是XML,还可以防止出现错误。无需编辑
Global.asax
即可删除
XmlFormatter

'ObjectContent'1'类型未能序列化内容类型'application/xml'的响应正文;字符集=utf-8

公共类用户控制器:ApiController
{
数据库db=新数据库();
//建筑
公共用户控制器()
{
//添加以下代码
//问题会解决的
db.Configuration.ProxyCreationEnabled=false;
}
公共IEnumerable GetAll()
{
返回db.Users.ToList();
}
}

使用以下命名空间:

使用System.Web.OData

而不是:

使用System.Web.Http.OData


它对我有效

对我有效的解决方案:

var listOfUsers = db.Users.Select(r => new UserModel
                         {
                             userModel.FirstName = r.FirstName;
                             userModel.LastName = r.LastName;

                         });

return listOfUsers.ToList();
var allShops = context.shops.Where(s => s.city_id == id)**.ToList()**;
return allShops;
  • 对类使用
    [DataContract]
    ,对每个要序列化的属性使用
    [DataMember]
    属性。这足以获得Json结果(例如,来自fiddler)

  • 要获取xml序列化,请写入
    Global.asax
    此代码:

    var xml=GlobalConfiguration.Configuration.Formatters.XmlFormatter;
    xml.UseXmlSerializer=true

  • 阅读这篇文章,它帮助我理解了序列化:

  • 当响应类型不是public时也会发生这种情况! 在使用VisualStudio生成类型时,我返回了一个内部类

    internal class --> public class
    

    虽然上述所有答案都是正确的,但您可能需要检查InnerException>ExceptionMessage

    如果它显示类似于“T的内容,则ObjectContext实例已被释放,不能再用于需要连接的操作。”。这可能是一个问题,因为EF的默认行为

    通过在DbContext构造函数中指定LazyLoadingEnabled=false,可以实现这一目的

    public class MyDbContext : DbContext
    {
      public MyDbContext()
      {
        this.Configuration.LazyLoadingEnabled = false;
      }
    }
    

    有关EF的快速加载和懒散加载行为的更多详细信息,请参阅此。

    将此添加到
    应用程序的
    全局方法中。asax
    文件应该可以解决此问题

    protected void Application_Start()
    {
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
            .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        GlobalConfiguration.Configuration.Formatters
            .Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter); 
    // ...
    }
    
    方法2:[不推荐]
    如果使用EntityFramework,可以在DbContext类构造函数中禁用代理。注意:如果您更新模型,此代码将被删除

    public class MyDbContext : DbContext
    {
      public MyDbContext()
      {
        this.Configuration.ProxyCreationEnabled = false;
      }
    }
    

    在我的情况下,我收到了类似的错误消息:

    ObjectContent“1”类型未能序列化的响应正文 “内容类型”应用程序/xml;字符集=utf-8'

    但当我深入研究时,问题是:

    键入“name.someSubrototype” 使用数据合同名称 “萨默奥特ype://schemas.datacontract.org/2004/07/WhatEverService' 这是预料不到的。考虑使用DATACONTracTracver
    var allShops = context.shops.Where(s => s.city_id == id)**.ToList()**;
    return allShops;
    
    this.Configuration.ProxyCreationEnabled = false;
    
    public ProductEntities() : base("name=ProductEntities")
    {
        this.Configuration.ProxyCreationEnabled = false;
    }
    
    public IEnumerable<Brand_Details> Get()
    {
        using (ProductEntities obj = new ProductEntities())
        {
            this.Configuration.ProxyCreationEnabled = false;
            return obj.Brand_Details.ToList();
        }
    }
    
    [Serializable]
    public class UserModel {
        public string Name {get;set;}
        public string Age {get;set;}
    }
    
    public virtual MembershipType MembershipType { get; set; }
    
    public MembershipType MembershipType { get; set; }
    
    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;  
    GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
    
    using System.Data.Entity;