If a requested resource is not found by the Service Layer returning null to the Web API controller; what is the best way to throw a HttpStatusCode.NotFound response back to the client without hard coding it in the controller, and by checking if it's null?
-
You can either return a response message with a NotFound status within the controller action method; or you can just throw an exception and have a global filter map the exception type to an appropriate response. I am not sure why checking for null would be an issue, you controller action logic has to handle a variety of conditions and map them to a response with an appropriate status code.Oppositional– Oppositional2012-09-25 23:24:38 +00:00Commented Sep 25, 2012 at 23:24
-
I have a global filter like you said. I dont want to have these null checks in every controller action.Mike Flynn– Mike Flynn2012-09-26 02:01:51 +00:00Commented Sep 26, 2012 at 2:01
2 Answers
Personally I would just do the checks in the controllers as per Oppositional's comment but what you are asking for is perfectly reasonable. Again using action filters either attached per controller (or registered globally) you could do something along these lines:
Example Model:
public class Foo
{
public string Bar { get; set; }
}
Example Controller:
public class FoosController : ApiController
{
[NullObjectActionFilter]
public Foo Get(string id)
{
// - Returns model and 200
//return new Foo() { Bar = "TEST" };
// - Returns 404
//return null;
}
}
The Filter:
public class NullObjectActionFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
object outValue = null;
actionExecutedContext.Response.TryGetContentValue<object>(out outValue);
if (outValue == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
base.OnActionExecuted(actionExecutedContext);
}
}
Comments
I agree with Mark that the ActionFilter is the way to go - small action methods are a good smell.
However, HttpActionExecutedContext.Response can be null when an exception occurs; and the NullObjectActionFilter class shown above can obscure error HTTP status codes. You're better off checking for successful exit and a successful HTTP code.
Here's an action filter I use:
/// <summary>
/// Converts <c>null</c> return values into an HTTP 404 return code.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NullResponseIs404Attribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if ((actionExecutedContext.Response != null) && actionExecutedContext.Response.IsSuccessStatusCode)
{
object contentValue = null;
actionExecutedContext.Response.TryGetContentValue<object>(out contentValue);
if (contentValue == null)
{
actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "Object not found");
}
}
}
}