18

我刚刚开始使用 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 控制器返回匿名类型,我不明白什么?

4

4 回答 4

33

如果您查看 Fiddler(此处的示例我使用 Firefox)

在此处输入图像描述

默认情况下,来自浏览器的请求将接受application/xml,而不是 application/json

但是,您可以通过添加一个标头从 Fiddler创建虚假请求:

Accept: application/json

它会工作

链接

XML 序列化程序不支持匿名类型或 JObject 实例。如果您将这些功能用于 JSON 数据,则应从管道中删除 XML 格式化程序,如本文后面所述。

如何删除XmlFormatter

  var configuration = GlobalConfiguration.Configuration;
  configuration.Formatters.Remove(configuration.Formatters.XmlFormatter);
于 2013-02-19T16:29:17.687 回答
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 )。

于 2013-12-13T13:51:09.037 回答
0

我发现 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 { });
    }
}
于 2016-12-01T04:43:51.687 回答
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);
    }
于 2019-09-21T11:50:54.323 回答