23

我想創建一個新的ASP.NET Core項目,使用OData和EntityFramework的「簡單」web api。我以前在舊版本的ASP.NET中使用過OData。如何正確整合OData與ASP.net核心

我已經建立了一個只有一個簡單的get函數的控制器。我設法使用基本的OData命令作爲過濾器和頂層,但我無法使擴展命令工作。我想這是因爲我無法弄清楚如何在Startup.cs中設置它。我已經嘗試了很多事情,包括以下從GitHub一些OData的樣本:

https://github.com/OData/WebApi/tree/vNext/vNext/samples/ODataSample.Web https://github.com/bigfont/WebApi/tree/master/vNext/samples/ODataSample.Web

在我的啓動文件,我嘗試排除其中有沒有效果,在所有服務類的一些屬性。所以問題可能在於我使用IDataService接口的方式。 (ApplicationContext在樣本中實現它)

要清楚我正在創建一個帶有完整.NET Framework的ASP.NET Core web api,而不僅僅是.Core框架。我目前的代碼是兩種樣本中最好/最差的混合,我可以過濾WebAPI但無法擴展或隱藏屬性。

任何人都可以看到我失蹤的og有一個ASP.NET Odata示例。我是startup.cs中的整個設置的新手?猜猜我正在找人做這項工作。

控制器

[EnableQuery] 
[Route("odata/Services")] 
public class ServicesController : Controller 
{ 
    private IGenericRepository<Service> _serviceRepo; 
    private IUnitOfWork _unitOfWork; 

    public ServicesController(IGenericRepository<Service> serviceRepo, IUnitOfWork unitOfWork) 
    { 
     _serviceRepo = serviceRepo; 
     _unitOfWork = unitOfWork; 
    } 

    [HttpGet] 
    public IQueryable<Service> Get() 
    { 
     var services = _serviceRepo.AsQueryable(); 
     return services; 
    } 
} 

啓動

using Core.DomainModel; 
using Core.DomainServices; 
using Infrastructure.DataAccess; 
using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Hosting; 
using Microsoft.Extensions.DependencyInjection; 
using Microsoft.Extensions.Logging; 
using Microsoft.Extensions.Configuration; 
using Microsoft.AspNetCore.OData.Extensions; 

namespace Web 
{ 
public class Startup 
{ 
    public Startup(IHostingEnvironment env) 
    { 
     var builder = new ConfigurationBuilder() 
      .SetBasePath(env.ContentRootPath) 
      .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 
      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 
      .AddEnvironmentVariables(); 

     if (env.IsDevelopment()) 
     { 
      // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately. 
      builder.AddApplicationInsightsSettings(developerMode: true); 
     } 
     Configuration = builder.Build(); 
    } 

    public IConfigurationRoot Configuration { get; } 

    // This method gets called by the runtime. Use this method to add services to the container. 
    public void ConfigureServices(IServiceCollection services) 
    { 
     // Add framework services. 
     services.AddApplicationInsightsTelemetry(Configuration); 
     services.AddMvc().AddWebApiConventions(); 

     services.AddSingleton<ApplicationContext>(_ => ApplicationContext.Create()); 

     services.AddSingleton<IDataService, ApplicationContext>(); 

     services.AddOData<IDataService>(builder => 
     { 
      //builder.EnableLowerCamelCase(); 
      var service = builder.EntitySet<Service>("Services"); 
      service.EntityType.RemoveProperty(x => x.CategoryId); 
      service.EntityType.RemoveProperty(x => x.PreRequisiteses); 
     }); 


     services.AddSingleton<IGenericRepository<Service>, GenericRepository<Service>>(); 
     services.AddSingleton<IUnitOfWork, UnitOfWork>(); 
    } 

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
    { 
     loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
     loggerFactory.AddDebug(); 

     //ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); 

     app.UseApplicationInsightsRequestTelemetry(); 

     //var builder = new ODataConventionModelBuilder(app.ApplicationServices.GetRequiredService<AssembliesResolver>()); 
     //var serviceCtrl = nameof(ServicesController).Replace("Controller", string.Empty); 
     //var service = builder.EntitySet<Service>(serviceCtrl); 
     //service.EntityType.RemoveProperty(x => x.CategoryId); 

     app.UseOData("odata"); 

     if (env.IsDevelopment()) 
     { 
      app.UseDeveloperExceptionPage(); 
      app.UseBrowserLink(); 
     } 
     else 
     { 
      app.UseExceptionHandler("/Home/Error"); 
     } 

     app.UseApplicationInsightsExceptionTelemetry(); 

     app.UseStaticFiles(); 

     app.UseMvc(routes => 
     { 
      routes.MapRoute(
       name: "default", 
       template: "{controller=Home}/{action=Index}/{id?}"); 
     }); 
    } 
} 

}

Project.json依賴性

"dependencies": { 
    "Microsoft.ApplicationInsights.AspNetCore": "1.0.2", 
    "Microsoft.AspNet.Identity.EntityFramework": "2.2.1", 
    "Microsoft.AspNetCore.Diagnostics": "1.0.0", 
    "Microsoft.AspNetCore.Identity": "1.0.0", 
    "Microsoft.AspNetCore.Mvc": "1.0.1", 
    "Microsoft.AspNetCore.Razor.Tools": { 
     "version": "1.0.0-preview2-final", 
     "type": "build" 
    }, 
    "Microsoft.AspNetCore.Routing": "1.0.1", 
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", 
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.1", 
    "Microsoft.AspNetCore.StaticFiles": "1.0.0", 
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", 
    "Microsoft.Extensions.Configuration.Json": "1.0.0", 
    "Microsoft.Extensions.Logging": "1.0.0", 
    "Microsoft.Extensions.Logging.Console": "1.0.0", 
    "Microsoft.Extensions.Logging.Debug": "1.0.0", 
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", 
    "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0", 
    "Microsoft.AspNetCore.OData": "1.0.0-rtm-00015", 
    "dnx-clr-win-x86": "1.0.0-rc1-update2", 
    "Microsoft.OData.Core": "7.0.0", 
    "Microsoft.OData.Edm": "7.0.0", 
    "Microsoft.Spatial": "7.0.0" 
+0

@l - '''''' - '''''''''''',嘗試使用https://github.com/voronov-格言/ OdataToEntity女巫有容器作爲客戶端,展開,選擇和其他 – itikhomi

回答

2

我有一個GitHub庫,其自動從代碼第一EF模型生成ASP.NET核心的OData v4的控制器,使用T4繼承控制器。它使用Microsoft.AspNetCore.OData.vNext 6.0.2-alpha-rtm。可能會有興趣。

https://github.com/afgbeveridge/AutoODataEF.Core

+0

我試了很多個小時纔得到這個工作。但由於某種原因,我無法讓它轉變,我得到了一些非常奇怪的錯誤,我無法使用Google。你會碰巧有一些時間來幫忙嗎? –

5

我設法使它工作,但因爲我需要更多的粒度我沒有使用所提供的OData路由。通過此解決方案,您可以創建自己的Web API,同時仍允許使用OData查詢參數。

注:

  • 我用NuGet包Microsoft.AspNetCore.OData.vNext,版本6.0.2-alpha-rtm,這需要.NET 4.6.1
  • 作爲FAS我可以告訴大家,OData的vNext僅支持OData的V4(所以沒有V3)
  • OData vNext似乎已經被趕下了,並且充滿了bug。例如,$orderby查詢參數被打破

MyEntity.cs

namespace WebApplication1 
{ 
    public class MyEntity 
    { 
     // you'll need a key 
     public int EntityID { get; set; } 
     public string SomeText { get; set; } 
    } 
} 

Startup.cs

using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Hosting; 
using Microsoft.AspNetCore.OData; 
using Microsoft.AspNetCore.OData.Abstracts; 
using Microsoft.AspNetCore.OData.Builder; 
using Microsoft.AspNetCore.OData.Extensions; 
using Microsoft.Extensions.Configuration; 
using Microsoft.Extensions.DependencyInjection; 
using Microsoft.Extensions.Logging; 
using System; 

namespace WebApplication1 
{ 
    public class Startup 
    { 
     public Startup(IHostingEnvironment env) 
     { 
      var builder = new ConfigurationBuilder() 
       .SetBasePath(env.ContentRootPath) 
       .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 
       .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 
       .AddEnvironmentVariables(); 
      Configuration = builder.Build(); 
     } 

     public IConfigurationRoot Configuration { get; } 

     public void ConfigureServices(IServiceCollection services) 
     { 
      services.AddMvc(); 

      /* ODATA part */ 
      services.AddOData(); 
      // the line below is used so that we the EdmModel is computed only once 
      // we're not using the ODataOptions.ModelManager because it doesn't seemed plugged in 
      services.AddSingleton<IODataModelManger, ODataModelManager>(DefineEdmModel); 
     } 

     private static ODataModelManager DefineEdmModel(IServiceProvider services) 
     { 
      var modelManager = new ODataModelManager(); 

      // you can add all the entities you need 
      var builder = new ODataConventionModelBuilder(); 
      builder.EntitySet<MyEntity>(nameof(MyEntity)); 
      builder.EntityType<MyEntity>().HasKey(ai => ai.EntityID); // the call to HasKey is mandatory 
      modelManager.AddModel(nameof(WebApplication1), builder.GetEdmModel()); 

      return modelManager; 
     } 

     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
     { 
      loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
      loggerFactory.AddDebug(); 

      if (env.IsDevelopment()) 
      { 
       app.UseDeveloperExceptionPage(); 
       app.UseBrowserLink(); 
      } 
      else 
      { 
       app.UseExceptionHandler("/Home/Error"); 
      } 

      app.UseStaticFiles(); 

      app.UseMvc(routes => 
      { 
       routes.MapRoute(
        name: "default", 
        template: "{controller=Home}/{action=Index}/{id?}"); 
      }); 
     } 
    } 
} 

Controller.cs

using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.AspNetCore.OData; 
using Microsoft.AspNetCore.OData.Abstracts; 
using Microsoft.AspNetCore.OData.Query; 
using System.Linq; 

namespace WebApplication1.Controllers 
{ 
    [Produces("application/json")] 
    [Route("api/Entity")] 
    public class ApiController : Controller 
    { 
     // note how you can use whatever endpoint 
     [HttpGet("all")] 
     public IQueryable<MyEntity> Get() 
     { 
      // plug your entities source (database or whatever) 
      var entities = new[] { 
       new MyEntity{ EntityID = 1, SomeText = "Test 1" }, 
       new MyEntity{ EntityID = 2, SomeText = "Test 2" }, 
       new MyEntity{ EntityID = 3, SomeText = "Another texts" }, 
      }.AsQueryable(); 

      var modelManager = (IODataModelManger)HttpContext.RequestServices.GetService(typeof(IODataModelManger)); 
      var model = modelManager.GetModel(nameof(WebApplication1)); 
      var queryContext = new ODataQueryContext(model, typeof(MyEntity), null); 
      var queryOptions = new ODataQueryOptions(queryContext, HttpContext.Request); 

      return queryOptions 
       .ApplyTo(entities, new ODataQuerySettings 
       { 
        HandleNullPropagation = HandleNullPropagationOption.True 
       }) 
       .Cast<MyEntity>(); 
     } 
    } 
} 

如何測試

您可以使用下面的URI:/api/Entity/all?$filter=contains(SomeText,'Test')。如果它工作正常,你應該只看到前兩個實體。

+0

這是一顆寶石非常感謝你! –

+0

證實,這與核心2.0一起工作,當我們有多個實體之間存在關係時會發生什麼?我們是否可以做擴展和所有這些操作? –

+0

該解決方案允許您更多地控制如何通過OData公開您的實體,但缺點是它不會自動生成路線。所以不,你將無法擴大兒童實體。 –

4

我也得到了Microsoft.AspNetCore.OData.vNextversion 6.0.2-alpha-rtm工作,但我用下面的代碼映射Edm模型路線:

services.AddOData(); 
// ... 
app.UseMvc(routes => 
{ 
    ODataModelBuilder modelBuilder = new ODataConventionModelBuilder(); 
    modelBuilder.EntitySet<Product>("Products"); 
    IEdmModel model = modelBuilder.GetEdmModel(); 
    routes.MapODataRoute(
    prefix: "odata", 
     model: model 
); 

隨着services.AddOData()

很奇怪,但它似乎與.net工作核心1.1

+0

這看起來像一個有趣的方法,可以幫助如果你只是想在特定的查詢中應用OData。 – bigtlb

+0

與core 2一起工作嗎? –

+0

支持461所以是的。 – davidcarr