ASP.NET Web API调用GetPrizes()时序列化失败问题排查求助
问题描述
我正在开发一个包含3个控制器(HomeController、LaureatesController、PrizesController)的ASP.NET Web API项目。调用PrizesController中的GetPrizes() GET方法时,出现以下错误:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'
相关代码如下:
PrizesController代码
private ApplicationDbContext db = new ApplicationDbContext(); public IEnumerable<object> GetPrizes() { var prizes = db.Prizes.ToList() .Select(prize => new { prize.PrizeID, prize.Category, prize.Year, Laureates = prize.Laureates.Select(Laureate => new { Laureate.LaureateID, Laureate.Surname, Laureate.FirstName, Laureate.Gender, Laureate.Born, Laureate.BornCountry, Laureate.Died }) }); return db.Prizes; }
WebApiConfig.cs配置
public static void Register(HttpConfiguration config) { // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); var json = config.Formatters.JsonFormatter; json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects; config.Formatters.Remove(config.Formatters.XmlFormatter); json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; }
Global.asax代码
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } }
错误原因分析
- 返回对象不匹配:方法内构建了处理后的匿名类型集合
prizes,但最终返回的是原始实体集合db.Prizes。原始实体存在双向导航属性(Prize与Laureate互相引用),即便配置了ReferenceLoopHandling.Ignore,序列化时仍可能因延迟加载触发的关联加载导致失败。 - 延迟加载与代理对象问题:EF默认启用延迟加载,返回原始实体时,序列化器会尝试加载关联的
Laureates数据,过程中生成的动态代理对象无法被正常序列化。
解决办法
方案1:返回处理后的匿名对象集合
修改GetPrizes()方法,确保返回预先构建好的匿名类型集合,而非原始实体:
public IEnumerable<object> GetPrizes() { var prizes = db.Prizes.ToList() .Select(prize => new { prize.PrizeID, prize.Category, prize.Year, Laureates = prize.Laureates.Select(Laureate => new { Laureate.LaureateID, Laureate.Surname, Laureate.FirstName, Laureate.Gender, Laureate.Born, Laureate.BornCountry, Laureate.Died }) }); return prizes; // 返回处理后的集合,替换原db.Prizes }
方案2:禁用延迟加载与代理创建
若需返回原始实体,可在DbContext中禁用延迟加载和动态代理生成,避免序列化时的关联加载与代理对象问题:
public class ApplicationDbContext : DbContext { public ApplicationDbContext() { Configuration.LazyLoadingEnabled = false; Configuration.ProxyCreationEnabled = false; } // DbSet定义... }
方案3:使用DTO类(推荐)
创建专用的DTO(数据传输对象)类,明确控制序列化的数据结构,提升代码可维护性:
// PrizeDTO.cs public class PrizeDTO { public int PrizeID { get; set; } public string Category { get; set; } public int Year { get; set; } public List<LaureateDTO> Laureates { get; set; } } // LaureateDTO.cs public class LaureateDTO { public int LaureateID { get; set; } public string Surname { get; set; } public string FirstName { get; set; } public string Gender { get; set; } public DateTime? Born { get; set; } public string BornCountry { get; set; } public DateTime? Died { get; set; } }
修改控制器方法:
public IEnumerable<PrizeDTO> GetPrizes() { var prizes = db.Prizes.Select(prize => new PrizeDTO { PrizeID = prize.PrizeID, Category = prize.Category, Year = prize.Year, Laureates = prize.Laureates.Select(laureate => new LaureateDTO { LaureateID = laureate.LaureateID, Surname = laureate.Surname, FirstName = laureate.FirstName, Gender = laureate.Gender, Born = laureate.Born, BornCountry = laureate.BornCountry, Died = laureate.Died }).ToList() }).ToList(); return prizes; }
内容的提问来源于stack exchange,提问作者user20792585
相关产品推荐
相关产品推荐

