[c#] Returning http status code from Web Api controller

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

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.

The answer is


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

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

I know there are several good answers here but this is what I needed so I figured I'd add this code in case anyone else needs to return whatever status code and response body they wanted in 4.7.x with 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));
    }
}

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

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

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.

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:

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." 
                });
}

For ASP.NET Web Api 2, this post from MS suggests to change the method's return type to IHttpActionResult. You can then return a built in IHttpActionResult implementation like Ok, BadRequest, etc (see here) or return your own implementation.

For your code, it could be done like:

public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
{
    var user = new DataEntities().Users.First(p => p.Id == userId);
    if (user.LastModified <= lastModifiedAtClient)
    {
        return StatusCode(HttpStatusCode.NotModified);
    }
    return Ok(user);
}

In MVC 5, things got easier:

return new StatusCodeResult(HttpStatusCode.NotModified, this);

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

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 200 then you throw an HttpResponseException in your action and pass in the HttpResponseMessage you want to send to the client.


.net core 2.2 returning 304 status code. This is using an 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); 
    }

An update to @Aliostads answer using the more moden IHttpActionResult introduced in Web API 2.

https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/action-results#ihttpactionresult

public class TryController : ApiController
{
    public IHttpActionResult GetUser(int userId, DateTime lastModifiedAtClient)
    {
        var user = new DataEntities().Users.First(p => p.Id == userId);
        if (user.LastModified <= lastModifiedAtClient)
        {
            return StatusCode(HttpStatusCode.NotModified);
            // If you would like to return a Http Status code with any object instead:
            // return Content(HttpStatusCode.InternalServerError, "My Message");
        }
        return Ok(user);
    }
}

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.

    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.

The MVC framework should still serialize and return your object.

NOTE

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


Try this :

return new ContentResult() { 
    StatusCode = 404, 
    Content = "Not found" 
};

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

Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to asp.net-web-api

Entity Framework Core: A second operation started on this context before a previous operation completed FromBody string parameter is giving null How to read request body in an asp.net core webapi controller? JWT authentication for ASP.NET Web API Token based authentication in Web API without any user interface Web API optional parameters How do I get the raw request body from the Request.Content object using .net 4 api endpoint How to use a client certificate to authenticate and authorize in a Web API HTTP 415 unsupported media type error when calling Web API 2 endpoint The CodeDom provider type "Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider" could not be located

Examples related to httpresponse

Return content with IHttpActionResult for non-OK response Why should I use IHttpActionResult instead of HttpResponseMessage? download csv file from web api in angular js Proper way to return JSON using node or Express Writing MemoryStream to Response Object Returning http status code from Web Api controller Difference between Pragma and Cache-Control headers? How to Use Content-disposition for force a file to download to the hard drive? Return HTTP status code 201 in flask How to get HTTP Response Code using Selenium WebDriver

Examples related to http-status-codes

Laravel - Return json along with http status code Spring: return @ResponseBody "ResponseEntity<List<JSONObject>>" HTTP status code 0 - Error Domain=NSURLErrorDomain? 400 vs 422 response to POST of data Python Request Post with param data HTTP Get with 204 No Content: Is that normal Throw HttpResponseException or return Request.CreateErrorResponse? Returning http status code from Web Api controller How to specify HTTP error code? How to get HTTP response code for a URL in Java?

Examples related to http-status-code-415

How can I get the status code from an http error in Axios? Curl to return http status code along with the response Job for httpd.service failed because the control process exited with error code. See "systemctl status httpd.service" and "journalctl -xe" for details How to deal with http status codes other than 200 in Angular 2 HTTP 415 unsupported media type error when calling Web API 2 endpoint AngularJS POST Fails: Response for preflight has invalid HTTP status code 404 Laravel - Return json along with http status code Swift Alamofire: How to get the HTTP response status code Spring Boot Rest Controller how to return different HTTP status codes? Http 415 Unsupported Media type error with JSON