从 MVC 4 Web Api 返回匿名类型失败并出现序列化错误
Posted
技术标签:
【中文标题】从 MVC 4 Web Api 返回匿名类型失败并出现序列化错误【英文标题】:Returning an anonymous type from MVC 4 Web Api fails with a serialization error 【发布时间】:2013-02-04 09:48:11 【问题描述】:我刚刚开始使用 MVC 4 Web API,我似乎误解了它的工作原理。
在使用 Web API 之前,我有一个简单的 MVC 操作方法,如下所示:
public JsonResult User()
return Json(new
firstName = "Joe",
lastName = "Jacobs",
email = "joe.jacobs@gmail.com"
);
这样就可以了。在新的 Web API 控制器中,我正在尝试做类似的事情。
public object User()
return new
firstName = "Joe",
lastName = "Jacobs",
email = "joe.jacobs@gmail.com"
这会因序列化错误而失败:
“ObjectContent`1”类型未能序列化内容类型“application/xml;”的响应正文; charset=utf-8'。
内部异常:
类型 'f__AnonymousType1`3[System.String,System.String,System.String]' 无法序列化。考虑使用 DataContractAttribute 属性对其进行标记,并使用 DataMemberAttribute 属性标记您想要序列化的所有成员。如果类型是集合,请考虑使用 CollectionDataContractAttribute 对其进行标记。有关其他支持的类型,请参阅 Microsoft .NET Framework 文档。
关于从 API 控制器返回匿名类型,我有什么不明白的地方?
【问题讨论】:
当您请求 json 而不是 xml 时,您是否尝试并检查过它是否有效?不管怎样,看看这个:***.com/questions/10123371/…,你可以使用HttpResponseMessage
作为你的 WebApi 方法的返回类型,并将资源添加到它。
“我在浏览器中点击 URL,所以我明白默认情况下它会尝试返回 XML,但即使我请求 JSON,我也会遇到同样的错误。”
你的浏览器是什么?铬?
是的。无论浏览器如何,它都会失败。
这很奇怪,因为我现在正在这样做,和你一样。如果您使用 JsonResult 并返回 JSON - 您在客户端调用中请求的类型是 JSON,而不是 XML?
【参考方案1】:
如果您查看 Fiddler(此处的示例我使用 Firefox)
默认情况下,来自浏览器的请求将接受 application/xml,而不是 application/json
但是,您可以通过添加一个标头从 Fiddler 创建 假请求:
Accept: application/json
会有用的
来自link:
XML 序列化程序不支持匿名类型或 JObject 实例。如果您将这些功能用于 JSON 数据,则应从管道中删除 XML 格式化程序,如本文后面所述。
如何删除XmlFormatter
:
var configuration = GlobalConfiguration.Configuration;
configuration.Formatters.Remove(configuration.Formatters.XmlFormatter);
【讨论】:
【参考方案2】:您也可以使用 JsonMediaTypeFormatter,这样就不需要 JSONObject 和相关类。然后你可以在你的控制器类中返回一个动态类型。
public static void Register(HttpConfiguration config)
config.Formatters.Clear();
config.Formatters.Add(new JsonMediaTypeFormatter());
config.MapHttpAttributeRoutes();
public class YourController : ApiController
[HttpGet, Route("getstuff/stuffId")]
public dynamic Get(string stuffId)
var stuff = Model.Stuff.Get(stuffId);
return new
success= stuff != null,
stuffId = stuff.Id,
name = stuff.Name
;
如果您还想支持 Jsonp,您可以继承 JsonMediaTypeFormatter 并创建您自己的 JsonpMediaTypeFormatter(也可以在 *** 上找到:https://***.com/a/12492552/1138266)。
【讨论】:
【参考方案3】:我发现 API 不喜欢返回原始列表。相反,我必须创建一个对象,并将对象的值设置为我的列表;请参阅第一个 return 语句。
例子:
public IHttpActionResult GetMessages(int messageFeedId, int lastMessageId)
List<Message> messageDomainObjects = MessageService.GetMessages(messageFeedId, lastMessageId);
if (messageDomainObjects.Any())
var messages = messageDomainObjects.Select(m => new MessageModel(
m.Id,
m.Message,
m.CreatedDate,
m.IsActive,
new UserModel(
m.User.Id,
m.User.FirstName,
m.User.LastName
)
));
return Ok(new messages = messages );
else
return Ok(new );
【讨论】:
【参考方案4】:我遇到了类似的问题,解决方法是在
Global.asax.cs
文件。
要添加的sn-p如下:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters
.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
我还将上述代码行添加到 Application_Start 方法的最顶部,使该方法看起来像这样:
protected void Application_Start()
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters
.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
【讨论】:
以上是关于从 MVC 4 Web Api 返回匿名类型失败并出现序列化错误的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NEt MVC 使用 Web API 返回 Razor 视图
在 MVC Web Api 4 Beta 中从 Json 中删除 Null 属性
如何使用 json 从 web.api 获取返回值到 mvc 控制器?