OData v4 on .Net Core 1.1 missing /$metadata

核能气质少年 提交于 2020-01-01 18:57:07

问题


Using .net Core 1.1, with the Microsoft.AspNetCore.OData libraries, I am able to get an OData endpoint working with my simple controller to perform get, $expand, and other queries. However, I can't get it to return the $metadata to be returned. This question ($Metadata with WebAPi OData Attribute Routing Not Working) is for the same problem, however the .Net APIs have changed since this was posted.

Is there a setting, flag, or something else I need to enable?

This (http://localhost:52315/odata) seems to return the meta data,

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

this (http://localhost:52315/odata/$metadata) gives me the error:

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)

My Startup.cs looks like this:

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>();
    });
}

NOTE: I can work around it by adding this at the start of my ConfigureServices(...) method, though it seems wrong given $metadata support should be part of the core platform.

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

回答1:


I revisited this today and had more success using the Microsoft.AspNetCore.OData.vNext 6.0.2-alpha-rtm package. Referencing this example, the metadata and default OData routing worked as expected. My minimal configuration is:

    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:


The /odata/$metadata route should return "an XML representation of the service’s data model" (EDMX) (according to the OData v4 Web API documentation). This is not the same as the service root /odata/, which returns the top level description of resources published by the OData service (as shown in your example).

I encountered the same issue using the pre-release Microsoft.AspNetCore.OData 1.0.0-rtm-00015, since an official release is not yet available (see open issue on OData Web API repo).

To illustrate the point, you could manually emit the metadata, as in the crude example below. (You can find the InMemoryMessage class in the OData/odata.net GitHub repo.)

However, I would suggest waiting for an official release of OData ASP.NET Core as, quoting from the above issue, the "branch is still in its early stages and we may take a different approach once we have our architecture finalized". So things may well change... and $metadata should definitely work "out of the box"!

        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();
        });


来源:https://stackoverflow.com/questions/42193231/odata-v4-on-net-core-1-1-missing-metadata

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!