【问题标题】:OData v4 on .Net Core 1.1 missing /$metadata.Net Core 1.1 上的 OData v4 缺少 /$metadata
【发布时间】:2017-06-30 19:11:26
【问题描述】:

使用 .net Core 1.1 和 Microsoft.AspNetCore.OData 库,我可以让 OData 端点与我的简单控制器一起执行 get、$expand 和其他查询。但是,我无法让它返回要返回的 $metadata。这个问题 ($Metadata with WebAPi OData Attribute Routing Not Working) 是针对同一个问题的,但是自发布以来,.Net API 发生了变化。

我需要启用设置、标志或其他东西吗?

这(http://localhost:52315/odata)似乎返回了元数据,

{
  "@odata.context":"http://localhost:52315/odata/$metadata","value":[
    {
      "name":"Users","kind":"EntitySet","url":"Users"
    },{
      "name":"HelloComplexWorld","kind":"FunctionImport","url":"HelloComplexWorld"
    }
  ]
}

这个 (http://localhost:52315/odata/$metadata) 给了我错误:

An unhandled exception occurred while processing the request.
NotSupportedException: No action match template '$metadata'
in 'MetadataController'

Microsoft.AspNetCore.OData.Routing.Conventions.DefaultODataRoutingConvention.SelectAction(RouteContext routeContext)

我的 Startup.cs 如下所示:

public void Configure(IApplicationBuilder app) {
   app.UseDeveloperExceptionPage();
   app.UseOData("odata");
   app.UseMvcWithDefaultRoute();
}

public void ConfigureServices(IServiceCollection services) {
    services.AddMvc().AddWebApiConventions();
    services.AddSingleton<ISampleService, ApplicationDbContext>();
    services.AddOData<ISampleService>(builder =>
    {
         builder.Namespace = "Sample";
         builder.EntityType<ApplicationUser>();
         builder.EntityType<Product>();
         builder.Function("HelloComplexWorld").Returns<Permissions>();
    });
}

注意:我可以通过在我的 ConfigureServices(...) 方法的开头添加它来解决这个问题,但考虑到 $metadata 支持应该是核心平台的一部分,这似乎是错误的。

app.Use(async (context, next) => {
     if (0 == string.Compare(context.Request.Path, @"/odata/$metadata", true)) {
        context.Request.Path = "/odata";
   }
   await next.Invoke();
});

【问题讨论】:

    标签: c# asp.net-web-api asp.net-core odata .net-core


    【解决方案1】:

    我今天重新审视了这一点,并使用 Microsoft.AspNetCore.OData.vNext 6.0.2-alpha-rtm 包取得了更大的成功。参考 this 示例,元数据和默认 OData 路由按预期工作。我的最小配置是:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddOData();
        }
    
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
    
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
    
            var modelBuilder = new ODataConventionModelBuilder();
            modelBuilder.EntitySet<Document>("Documents");
    
            app.UseMvc(builder =>
            {
                builder.MapODataRoute("odata", modelBuilder.GetEdmModel());
            });
        }
    

    【讨论】:

      【解决方案2】:

      /odata/$metadata 路由应该返回“服务数据模型的 XML 表示”(EDMX)(根据 the OData v4 Web API documentation)。这与服务根 /odata/ 不同,后者返回 OData 服务发布的资源的顶级描述(如您的示例所示)。

      我在使用预发布版 Microsoft.AspNetCore.OData 1.0.0-rtm-00015 时遇到了同样的问题,因为尚未提供正式版本 (see open issue on OData Web API repo)。

      为了说明这一点,您可以手动发出元数据,如下面的粗略示例所示。 (您可以在 OData/odata.net GitHub 存储库中找到 InMemoryMessage 类。)

      但是,我建议等待 OData ASP.NET Core 的正式发布,因为引用上述问题,“分支仍处于早期阶段,一旦我们的架构最终确定,我们可能会采取不同的方法” .所以事情可能会发生变化...... $metadata 绝对应该“开箱即用”!

              app.Use((context, func) =>
              {
                  if (context.Request.Path.StartsWithSegments(new PathString("/data/v1/$metadata"), StringComparison.OrdinalIgnoreCase))
                  {
                      var model = app.ApplicationServices.GetService<IEdmModel>();
      
                      MemoryStream stream = new MemoryStream();
                      InMemoryMessage message = new InMemoryMessage() {Stream = stream};
      
                      ODataMessageWriterSettings settings = new ODataMessageWriterSettings();
      
                      ODataMessageWriter writer = new ODataMessageWriter((IODataResponseMessage)message, settings, model);
                      writer.WriteMetadataDocument();
      
                      string output = Encoding.UTF8.GetString(stream.ToArray());
      
                      return context.Response.WriteAsync(output);
                  }
      
                  return func();
              });
      

      【讨论】:

        猜你喜欢
        • 2013-03-27
        • 1970-01-01
        • 2014-12-28
        • 1970-01-01
        • 2018-09-27
        • 2017-05-26
        • 1970-01-01
        • 2015-03-06
        • 1970-01-01
        相关资源
        最近更新 更多