Mike Flynn
Mike Flynn

Reputation: 24325

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?

Upvotes: 8

Views: 8940

Answers (2)

crimbo
crimbo

Reputation: 11271

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

}

Upvotes: 11

Mark Jones
Mark Jones

Reputation: 12194

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

    }
}

Upvotes: 15

Related Questions