【问题标题】:Web Api: recommended way to return json stringWeb Api:返回json字符串的推荐方式
【发布时间】:2016-11-27 19:45:13
【问题描述】:

我有几个服务已经接收到必须返回给客户端的 json 字符串(不是对象)。目前,我正在显式创建 HttpResponseMessage 并将其 Content 属性设置为服务接收的 json 字符串:

var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(jsonUtilizadores, Encoding.UTF8, "application/json");
return response;

现在,有没有更好的方法来使用新的IHttpActionResult?使用ContentOk 方法最终会用引号包裹json 字符串,这不是我想要的。

有什么反馈吗?

【问题讨论】:

  • 就用return Json(response);?
  • 这怎么可能这么复杂。如果 MS 可以只接受一个字符串而不用引号括起来,那就太好了……
  • 如果 return Json(response) 工作会很棒。仍在寻找适用于 DNCore 2.1 的答案 - 疯狂了一个小时,MS 没用。

标签: c# asp.net-web-api2


【解决方案1】:

创建自定义实现。该框架可通过IHttpActionResult 进行扩展。

下面创建自定义结果和扩展方法...

public static class JsonStringResultExtension {
   public static CustomJsonStringResult JsonString(this ApiController controller, string jsonContent, HttpStatusCode statusCode = HttpStatusCode.OK) {
        var result = new CustomJsonStringResult(controller.Request, statusCode, jsonContent);
        return result;
    }

    public class CustomJsonStringResult : IHttpActionResult {
        private string json;
        private HttpStatusCode statusCode;
        private HttpRequestMessage request;

        public CustomJsonStringResult(HttpRequestMessage httpRequestMessage, HttpStatusCode statusCode = HttpStatusCode.OK, string json = "") {
            this.request = httpRequestMessage;
            this.json = json;
            this.statusCode = statusCode;
        }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) {
            return Task.FromResult(Execute());
        }

        private HttpResponseMessage Execute() {
            var response = request.CreateResponse(statusCode);
            response.Content = new StringContent(json, Encoding.UTF8, "application/json");
            return response;
        }
    }
}

...然后可以应用于ApiController 派生类。大大简化了以前的调用

return this.JsonString(jsonUtilizadores); //defaults to 200 OK

或带有所需的 HTTP 状态代码

return this.JsonString(jsonUtilizadores, HttpStatusCode.BadRequest);

【讨论】:

  • 我找到的最简单的答案 - 不知道为什么这不更受欢迎。谢谢
  • 我要试试这个。为什么 MS 不能让像 ToJson 扩展这样简单的东西内置到框架中,这超出了我的理解。应该就是这么简单。为什么要一遍又一遍地重新发明轮子?
【解决方案2】:

将您的 Web Api 设置为返回 JSON 格式:

    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();
        // Force to ignore Request Content Type Header and reply only JSON
        config.Formatters.Clear();
        config.Formatters.Add(new JsonMediaTypeFormatter());

        var corsAttr = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(corsAttr);
    }

然后像这样返回响应:

        [HttpGet]
    [Route("{taskId}/list")]
    public IHttpActionResult GetTaskDocuments(string taskId)
    {
        var docs = repository.getTaskDocuments(taskId);
        if (docs != null)
        {
            return Ok(docs);
        }
        else
        {
            return Ok(new ResponseStatus() { Status = Constants.RESPONSE_FAIL, Message = repository.LastErrorMsg });
        }
    }

其中 ResponseStatus 是下一个类:

 public class ResponseStatus
    {
        public string Status { get; set; }
        public string Message { get; set; }
    }

【讨论】:

    【解决方案3】:

    将响应格式留给内容协商以符合 REST 标准,客户端应决定它想要什么格式。

    在您的 Web API 操作中,您应该只返回 Ok(your object),Web API 会查看返回它的最佳格式。

    如果您需要省略其他格式化程序,则只需按照 Nkosi 的建议删除其他 MediaTypeFormatter 对象。

    【讨论】:

      【解决方案4】:

      这是@Nkosi 翻译成 VB.Net 的答案。

      我正在构建一个 WebAPI2 后端来支持 TourOfHeroes。

      我想我有一个“重”对象并且我不想将所有属性返回到所有视图的情况。想象一下 Hero 有大约 30 列,我只需要 Heroes.component.ts 的 Id 和 Name ......

      我不想另外创建一个对象来表示每个视图,以便我可以 JSON 序列化它们...干吗?

      所以,这是@NKosi 发布的 2 个课程。不确定共享类是否必要,我只是按照@NKosi 编写的方式实现。

      Imports System.Net.Http
      Imports System.Web.Http
      Imports System.Net
      Imports System.Threading
      Imports System.Threading.Tasks
      
      Public Class JsonStringResultExtension
      
          Public Shared Function JSONString(Controller As ApiController,
                                                      Optional jsonContent As String = "",
                                                   Optional statusCode As HttpStatusCode = HttpStatusCode.OK) As CustomJsonStringResult
      
              Dim result As New CustomJsonStringResult(Controller.Request, statusCode, jsonContent)
              Return result
              End Function
      
        End Class
      
          Public Class CustomJsonStringResult
              Implements IHttpActionResult
      
          Private json As String
          Private statusCode As HttpStatusCode
          Private request As HttpRequestMessage
      
          Public Sub New(httpRequestMessage As HttpRequestMessage, Optional statusCode As HttpStatusCode = HttpStatusCode.OK, Optional json As String = "")
              Me.request = httpRequestMessage
              Me.json = json
              Me.statusCode = statusCode
          End Sub
      
          Public Function ExecuteAsync(cancellationToken As CancellationToken) As Task(Of HttpResponseMessage) Implements IHttpActionResult.ExecuteAsync
              Return Task.FromResult(Execute())
          End Function
      
          Private Function Execute() As HttpResponseMessage
              Dim response = request.CreateResponse(statusCode)
              response.Content = New StringContent(json, Encoding.UTF8, "application/json")
      
              Return response
          End Function
      
      
      End Class
      

      我还将在 webApiConfig.vb 中添加以下内容,否则您将收到无法解析 HTML 的投诉

      config.Formatters.JsonFormatter.SupportedMediaTypes.Add(New MediaTypeHeaderValue("text/html"))
              config.Formatters.JsonFormatter.SupportedMediaTypes.Add(New MediaTypeHeaderValue("application/json"))
      

      这是支持 heros.component.js 的 webAPI 控制器调用 就像@Luis Abreu 一样,我的 BO 已经在返回 JSON。我只想将格式正确的 JSON 作为字符串返回,而不是将我的 BO 映射到 API 中的另一个类,其唯一目的是对其进行序列化...

       <HttpGet>
              <Route("")>
              Public Function GetAllHeroes() As CustomJsonStringResult
      
                 'populate a list of heros however you want 
                  dim ag as  new  HeroAg()
                  Dim l As List(Of TOHbos.Hero) = ag.Items
      
      
      
                  'This should be shoved down into a reusable class...ListToJSON
                  Dim sb As New StringBuilder("")
                  Dim first As Boolean = True
                  sb.Append("[")
                  For Each h As TOHbos.Hero In l
      
                      If first = True Then
                          first = False
                      Else
                          sb.Append(", ")
                      End If
                       'decide which fields to include and generate a JSON document
                       h.decideWhichFieldsGetSerializedForThisView()
                      sb.Append(h.JSON)
                  Next
                  sb.Append("]")
      
                  Return JsonStringResultExtension.JSONString(Me, sb.ToString(), HttpStatusCode.OK)
      
              End Function
      

      我遇到的下一个问题是我从浏览器控制台中的 Angular 应用程序中收到此错误

       Http failure during parsing for localhost:4300/api/heroes
      

      使用 jsonLint.com,我发现我的 JSON 不太正确。我没有将键名放在双勾中,而是将值放在单勾中。虽然这可能是可接受的 JSON,但 jsonLint 抱怨,我猜 Angular rxjs 也是如此

      【讨论】:

      • 是否有适用于 DotNetCore 2.1 WEB API 的答案?
      猜你喜欢
      • 2019-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-21
      相关资源
      最近更新 更多