我试图返回一个状态代码304未修改的web api控制器中的GET方法。

我成功的唯一方法是这样的:

public class TryController : ApiController
{
    public User GetUser(int userId, DateTime lastModifiedAtClient)
    {
        var user = new DataEntities().Users.First(p => p.Id == userId);
        if (user.LastModified <= lastModifiedAtClient)
        {
             throw new HttpResponseException(HttpStatusCode.NotModified);
        }
        return user;
    }
}

这里的问题是,它不是一个异常,它只是没有修改,所以客户端缓存是OK的。 我还希望返回类型是一个用户(所有的web api示例显示与GET)不返回HttpResponseMessage或类似的东西。


当前回答

我不喜欢改变我的签名来使用HttpCreateResponse类型,所以我提出了一个扩展的解决方案来隐藏它。

public class HttpActionResult : IHttpActionResult
{
    public HttpActionResult(HttpRequestMessage request) : this(request, HttpStatusCode.OK)
    {
    }

    public HttpActionResult(HttpRequestMessage request, HttpStatusCode code) : this(request, code, null)
    {
    }

    public HttpActionResult(HttpRequestMessage request, HttpStatusCode code, object result)
    {
        Request = request;
        Code = code;
        Result = result;
    }

    public HttpRequestMessage Request { get; }
    public HttpStatusCode Code { get; }
    public object Result { get; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(Request.CreateResponse(Code, Result));
    }
}

然后你可以添加一个方法到你的ApiController(或者更好的是你的基本控制器),像这样:

protected IHttpActionResult CustomResult(HttpStatusCode code, object data) 
{
    // Request here is the property on the controller.
    return new HttpActionResult(Request, code, data);
}

然后你可以像任何内置方法一样返回它:

[HttpPost]
public IHttpActionResult Post(Model model)
{
    return model.Id == 1 ?
                Ok() :
                CustomResult(HttpStatusCode.NotAcceptable, new { 
                    data = model, 
                    error = "The ID needs to be 1." 
                });
}

其他回答

我不知道答案所以问ASP。NET团队。

因此,诀窍是将签名更改为HttpResponseMessage并使用Request.CreateResponse。

[ResponseType(typeof(User))]
public HttpResponseMessage GetUser(HttpRequestMessage request, int userId, DateTime lastModifiedAtClient)
{
    var user = new DataEntities().Users.First(p => p.Id == userId);
    if (user.LastModified <= lastModifiedAtClient)
    {
         return new HttpResponseMessage(HttpStatusCode.NotModified);
    }
    return request.CreateResponse(HttpStatusCode.OK, user);
}

我知道这里有几个很好的答案,但这是我需要的,所以我想我应该添加这个代码,以防任何人需要返回任何状态代码和响应体,他们想在4.7。x与webAPI。

public class DuplicateResponseResult<TResponse> : IHttpActionResult
{
    private TResponse _response;
    private HttpStatusCode _statusCode;
    private HttpRequestMessage _httpRequestMessage;
    public DuplicateResponseResult(HttpRequestMessage httpRequestMessage, TResponse response, HttpStatusCode statusCode)
    {
        _httpRequestMessage = httpRequestMessage;
        _response = response;
        _statusCode = statusCode;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(_statusCode);
        return Task.FromResult(_httpRequestMessage.CreateResponse(_statusCode, _response));
    }
}

如果您希望将操作签名保留为返回User,还可以执行以下操作:

public User GetUser(int userId, DateTime lastModifiedAtClient) 

如果你想返回200以外的值,那么你在你的动作中抛出一个HttpResponseException,并传递你想要发送给客户端的HttpResponseMessage。

我不喜欢改变我的签名来使用HttpCreateResponse类型,所以我提出了一个扩展的解决方案来隐藏它。

public class HttpActionResult : IHttpActionResult
{
    public HttpActionResult(HttpRequestMessage request) : this(request, HttpStatusCode.OK)
    {
    }

    public HttpActionResult(HttpRequestMessage request, HttpStatusCode code) : this(request, code, null)
    {
    }

    public HttpActionResult(HttpRequestMessage request, HttpStatusCode code, object result)
    {
        Request = request;
        Code = code;
        Result = result;
    }

    public HttpRequestMessage Request { get; }
    public HttpStatusCode Code { get; }
    public object Result { get; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(Request.CreateResponse(Code, Result));
    }
}

然后你可以添加一个方法到你的ApiController(或者更好的是你的基本控制器),像这样:

protected IHttpActionResult CustomResult(HttpStatusCode code, object data) 
{
    // Request here is the property on the controller.
    return new HttpActionResult(Request, code, data);
}

然后你可以像任何内置方法一样返回它:

[HttpPost]
public IHttpActionResult Post(Model model)
{
    return model.Id == 1 ?
                Ok() :
                CustomResult(HttpStatusCode.NotAcceptable, new { 
                    data = model, 
                    error = "The ID needs to be 1." 
                });
}

如果你需要返回一个IHttpActionResult并且想要返回错误代码和消息,使用:

return ResponseMessage(Request.CreateErrorResponse(HttpStatusCode.NotModified, "Error message here"));