当我的oData V4方法返回SingleResult <t>并且没有找到任何内容时,我应该返回什么?

时间:2016-01-20 22:41:24

标签: asp.net odata asp.net-web-api2

我在oData V4项目中有一个返回SingleResult的控制器方法。它查询一个表,当表中有数据时,返回它应该返回的表。但是,当应用程序是新的并且表格为空时,它会给出一个不起眼的错误:

"'SingleResult`1' cannot be serialized using the ODataMediaTypeFormatter."

我的方法如下所示:

    [EnableQuery]
    public virtual SingleResult<LoggerEntry> Get([FromODataUri] int key)
    {
        using (var gateway = this.Gateway.GetChild())
        {
            var model = gateway.GetLoggerEntry(key);
            // TODO: Check for null and tell the client NotFound
            return SingleResult.Create((new List<LoggerEntry>(){ model }).AsQueryable());
        }
    }

因为我使用的是SingleResult,所以我无法return NotFound();。我试图使用一个空列表,但这给了我同样的错误。在这种情况下,我无法找到返回的示例或文档。我该怎么回事。

2 个答案:

答案 0 :(得分:4)

保留原始代码并尝试使用ODataNullValueMessageHandler

        configuration.MapODataServiceRoute(
            "odata", 
            "odata", 
            GetEdmModel(configuration),
            defaultHandler: HttpClientFactory.CreatePipeline(innerHandler: new HttpControllerDispatcher(configuration), handlers: new[] { new ODataNullValueMessageHandler()}));

答案 1 :(得分:0)

如您所知,我们可能想向用户报告许多可能不同的响应,而200和404还不够。

我们可以添加处理程序或过滤器来解释异常,并返回其他应答中所述的更有意义的http响应代码,但是当您要显式返回其他HTTP响应代码(例如400-BadRequest或404-未找到。

  

如果您发现自己抛出了任意异常,以便另一个进程可以解释该消息并将其重新格式化为可用的响应或更有意义的东西,这就是我们首先抛出异常的原因,那么您应该评估异常是否为首先表达响应的最佳机制。

通过将您的网络方法的响应类型更改为IHttpActionResult,我们可以通过出色的代码响应来表现更多。在大多数情况下,此更改将与您的Web API运行时的其余部分兼容。

现在,从您的方法中,我们可以轻松地表达不同的常见响应,如果您的控制器类继承自ApiController,那么以下示例应该可以工作:

[EnableQuery]
public virtual IHttpActionResult Get([FromODataUri] int key)
{
    // HACK: Example of a specific case that we want to disallow
    if(key <= 0)
        return BadRequest("Keys must be positive values");

    using (var gateway = this.Gateway.GetChild())
    {
        var model = gateway.GetLoggerEntry(key);

        // Check for null and tell the client NotFound
        if(model == null)
            return NotFound();

        // NOTE: SingleResult does not implement IHttpActionResult and the ApiController 
        // does not provide a simple helper for SingleResult, so I've added one for you.
        return Single((new List<LoggerEntry>(){ model }).AsQueryable());
    }
}

/// <summary>
/// Helper to Create a SingleResult (200 OK) Response as IHttpActionResult
/// </summary>
/// <typeparam name="T">The type of item in query.</typeparam>
/// <param name="itemQuery">The query to get the item.</param>
/// <returns>A System.Web.Http.Results.JsonResult`1 with the specified values.</returns>
protected IHttpActionResult Single<T>(IQueryable<T> itemQuery)
{
    return Content(HttpStatusCode.OK, System.Web.Http.SingleResult.Create(itemQuery));
}
  

注意:许多过渡到使用IHttpActionResult的api开发人员可能会选择使用protected internal virtual OkNegotiatedContentResult<T> Ok<T>(T content);方法来生成IHttpActionResult响应,但是即使您的查询结果只有一行,它也会始终返回一个数组,这就是为什么在我的回复中包括了Single助手。

在这种情况下,Single<T>帮助程序方法演示了如何轻松地自定义控制器类中的响应处理程序以及如何完全控制输出,包括如何指定可能有助于编写代码的不同Status响应。对其他团队成员更具表达力和可读性。