0

我正在研究通过 Microsoft.AspNetCore.Odata v7.1.0 NuGet 实现 OData 的 ASP.NET Core 2.2 API。我一切正常,所以我决定通过 Microsoft.AspNetCore.OData.Versioning v3.1.0 添加 API 版本控制。

现在,我的控制器中的 GET 和 GET{id} 方法可以与版本控制一起正常工作。例如,我可以使用 URL 访问 GET 列表端点方法

~/api/v1/addresscompliancecodes

或者

~/api/addresscompliancecodes?api-version=1.0

但是,当我尝试创建新记录时,请求会路由到控制器中的正确方法,但现在请求正文内容未传递给 POST 控制器方法

我一直在关注 Microsoft.ApsNetCore.OData.Versioning GitHub中的示例

我的控制器中有 HttpPost 方法;

    [HttpPost]
    [ODataRoute()]
    public async Task<IActionResult> CreateRecord([FromBody] AddressComplianceCode record, ODataQueryOptions<AddressComplianceCode> options)
    {

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        _context.Add(record);
        await _context.SaveChangesAsync();

        return Created(record);
    }

当我调试时,请求正确地路由到控制器方法,但“记录”变量现在为空,而在添加 API 版本控制的代码更改之前,它已正确填充。

我怀疑这是我使用模型构建器的方式,因为该代码已更改为支持 API 版本控制。

在尝试实现 API 版本控制之前,我使用了一个模型构建器类,如下所示;

public class AddressComplianceCodeModelBuilder
{

    public IEdmModel GetEdmModel(IServiceProvider serviceProvider)
    {
        var builder = new ODataConventionModelBuilder(serviceProvider);

        builder.EntitySet<AddressComplianceCode>(nameof(AddressComplianceCode))
            .EntityType
            .Filter()
            .Count()
            .Expand()
            .OrderBy()
            .Page() // Allow for the $top and $skip Commands
            .Select(); 

        return builder.GetEdmModel();
    }

}

还有一个 Startup.cs --> Configure 方法,如下面的代码片段所示;

        // Support for OData $batch
        app.UseODataBatching();

        app.UseMvc(routeBuilder =>
        {
            // Add support for OData to MVC pipeline
            routeBuilder
                .MapODataServiceRoute("ODataRoutes", "api/v1",
                    modelBuilder.GetEdmModel(app.ApplicationServices),
                    new DefaultODataBatchHandler());



        });

它在控制器的 HttpPost 方法中与 [FromBody] 一起使用。

但是,在遵循 API Versioning OData GitHub 中的示例时,我现在使用如下所示的配置类,而不是之前的模型构建器;

public class AddressComplianceCodeModelConfiguration : IModelConfiguration
{

    private static readonly ApiVersion V1 = new ApiVersion(1, 0);

    private EntityTypeConfiguration<AddressComplianceCode> ConfigureCurrent(ODataModelBuilder builder)
    {
        var addressComplianceCode = builder.EntitySet<AddressComplianceCode>("AddressComplianceCodes").EntityType;

        addressComplianceCode
            .HasKey(p => p.Code)
            .Filter()
            .Count()
            .Expand()
            .OrderBy()
            .Page() // Allow for the $top and $skip Commands
            .Select();


        return addressComplianceCode;
    }
    public void Apply(ODataModelBuilder builder, ApiVersion apiVersion)
    {
        if (apiVersion == V1)
        {
            ConfigureCurrent(builder);
        }
    }
}

而我的 Startup.cs --> Configure 方法改变如下图;

    public void Configure(IApplicationBuilder app,
        IHostingEnvironment env, 
        VersionedODataModelBuilder modelBuilder)
    {

        // Support for OData $batch
        app.UseODataBatching();

        app.UseMvc(routeBuilder =>
        {
            // Add support for OData to MVC pipeline
            var models = modelBuilder.GetEdmModels();
            routeBuilder.MapVersionedODataRoutes("odata", "api", models);
            routeBuilder.MapVersionedODataRoutes("odata-bypath", "api/v{version:apiVersion}", models);
        });


    }

如果相关,我的 Startup.cs -> ConfigureServices 中有以下代码;

        // Add Microsoft's API versioning
        services.AddApiVersioning(options =>
        {
            // reporting api versions will return the headers "api-supported-versions" and "api-deprecated-versions"
            options.ReportApiVersions = true;
        });

        // Add OData 4.0 Integration
        services.AddOData().EnableApiVersioning();

        services.AddMvc(options =>
            {
                options.EnableEndpointRouting = false; // TODO: Remove when OData does not causes exceptions anymore
            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(opt =>
            {
                opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });

我觉得问题在于模型在某种程度上没有正确匹配,但我看不出它为什么不正确

更新 3/18/19 - 附加信息

这是我的实体类;

[Table("AddressComplianceCodes")]
public class AddressComplianceCode : EntityBase
{
    [Key]
    [Column(TypeName = "char(2)")]
    [MaxLength(2)]
    public string Code { get; set; }

    [Required]
    [Column(TypeName = "varchar(150)")]
    [MaxLength(150)]
    public string Description { get; set; }
}

和 EntityBase 类;

public class EntityBase : IEntityDate
{
    public bool MarkedForRetirement { get; set; }

    public DateTimeOffset? RetirementDate { get; set; }

    public DateTimeOffset? LastModifiedDate { get; set; }

    public string LastModifiedBy { get; set; }

    public DateTimeOffset? CreatedDate { get; set; }

    public string CreatedBy { get; set; }

    public bool Delete { get; set; }

    public bool Active { get; set; }
}

这是 Postman 的请求正文;

{   
    "@odata.context": "https://localhost:44331/api/v1/$metadata#AddressComplianceCodes",
    "Code": "Z1",
    "Description": "Test Label - This is a test for Z1",
    "Active": true
}

有任何想法吗?

4

2 回答 2

2

事实证明,问题是因为我没有在 Postman 请求正文中使用驼峰式大小写作为我的属性名称。这不是单独的 Microsoft.AspNetCore.Odata 的问题,但是一旦我添加了 Microsoft.AspNetCore.Odata.Versioning NuGet 包,它就会因属性名称的大写起始字符而失败。似乎 Microsoft.AspNetCore.Odata.Versioning 使用它自己的 MediaTypeFormatter 来启用小驼峰式大小写。我在以下 GitHub 帖子中发现了这一点;https://github.com/Microsoft/aspnet-api-versioning/issues/310

于 2019-03-19T20:26:48.310 回答
0

没有自定义 MediaTypeFormatter,但行为在 3.0 中确实发生了变化,因为使用驼峰式大小写似乎是大多数基于 JSON 的 API 的默认设置。然而,这很容易恢复。

modelBuilder.ModelBuilderFactory = () => new ODataConventionModelBuilder();
// as opposed to the new default:
// modelBuilder.ModelBuilderFactory = () => new ODataConventionModelBuilder().EnableLowerCamelCase();

这也是您执行或更改与模型构建器相关的任何其他设置的地方。调用工厂方法来为每个 API 版本创建一个新的模型构建器。

值得指出的是,您不需要两次映射路线。出于演示目的,配置了按查询字符串按 URL 路径。您应该选择其中一个并删除未使用的那个。

我希望这会有所帮助。

于 2019-04-25T18:21:20.717 回答