从MVC 4 Web Api返回匿名类型失败,出现序列化错误

时间:2022-11-07 18:53:51

I'm just getting started with MVC 4 Web API and I seem to be misunderstanding how it works.

我刚刚开始使用MVC 4 Web API,我似乎误解了它是如何工作的。

Before Web API I had a simple MVC action method like this:

在Web API之前,我有一个像这样的简单MVC操作方法:

public JsonResult User()
{
    return Json(new
    {
        firstName = "Joe",
        lastName = "Jacobs",
        email = "joe.jacobs@gmail.com"
    });
}

That would work fine. In the new web API controller I am trying to do something similar.

那会很好。在新的Web API控制器中,我正在尝试做类似的事情。

public object User()
{
    return new
    {
        firstName = "Joe",
        lastName = "Jacobs",
        email = "joe.jacobs@gmail.com"
    }
}

This fails with a serialization error:

这会因序列化错误而失败:

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.

'ObjectContent`1'类型无法序列化内容类型'application / xml的响应主体;字符集= UTF-8' 。

Inner exception:

内部异常:

Type '<>f__AnonymousType1`3[System.String,System.String,System.String]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.

类型'<> f__AnonymousType1`3 [System.String,System.String,System.String]'无法序列化。请考虑使用DataContractAttribute属性对其进行标记,并使用DataMemberAttribute属性标记要序列化的所有成员。如果类型是集合,请考虑使用CollectionDataContractAttribute对其进行标记。有关其他受支持的类型,请参阅Microsoft .NET Framework文档。

What am I not understanding about returning anonymous type from the API controller?

关于从API控制器返回匿名类型我不明白的是什么?

3 个解决方案

#1


30  

If you look at the Fiddler (sample in here I use Firefox)

如果你看一下Fiddler(我在这里使用Firefox的示例)

从MVC 4 Web Api返回匿名类型失败,出现序列化错误

By default, request from browser will accepts application/xml, not application/json

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

But, you can create fake request from Fiddler by adding one header:

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

Accept: application/json

It will work

它会工作

From the link:

从链接:

The XML serializer does not support anonymous types or JObject instances. If you use these features for your JSON data, you should remove the XML formatter from the pipeline, as described later in this article.

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

How to remove XmlFormatter:

如何删除XmlFormatter:

  var configuration = GlobalConfiguration.Configuration;
  configuration.Formatters.Remove(configuration.Formatters.XmlFormatter);

#2


3  

You could also use the JsonMediaTypeFormatter so you do not need the JSONObject and related classes. Then you can return a dynamic type in your controller class.

您还可以使用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
        };
    }
}

If you also want to support Jsonp you can inherit the JsonMediaTypeFormatter and create you own JsonpMediaTypeFormatter (which also can be found on *: https://*.com/a/12492552/1138266).

如果您还想支持Jsonp,您可以继承JsonMediaTypeFormatter并创建自己的JsonpMediaTypeFormatter(也可以在*上找到:https://*.com/a/12492552/1138266)。

#3


0  

I found that the API didn't like returning a raw list. Instead, I had to create an object, and set the value of the object as my list; see the first return statement.

我发现API不喜欢返回原始列表。相反,我必须创建一个对象,并将对象的值设置为我的列表;看到第一个返回声明。

Example:

例:

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 { });
    }
}

#1


30  

If you look at the Fiddler (sample in here I use Firefox)

如果你看一下Fiddler(我在这里使用Firefox的示例)

从MVC 4 Web Api返回匿名类型失败,出现序列化错误

By default, request from browser will accepts application/xml, not application/json

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

But, you can create fake request from Fiddler by adding one header:

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

Accept: application/json

It will work

它会工作

From the link:

从链接:

The XML serializer does not support anonymous types or JObject instances. If you use these features for your JSON data, you should remove the XML formatter from the pipeline, as described later in this article.

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

How to remove XmlFormatter:

如何删除XmlFormatter:

  var configuration = GlobalConfiguration.Configuration;
  configuration.Formatters.Remove(configuration.Formatters.XmlFormatter);

#2


3  

You could also use the JsonMediaTypeFormatter so you do not need the JSONObject and related classes. Then you can return a dynamic type in your controller class.

您还可以使用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
        };
    }
}

If you also want to support Jsonp you can inherit the JsonMediaTypeFormatter and create you own JsonpMediaTypeFormatter (which also can be found on *: https://*.com/a/12492552/1138266).

如果您还想支持Jsonp,您可以继承JsonMediaTypeFormatter并创建自己的JsonpMediaTypeFormatter(也可以在*上找到:https://*.com/a/12492552/1138266)。

#3


0  

I found that the API didn't like returning a raw list. Instead, I had to create an object, and set the value of the object as my list; see the first return statement.

我发现API不喜欢返回原始列表。相反,我必须创建一个对象,并将对象的值设置为我的列表;看到第一个返回声明。

Example:

例:

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 { });
    }
}