-->

OData on .Net Core doesn't return the right re

2020-08-17 06:35发布

问题:

I've added OData to my WebAPI project.

Versions:

  1. Core 3.1
  2. OData 7.3.0 (beta version in order to work with Core 3.x)
  3. EF Core 3.1.0

Here is my startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<Models.Contexts.EntityContext>(opts => opts.UseSqlServer(Configuration["ConnectionString:MailBackup"]));
        services.AddControllers();
        services.AddMvc(options =>
        {
            options.EnableEndpointRouting = false;
        }).SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_3_0);

        services.AddOData();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc(routeBuilder =>
        {
            routeBuilder.EnableDependencyInjection();
            routeBuilder.Expand().Select().OrderBy().Filter();
        });

        app.UseHttpsRedirection();
        app.UseAuthorization();

    }
}

And the controller is:

[EnableQuery()]
[HttpGet]
[Route("GetAll")]
public IQueryable<Models.EmailMessage> GetAll()
{    
    return this._context.EmailMessages;
}

The APIs are working fine, but when I try to add some OData action like $select I get the following and not the expected results:

{
    "instance": null,
    "container": {},
    "modelID": "529e8054-04c4-4729-aa91-d7eaf67a55d0",
    "untypedInstance": null,
    "instanceType": null,
    "useInstanceForProperties": false
},
{
    "instance": null,
    "container": {},
    "modelID": "529e8054-04c4-4729-aa91-d7eaf67a55d0",
    "untypedInstance": null,
    "instanceType": null,
    "useInstanceForProperties": false
},

回答1:

I had the same problem. This solved the problem for me. Perhaps odata is not fully compatible with the new JSON serializer in Asp.Net 3.1. I don't know.

services.AddControllers(mvcOptions =>
           mvcOptions.EnableEndpointRouting = false)
       .AddNewtonsoftJson();


回答2:

The APIs are working fine, but when I try to add some OData action like $select I get the following and not the expected results

I can reproduce same issue in my .NET Core 3.x application with similar code as you shared, it seems that currently injecting OData services into existing API controller with following code snippet does not support well for .NET Core 3.x.

routeBuilder.EnableDependencyInjection();

And based on my test, it can work well in .NET Core 2.x. To make $select functionality work fine in .NET Core 3.x, currently we can try this workaround:

In Startup.cs

var builder = new ODataConventionModelBuilder(app.ApplicationServices);

builder.EntitySet<Product>("Products");


app.UseMvc(routeBuilder =>
{
    // and this line to enable OData query option, for example $filter

    routeBuilder.Expand().Select().OrderBy().Filter();

    routeBuilder.MapODataServiceRoute("ODataRoute", "api", builder.GetEdmModel());

});

In ODataController

public class ProductsController : ODataController
{
    // ...
    //code logic here
    // ...

    [HttpGet]
    [EnableQuery]
    public IQueryable<Product> Get()
    {
        var products = _context.Products;

        return products;
    }

    // ...

}

Test Result

For more information, please check: https://docs.microsoft.com/en-us/odata/webapi/netcore#e-configure-the-odata-endpoint