F#WebApi从有区别的联合返回格式正确的json

时间:2016-10-05 06:56:22

标签: f# json.net asp.net-web-api2

我想知道从WebApi中的歧视联盟的结果返回干净的json最简单的方法是什么?此用例仅用于业务逻辑,不用于http错误等 - 这些用例在管道中处理并像往常一样返回给用户(404,500等)

例如:

type ServiceResult<'a> = { Message:string; Payload:'a }

type ServiceResponse<'a> =
    | Success of ServiceResult<'a>
    | Fail of ServiceResult<string>

返回:

{
  "Case": "Fail",
  "Fields": [
    {
      "Message": "Error performing business logic, your x is not in the y.",
      "Payload": "I just couldnt do it"
    }
  ]
}

...或...

{
  "Case": "Success",
  "Fields": [
    {
      "Message": "",
      "Payload": { "FirstName": "Johnny", "LastName":"Smith" }
    }
  ]
}

我希望只返回服务结果,如:

{
  "Message": "",
  "Payload": { "FirstName": "Johnny", "LastName":"Smith" }
}

......或......

{
  "Message": "Error during operation due to spite.",
  "Payload": "I just couldnt do it"
}

我尝试过IdiomaticDuConverter: https://gist.github.com/isaacabraham/ba679f285bfd15d2f53e

但它没有用。我见过的最接近的是Microsoft.FSharpLu.Json,但它没有MediaTypeFormatter来插入管道。

我知道我可以使用Lu并创建我自己的MediaTypeFormatter,但我觉得必须有一种更简单的方法(就像我缺少的一些Json.Net选项)。

你能指出我正确的方向吗?

谢谢: - )

2 个答案:

答案 0 :(得分:3)

虽然可能存在一些极端情况,您回答的返回表示是正确的设计,但一般来说这不是一个好的HTTP API设计。 ASP.NET Web API返回HTTP响应,因此返回

的含义
{
  "Success": false,
  "Message": "Error during operation due to spite.",
  "Payload": "I just couldnt do it"
}

是该值作为200 OK响应的一部分返回。这给客户带来了额外的负担,因为他们现在不仅要处理HTTP错误(这仍然可能发生),而且还不能相信200 OK实际上意味着成功。

相反,如果出现错误,请返回the appropriate HTTP status code

这也解决了这个问题,并使您的F#代码易于编写。在Controller中,您基本上可以这样做:

member this.Get() =
    let result = // produce the result somehow...
    match result with
    | Success x -> this.Ok x :> IHttpActionResult
    | Fail msg  -> this.BadRequest msg :> IHttpActionResult

为简单起见,此示例在400 Bad Request情况下返回Fail,但如果此情况表示内部错误,则500 Internal Server Error可能更合适。

答案 1 :(得分:1)

您可以为ServiceResponse类型编写custom JSON.NET serializer,只需跳过案例标签并将序列化委托给嵌套ServiceResult

这里真正的问题是你为什么会遇到这个问题?您已经在记录中携带成功/失败状态,DU不提供任何其他信息。更重要的是,通过您拥有的设置,您可以轻松地代表看似不合适的状态:

Success <| { Success = false; Message = "necktie"; Payload = "bacon" }

为什么不放弃它并仅传递记录,完全避免序列化问题?