Grokys
Grokys

Reputation: 16536

Web API, OData, $inlinecount and testing

I previously had a Web API controller that looked like this:

    public IQueryable<ApiDesignOverview> GetList(
        string brandIds = "", 
        string categoryIds = "", 
        string query = "",
        string categoryOp = "or")

I heard that the OData NuGet package now supports the $inlinecount OData parameter, so I tried to add it using the instructions from http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/supporting-odata-query-options - I don't want to have to use OData wholesale as that would entail a large amount of re-architecturing of the app, so I went for the PageResult<T> option.

So now my controller looks like this:

    public PageResult<ApiDesignOverview> GetList(
        ODataQueryOptions<ApiDesignOverview> options,
        string brandIds = "", 
        string categoryIds = "", 
        string query = "",
        string categoryOp = "or")

My problems are now:

Really, it would be better if I could remove the ODataQueryOptions from the controller signature like before. Is this possible?

Upvotes: 4

Views: 6067

Answers (3)

emragins
emragins

Reputation: 5167

In the latest ODataController there is an AllowedQueryOptions that solves this.

public class MyOdataController : ODataController

    {
        [Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
        public IQueryable<Product> Get()
        {
            return Products.AsQueryable();
        }
    }

Upvotes: 0

user1366516
user1366516

Reputation: 111

If you do not (or cannot as in my case) want to change away from using ODataQueryOptions and PageResult, here is how you can create an ODataQueryOptions instance for unit tests:

//arrange
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/MyProject/api/Customers?$filter=CustomerID eq 1");
var controller = new CustomersController
{
    Request = request
};

ODataModelBuilder modelBuilder = new ODataConventionModelBuilder(); 
modelBuilder.EntitySet<Customer>("Customers"); 
var opts = new ODataQueryOptions<Customer>(new ODataQueryContext(modelBuilder.GetEdmModel(),typeof(Customer)), request);

//act
var result = controller.Get(opts);

//assert
Assert.AreEqual(1, result.Items.First().CustomerID);

Upvotes: 11

RaghuRam Nadiminti
RaghuRam Nadiminti

Reputation: 6793

If you prefer returning IQueryable and yet want support for $inlinecount, it is still possible to do that by modyifying QueryableAttribute.

public class InlineCountQueryableAttribute : QueryableAttribute
{
    private static MethodInfo _createPageResult =
        typeof(InlineCountQueryableAttribute)
        .GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
        .Single(m => m.Name == "CreatePageResult");

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);

        HttpRequestMessage request = actionExecutedContext.Request;
        HttpResponseMessage response = actionExecutedContext.Response;

        IQueryable result;
        if (response.IsSuccessStatusCode
            && response.TryGetContentValue<IQueryable>(out result))
        {
            long? inlineCount = request.GetInlineCount();
            if (inlineCount != null)
            {
                actionExecutedContext.Response = _createPageResult.MakeGenericMethod(result.ElementType).Invoke(
                    null, new object[] { request, request.GetInlineCount(), request.GetNextPageLink(), result }) as HttpResponseMessage;
            }
        }
    }

    internal static HttpResponseMessage CreatePageResult<T>(HttpRequestMessage request, long? count, Uri nextpageLink, IEnumerable<T> results)
    {
        return request.CreateResponse(HttpStatusCode.OK, new PageResult<T>(results, nextpageLink, count));
    }
}

Notice, that I am using reflection to create PageResult. You can instead return an object of your liking that can be formatted by the formatter that you use. An anonymous object with results and count will work too if you are using the Json formatter.

Upvotes: 8

Related Questions