.Net Core 1.1 上的 OData v4 缺少 /$metadata

Posted

技术标签:

【中文标题】.Net Core 1.1 上的 OData v4 缺少 /$metadata【英文标题】:OData v4 on .Net Core 1.1 missing /$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();
);

【问题讨论】:

【参考方案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();
        );

【讨论】:

以上是关于.Net Core 1.1 上的 OData v4 缺少 /$metadata的主要内容,如果未能解决你的问题,请参考以下文章

ODataLib for OData V4 是不是支持请求中的 Atom 有效负载?

使用 ASP.NET Core OData 8.0 映射动态 OData 路由

如何正确地将 OData 与 ASP.net Core 集成

带有 EF Core / ASP.NET Core 的 OData - 好还是坏?

在 ASP.NET Core WebAPI 中获取 OData 计数

Net Core:在洋葱架构中使用OData,将查询参数转换为Linq