Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp.Net Web Api - Returning 404 for IEnumerable<T> Get When null

I am creating an API using the release version of Asp.Net Web Api. I am trying to pass back the correct response code (404) if no results are found.

First Get Version (throws multiple enumeration error):

public IEnumerable<MyObjectType> Get(int id, string format)
{
    var db = new DbEntities();

    var result = db.pr_ApiSelectMyObjectType(store, id, format).AsEnumerable();
    if (result.Any())
    {
        return result;
    }
    var response = new HttpResponseMessage(HttpStatusCode.NotFound) 
        { Content = new StringContent("Unable to find any results") };
    throw new HttpResponseException(response);
}

Second Get Version (result is never null, so it always returns 200):

public IEnumerable<MyObject> Get(int id, string format)
{
    var db = new DbEntities();

    var result = db.pr_ApiSelectMyObjectType(store, id, format);
    if (result == null)
    {
        var response = new HttpResponseMessage(HttpStatusCode.NoContent) 
            { Content = new StringContent("Unable to find any results") };
        throw new HttpResponseException(response);
    }
    return result.AsEnumerable();
}

How do I pass back a 404 if no results are found? I know I could use a list, but I have a custom csv media type formatter that only works with IEnumerable types, so I would prefer to stick with that.

like image 886
Luke Jenkins Avatar asked Oct 02 '12 16:10

Luke Jenkins


2 Answers

Better approach is to catch null at action filter level, define an action filter with global scope, and throw exception 404 from this:

public class NullFilter : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        var response = actionExecutedContext.Response;

        object responseValue;
        bool hasContent = response.TryGetContentValue(out responseValue);

        if (!hasContent)
            throw new HttpResponseException(HttpStatusCode.NotFound);
    }
}

With this way, you don't need to use Any in your action, code would be simpler:

public IEnumerable<MyObjectType> Get(int id, string format)
{
    using (db = new DbEntities())
    {
       return db.pr_ApiSelectMyObjectType(store, id, format)
                .AsEnumerable();
    }
}
like image 55
cuongle Avatar answered Nov 12 '22 06:11

cuongle


It's probably simplest to just convert the results to a list, which can obviously be enumerated multiple times:

var result = db.pr_ApiSelectMyObjectType(store, id, format).ToList();
if (!result.Any())
{
    ...
}

Of course that means materializing the whole query... but presumably you'd end up doing that anyway at some point.

like image 5
Jon Skeet Avatar answered Nov 12 '22 04:11

Jon Skeet