使用服务数据库上下文作为 WebApi OData 上下文

Using A Service DB Context as WebApi OData Context

我正在尝试使用 Webapi 2 创建 OData 服务。 我已经创建了一个适用于本地上下文的工作示例。现在,我想使用由单独的 WCF 服务提供的上下文。

WebApiConfig.cs:

public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

        config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
        config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;


        config.AddODataQueryFilter();

        // To disable tracing in your application, please comment out or remove the following line of code
        // For more information, refer to: http://www.asp.net/web-api
        config.EnableSystemDiagnosticsTracing();
    }

控制器Class:

public class ProductsController : ODataController
{
    static Uri ServiceRoot = new Uri("http://localhost:4684/BDBWcfService.svc/");

    public ProductsController()
    {
        //db.Configuration.ProxyCreationEnabled = false;
        InitDB();
    }

    public void InitDB()
    {
         db = new BDBODataService.NORTHWNDEntities(ServiceRoot);
    }

    DataServiceContext Context = new DataServiceContext(ServiceRoot, DataServiceProtocolVersion.V3);

    BDBODataService.NORTHWNDEntities db = null;

    //NORTHWNDEntities db = new NORTHWNDEntities();
    // GET api/values
    //[EnableQuery]
    //public IQueryable<Product> Get()
    //{
    //    return db.Products;
    //}

    [EnableQuery]
    public IQueryable<BDBODataService.Product> Get()
    {
        return db.Products;
        //return Context.CreateQuery<BDBODataService.Product>("Products");
    }






    // GET api/values/5

    //Naming the attribute as key allows the model binder to sync when
    // calling urls like http://localhost:7428/odata/Products(1) key here = 1

    //[EnableQuery(MaxExpansionDepth=3)]
    //public SingleResult<Product> Get([FromODataUri]int key)
    //{
    //    var res = db.Products.Where(p => p.ProductID == key);
    //    return SingleResult.Create(res);
    //}

    // POST api/values
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/values/5
    public void Delete(int id)
    {
    }
}

很抱歉这些评论是我尝试过的其他解决方案。

当我执行代码时,我要么收到 406 不可接受的错误,要么得到一个空体而不是我的 Json。

有人知道我能做些什么来解决这个问题吗?

显然只需使用即可启用 OData 支持:

config.AddODataQueryFilter();

在本地工作,但如果来自服务,您需要明确声明您的模型。我不是 100% 确定这是我所有问题的原因,我最终调试了 System.Web.Http.OData 和 .net 4.5 框架,发现根本原因是 DefaultContentNegotiator.cs 一直说它不能Iqueryable 类型,因为请求无法解析 EDM 模型。在像这样明确声明我的模型后,一切都开始工作了:

 public static IEdmModel GetServiceModel()
    {
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

        builder.EntitySet<BDBODataService.Order>("Orders");

        /* this explicitly Ignores a specific property.
         * notice if you call http://localhost:7428/odata/Products(1)?$expand=Category
         * picture will be hidden */

        var cat = builder.EntitySet<BDBODataService.Category>("Categories");
        cat.EntityType.Ignore(c => c.Picture);

        builder.EntitySet<BDBODataService.CustomerDemographic>("CustomerDemographics");
        builder.EntitySet<BDBODataService.Customer>("Customers");
        builder.EntitySet<BDBODataService.Employee>("Employees");
        builder.EntitySet<BDBODataService.Order_Detail>("OrderDetails");
        builder.EntitySet<BDBODataService.Region>("Regions");
        builder.EntitySet<BDBODataService.Shipper>("Shippers");
        builder.EntitySet<BDBODataService.Supplier>("Suppliers");
        builder.EntitySet<BDBODataService.Territory>("Territories");
        builder.EntitySet<BDBODataService.Orpan>("Orphans");


        var products = builder.EntitySet<BDBODataService.Product>("Products");

        return builder.GetEdmModel();
    }