我刚刚开始使用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的响应主体;字符集= UTF-8' 。
内部异常:
类型'<> f__AnonymousType1`3 [System.String,System.String,System.String]'无法序列化。请考虑使用DataContractAttribute属性对其进行标记,并使用DataMemberAttribute属性标记要序列化的所有成员。如果类型是集合,请考虑使用CollectionDataContractAttribute对其进行标记。有关其他受支持的类型,请参阅Microsoft .NET Framework文档。
我不了解从API控制器返回匿名类型?
答案 0 :(得分:31)
如果你看一下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);
答案 1 :(得分:3)
您还可以使用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(也可以在stackoverflow上找到:https://stackoverflow.com/a/12492552/1138266)。
答案 2 :(得分:0)
我发现API不喜欢返回原始列表。相反,我必须创建一个对象,并将对象的值设置为我的列表;看到第一个返回声明。
示例:
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 { });
}
}
答案 3 :(得分:0)
我遇到了类似的问题,解决方法是向其中添加一个代码段
Global.asax.cs
个文件。
要添加的代码段如下:
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);
}