Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Web API and Status Code For Null Response

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?

like image 393
Mike Flynn Avatar asked Sep 25 '12 23:09

Mike Flynn


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

    }
}
like image 53
Mark Jones Avatar answered Oct 05 '22 10:10

Mark Jones


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

}
like image 40
crimbo Avatar answered Oct 05 '22 11:10

crimbo