.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 - 好还是坏?