Problem
In a web api controller, I’m trying to return a 304 status code that hasn’t been modified for a GET method.
I could only succeed if I did 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 issue is that it is not an error; it is simply not updated, therefore the client cache is unaffected. I also want the response type to be User (as seen in all of the web api examples with GET), not HttpResponseMessage or something similar.
Asked by ozba
Solution #1
I was stumped and turned to the ASP.NET team for help.
The trick is to use Request and alter the signature to HttpResponseMessage. 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);
}
Answered by Aliostad
Solution #2
If you wish to keep the action signature as a returning User, you can do the following:
public User GetUser(int userId, DateTime lastModifiedAtClient)
Throw a HttpResponseException in your action and pass in the HttpResponseMessage you wish to deliver to the client if you want to return something other than 200.
Answered by Henrik Frystyk Nielsen
Solution #3
Change the GetXxx API method to return HttpResponseMessage, then return both a typed and untyped version of the complete response and 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);
}
}
*My extension for inspecting ETag and IfModifiedSince headers is ClientHasStale data.
Your object should still be serialized and returned by the MVC framework.
NOTE
In a future release of the Web API, I believe the generic version will be deleted.
Answered by Luke Puplett
Solution #4
Things got a lot easier with MVC 5:
return new StatusCodeResult(HttpStatusCode.NotModified, this);
Answered by Jon Bates
Solution #5
This post from Microsoft proposes changing the method’s return type to IHttpActionResult for ASP.NET Web Api 2. You may then either return a built-in IHttpActionResult implementation like Ok, BadRequest, or your own implementation (see here).
It could look like this in your code:
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);
}
Answered by datchung
Post is based on https://stackoverflow.com/questions/10655350/returning-http-status-code-from-web-api-controller