【问题标题】:OData fails to serialize model with constructorOData 无法使用构造函数序列化模型
【发布时间】:2020-07-15 08:44:43
【问题描述】:

我正在尝试在我的项目中启用可为空的引用类型,并遵循 EF Core 团队提供的模型 guidelines。但它会破坏 OData 中的模型创建。

可以通过将其放入.csproj 文件来启用可空引用类型

<Nullable>enable</Nullable>

我正在使用

  • netcoreapp3.1
  • Microsoft.AspNetCore.OData 版本="7.4.0-beta"
  • Microsoft.EntityFrameworkCore.SqlServer 版本="3.1.3"

我的模型是这样的

public class Blog
{
    public Blog(int id, string name, string author)
    {
        Id = id;
        Name = name;
        Author = author;
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Author { get; set; }

    public ICollection<Post> Posts { get; } = new List<Post>();
}

当我尝试 POST 到端点时

[Route("odata/[controller]s")]
public class BlogController : ODataController
{
    private readonly MyContext _context;

    public BlogController(MyContext context)
    {
        _context = context;
    }

    [HttpGet]
    [EnableQuery]
    public IActionResult Get() {...}

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] Blog blog) {...}
}

有效载荷:

{
    "id": 123,
    "name": "foo",
    "author": "bar"
}

那么blog参数就是null

如果我关闭“可空引用类型”并删除它可以工作的构造函数。

请指教。

启动

也许我应该提一下,我正在使用 ASPNET Core 3.1 中的新端点 API,并且刚刚添加了对 OData v7.4.0-beta 中的支持

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

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<MMContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MyDatabase")));
        services.AddControllersWithViews();

        // In production, the Angular files will be served from this directory
        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "..\\frontend\\dist";
        });

        services.AddOData();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        if (!env.IsDevelopment())
        {
            app.UseSpaStaticFiles();
        }

        app.UseRouting();

        var model = EdmModelBuilder.GetEdmModel(); // EnableLowerCamelCase = true

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.Select().Filter().OrderBy().Count().MaxTop(50);
            endpoints.MapODataRoute("odata", "odata", model);
        });

        app.UseSpa(spa =>
        {
            // To learn more about options for serving an Angular SPA from ASP.NET Core,
            // see https://go.microsoft.com/fwlink/?linkid=864501

            spa.Options.SourcePath = "..\\frontend";

            if (env.IsDevelopment())
            {
                spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
            }
        });
    }
}

更新 我相信问题归结为 OData 不支持带有构造函数的模型,尽管 Json.Net 开箱即用地支持它。

【问题讨论】:

  • @mjwills 可为空的引用类型决定了对构造函数的需求。还将有效负载添加到问题中

标签: c# asp.net-core json.net odata asp.net-core-webapi


【解决方案1】:

当我尝试使用 Payload POST 到端点时:

{ “身份证”:123, “名称”:“富”, “作者”:“酒吧” }

那么blog参数就是null

this github issue中,我们可以发现:payload内容不支持不区分大小写。

为了让它能够很好地处理上面的payload,就像你提到的,我们可以关闭“可为空的引用类型”,然后像下面这样修改代码。

在博客类中

public class Blog
{
    public Blog()
    {

    }
    public Blog(int id, string name, string author)
    {
        Id = id;
        Name = name;
        Author = author;
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Author { get; set; }

    public ICollection<Post> Posts { get; } = new List<Post>();
}

并使用EnableLowerCamelCase 配置ODataConventionModelBuilder

var builder = new ODataConventionModelBuilder()
    .EnableLowerCamelCase();

测试结果

【讨论】:

  • 糟糕,忘了说EnableLowerCamelCase 已开启
  • 是的,所以我将其包含在上面的帖子中。
  • 这整个问题源于打开“可空引用类型”,我想继续使用它。对此有何建议?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
  • 1970-01-01
  • 2022-10-15
相关资源
最近更新 更多