C# 从 Web Api 控制器返回 http 状态代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10655350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 14:41:21  来源:igfitidea点击:

Returning http status code from Web Api controller

c#asp.net-web-apihttpresponsehttp-status-codes

提问by ozba

I'm trying to return a status code of 304 not modified for a GET method in a web api controller.

我正在尝试为 Web api 控制器中的 GET 方法返回未修改的 304 状态代码。

The only way I succeeded was something like this:

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

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;
    }
}

The problem here is that it's not an exception, It's just not modified so the client cache is OK. I also want the return type to be a User (as all the web api examples shows with GET) not return HttpResponseMessage or something like this.

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

采纳答案by Aliostad

I did not know the answer so asked the ASP.NET team here.

我不知道答案,所以在这里询问 ASP.NET 团队。

So the trick is to change the signature to HttpResponseMessageand use Request.CreateResponse.

所以诀窍是将签名更改为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);
}

回答by Henrik Frystyk Nielsen

You can also do the following if you want to preserve the action signature as returning User:

如果要将操作签名保留为返回用户,还可以执行以下操作:

public User GetUser(int userId, DateTime lastModifiedAtClient) 

If you want to return something other than 200then you throw an HttpResponseExceptionin your action and pass in the HttpResponseMessageyou want to send to the client.

如果您想返回除此之外的其他内容,200HttpResponseException在您的操作中抛出一个并传递HttpResponseMessage您要发送给客户端的内容。

回答by Luke Puplett

Change the GetXxx API method to return HttpResponseMessage and then return a typed version for the full response and the untyped version for the NotModified response.

更改 GetXxx API 方法以返回 HttpResponseMessage,然后返回完整响应的类型化版本和 NotModified 响应的非类型化版本。

    public HttpResponseMessage GetComputingDevice(string id)
    {
        ComputingDevice computingDevice =
            _db.Devices.OfType<ComputingDevice>()
                .SingleOrDefault(c => c.AssetId == id);

        if (computingDevice == null)
        {
            return this.Request.CreateResponse(HttpStatusCode.NotFound);
        }

        if (this.Request.ClientHasStaleData(computingDevice.ModifiedDate))
        {
            return this.Request.CreateResponse<ComputingDevice>(
                HttpStatusCode.OK, computingDevice);
        }
        else
        {
            return this.Request.CreateResponse(HttpStatusCode.NotModified);
        }
    }

*The ClientHasStale data is my extension for checking ETag and IfModifiedSince headers.

*ClientHasStale 数据是我用于检查 ETag 和 IfModifiedSince 标头的扩展。

The MVC framework should still serialize and return your object.

MVC 框架仍应序列化并返回您的对象。

NOTE

笔记

I think the generic version is being removed in some future version of the Web API.

我认为在 Web API 的未来版本中将删除通用版本。

回答by Jon Bates

In MVC 5, things got easier:

在 MVC 5 中,事情变得更容易了:

return new StatusCodeResult(HttpStatusCode.NotModified, this);

回答by Jo Smo

public HttpResponseMessage Post(Article article)
{
    HttpResponseMessage response = Request.CreateResponse<Article>(HttpStatusCode.Created, article);

    string uriToTheCreatedItem = Url.Route(null, new { id = article.Id });
    response.Headers.Location = new Uri(Request.RequestUri, uriToTheCreatedItem);

    return response;
}

回答by Chris Halcrow

If you need to return an IHttpActionResult and want to return the error code plus a message, use:

如果您需要返回 IHttpActionResult 并希望返回错误代码和一条消息,请使用:

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

回答by Bora Ayd?n

Another option:

另外一个选项:

return new NotModified();


public class NotModified : IHttpActionResult
{
    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(HttpStatusCode.NotModified);
        return Task.FromResult(response);
    }
}

回答by krillgar

I don't like having to change my signature to use the HttpCreateResponse type, so I came up with a little bit of an extended solution to hide that.

我不喜欢必须更改我的签名来使用 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));
    }
}

You can then add a method to your ApiController (or better your base controller) like this:

然后,您可以向您的 ApiController(或更好的基本控制器)添加一个方法,如下所示:

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

Then you can return it just like any of the built in methods:

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

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

回答by Kenneth Garza

I hate bumping old articles but this is the first result for this in google search and I had a heck of a time with this problem (even with the support of you guys). So here goes nothing...

我讨厌撞旧文章,但这是谷歌搜索中的第一个结果,我在这个问题上遇到了很多时间(即使有你们的支持)。所以这里什么都没有......

Hopefully my solution will help those that also was confused.

希望我的解决方案能帮助那些也感到困惑的人。

namespace MyApplication.WebAPI.Controllers
{
    public class BaseController : ApiController
    {
        public T SendResponse<T>(T response, HttpStatusCode statusCode = HttpStatusCode.OK)
        {
            if (statusCode != HttpStatusCode.OK)
            {
                // leave it up to microsoft to make this way more complicated than it needs to be
                // seriously i used to be able to just set the status and leave it at that but nooo... now 
                // i need to throw an exception 
                var badResponse =
                    new HttpResponseMessage(statusCode)
                    {
                        Content =  new StringContent(JsonConvert.SerializeObject(response), Encoding.UTF8, "application/json")
                    };

                throw new HttpResponseException(badResponse);
            }
            return response;
        }
    }
}

and then just inherit from the BaseController

然后从 BaseController 继承

[RoutePrefix("api/devicemanagement")]
public class DeviceManagementController : BaseController
{...

and then using it

然后使用它

[HttpGet]
[Route("device/search/{property}/{value}")]
public SearchForDeviceResponse SearchForDevice(string property, string value)
{
    //todo: limit search property here?
    var response = new SearchForDeviceResponse();

    var results = _deviceManagementBusiness.SearchForDevices(property, value);

    response.Success = true;
    response.Data = results;

    var statusCode = results == null || !results.Any() ? HttpStatusCode.NoContent : HttpStatusCode.OK;

    return SendResponse(response, statusCode);
}

回答by Ives.me

.net core 2.2 returning 304 status code. This is using an ApiController.

.net core 2.2 返回 304 状态代码。这是使用 ApiController。

    [HttpGet]
    public ActionResult<YOUROBJECT> Get()
    {
        return StatusCode(304);
    }

Optionally you can return an object with the response

(可选)您可以返回一个带有响应的对象

    [HttpGet]
    public ActionResult<YOUROBJECT> Get()
    {
        return StatusCode(304, YOUROBJECT); 
    }