使用Web API返回匿名类型

87

在使用MVC时,返回临时JSON很容易。

return Json(new { Message = "Hello"});

我正在寻找使用新的Web API 实现这个功能。

public HttpResponseMessage<object> Test()
{    
   return new HttpResponseMessage<object>(new { Message = "Hello" }, HttpStatusCode.OK);
}

这会抛出异常,因为 DataContractJsonSerializer 无法处理匿名类型。

我已经用基于 Json.NetJsonNetFormatter 替换了它。 如果我使用以下内容,则可以正常工作:

 public object Test()
 {
    return new { Message = "Hello" };
 }

但是如果我不返回 HttpResponseMessage,我觉得使用Web API 没有意义,最好还是坚持使用原始的MVC。如果我尝试使用:

public HttpResponseMessage<object> Test()
{
   return new HttpResponseMessage<object>(new { Message = "Hello" }, HttpStatusCode.OK);
}

它将整个HttpResponseMessage序列化。

有人能指导我如何在HttpResponseMessage中返回匿名类型吗?

11个回答

90
这在Beta版本中无法工作,但在最新的代码片段(从http://aspnetwebstack.codeplex.com构建)中可以。因此,在RC中很可能会使用这种方法。 你可以这样做:
public HttpResponseMessage Get()
{
    return this.Request.CreateResponse(
        HttpStatusCode.OK,
        new { Message = "Hello", Value = 123 });
}

16
重要提示:仅默认的JSON序列化器可以处理匿名对象的序列化。默认的XML序列化器会报错,因此请确保如果您返回匿名对象,您的客户端知道在标头中发送accept:application/json。像Chrome这样的浏览器通常默认请求XML,所以提前告知一下。 - Despertar

24

虽然这个答案来得有点晚,但是今天看起来 WebApi 2 已经发布了,现在做你想要的事情更加容易了,你只需要这样做:

```csharp // 这里是示例代码 public IHttpActionResult MyAction() { // 在此处添加您的代码... return Ok(); } ```

public object Message()
{
    return new { Message = "hello" };
}

沿着管道,它将根据客户端的偏好(即Accept头)进行序列化为xmljson。希望这可以帮助所有遇到此问题的人。


@doker,你使用的是哪个版本的WebApi?我刚刚从我的控制器中使用VS 2015和WebApi2粘贴了那段代码。 - Luiso
5.2.3,最终我移除了XML格式化程序,因为大多数返回的对象无法序列化为XML。 - jjaskulowski
在您的情况下,当您尝试执行我建议的操作时会发生什么?您是否会收到一个“异常”? - Luiso

12

在Web API 2中,你可以使用新的IHttpActionResult替代HttpResponseMessage来返回一个简单的Json对象(类似于MVC)。

public IHttpActionResult GetJson()
    {
       return Json(new { Message = "Hello"});
    }

4
最适合我的答案。我需要一种从Web API Action返回简洁的JSON,而不会在其他地方/程序集中产生额外的东西。这个方法非常好用!谢谢。 - Alexey Matveev

7
您可以使用JsonObject来实现这个功能:
dynamic json = new JsonObject();
json.Message = "Hello";
json.Value = 123;

return new HttpResponseMessage<JsonObject>(json);

5
您可以使用一个ExpandoObject。(添加using System.Dynamic;)
[Route("api/message")]
[HttpGet]
public object Message()
{
    dynamic expando = new ExpandoObject();
    expando.message = "Hello";
    expando.message2 = "World";
    return expando;
}

3
public IEnumerable<object> GetList()
{
    using (var context = new  DBContext())
    {
        return context.SPersonal.Select(m =>
            new  
            {
                FirstName= m.FirstName ,
                LastName = m.LastName
            }).Take(5).ToList();               
        }
    }
}

3
你可以尝试以下方法:
var request = new HttpRequestMessage(HttpMethod.Post, "http://leojh.com");
var requestModel = new {User = "User", Password = "Password"};
request.Content = new ObjectContent(typeof(object), requestModel, new JsonMediaTypeFormatter());

3

2
如果您使用泛型,就可以使此功能正常工作,因为它将为您的匿名类型提供一个“类型”。然后,您可以将序列化程序绑定到该类型。
public HttpResponseMessage<T> MakeResponse(T object, HttpStatusCode code)
{
    return new HttpResponseMessage<T>(object, code);
}

如果您的类上没有 DataContractDataMebmer 属性,它将会回退到序列化所有公共属性,这应该正好符合您的要求。
(今天稍晚些我才能有机会测试,如果有什么问题,请告诉我。)

0

你可以将动态对象封装在返回对象中,例如

public class GenericResponse : BaseResponse
{
    public dynamic Data { get; set; }
}

然后在WebAPI中,做如下操作:

[Route("api/MethodReturingDynamicData")]
[HttpPost]
public HttpResponseMessage MethodReturingDynamicData(RequestDTO request)
{
    HttpResponseMessage response;
    try
    {
        GenericResponse result = new GenericResponse();
        dynamic data = new ExpandoObject();
        data.Name = "Subodh";

        result.Data = data;// OR assign any dynamic data here;// 

        response = Request.CreateResponse<dynamic>(HttpStatusCode.OK, result);
    }
    catch (Exception ex)
    {
        ApplicationLogger.LogCompleteException(ex, "GetAllListMetadataForApp", "Post");
        HttpError myCustomError = new HttpError(ex.Message) { { "IsSuccess", false } };
        return Request.CreateErrorResponse(HttpStatusCode.OK, myCustomError);
    }
    return response;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接