Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web API 2: OData 4: Single Controller with Common Repository does not work with IQueryable when passed to the OK method

I have tons of entities (created via Database first designer) within my EDMX file. I don't want to create a separate Web Api 2 controller for each entity that I want to expose to my Odata service. That is why my task is to create a SINGLE Web Api 2 OData 4 Controller to return data for any entity that is part of my EntityFramework EDMX file.

I created a GetData(db, "entity name") method to return IQueryable for any entity from the repository dynamically.

My IQueryable< DimUser > Get() method works, but IQueryable Get() (without hard-coded dimUser) does not. The OK method does not do anything and returns me blank result.

I am very frustrated as I don't get any error, and I don't seem to figure out the inner workings of the Ok method.

Question

Is is possible to use IQueryable Get() method instead of IQueryable Get() within my GenericController class?


Generic Controller Code

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.ModelBinding;
using System.Web.OData;
using System.Web.OData.Extensions;
using System.Web.OData.Query;
using System.Web.OData.Routing;


using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Library;

using MyDataAccess;
using System.Reflection;

namespace DataService.Controllers
{
    public class GenericController : ODataController
    {
        private Entities db = new MyDataAccess.Entities();

        //HARD-CODING ENTITY NAME RETURNS RESULT, 
        //(but it is not acceptable solution)

        //[EnableQuery(PageSize = 10)]
        //public IQueryable<DimUser> Get()
        //{
        //    return db.DimUsers;
        //}

        //THIS ONE DOES NOT WORK
        [EnableQuery(PageSize = 10)]
        public IQueryable Get()
        {
            var data = GetData(db,"DimUsers");
            return data;
        }

        // Define other methods and classes here
        public IQueryable GetData(MyDataAccess.Entities db, string EntityName)
        {
            foreach (PropertyInfo property in db.GetType().GetProperties())
            {
    var name = property.Name;
    if (name == EntityName)
    {
        var v = property.GetValue(db);
        return (IQueryable)v;
    }
            }
            return null;
        }

    }
}

Register method

public static void Register(HttpConfiguration config)
{
    IList<IODataRoutingConvention> routingConventions = ODataRoutingConventions.CreateDefault();
    routingConventions.Insert(0, new CustomControllerRoutingConvention());
    config.MapODataServiceRoute("EntityDataRoute", "GetEntityData", GenerateEdmModel_Entities(), 
        new DefaultODataPathHandler(), routingConventions);

}

CustomControllerRoutingConvention class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web;
using System.Web.OData.Routing;
using System.Web.OData.Routing.Conventions;

namespace DataService
{
    public class CustomControllerRoutingConvention : IODataRoutingConvention
    {
        public string SelectAction(ODataPath odataPath, System.Web.Http.Controllers.HttpControllerContext controllerContext, ILookup<string, System.Web.Http.Controllers.HttpActionDescriptor> actionMap)
        {
            return null;
        }

        public string SelectController(ODataPath odataPath, HttpRequestMessage request)
        {
            return "Generic";
        }
    }
}
like image 410
Syed B Avatar asked Oct 30 '22 21:10

Syed B


1 Answers

The solution is to creates an instance of the result with specific result type. see below

   [EnableQuery(PageSize = 10)]
    public IQueryable Get()
    {
        var data = GetData(db,"DimUsers");
        return Okay(data, data.GetType());
    }




    protected IHttpActionResult Okay(object content, Type type)
    {
        var resultType = typeof(OkNegotiatedContentResult<>).MakeGenericType(type);
        return Activator.CreateInstance(resultType, content, this) as IHttpActionResult;
    }
like image 114
Syed B Avatar answered Nov 09 '22 16:11

Syed B