简体   繁体   English

为什么添加Microsoft.AspNetCore.OData.Versioning后,我的HTTP Post不再传递正文内容

[英]Why is my HTTP Post no longer passing the body content after adding Microsoft.AspNetCore.OData.Versioning

I am working on an ASP.NET Core 2.2 API that is implementing OData via Microsoft.AspNetCore.Odata v7.1.0 NuGet. 我正在研究通过Microsoft.AspNetCore.Odata v7.1.0 NuGet实现OData的ASP.NET Core 2.2 API。 I had everything working fine so I decided to add API Versioning via the Microsoft.AspNetCore.OData.Versioning v3.1.0. 我一切正常,因此我决定通过Microsoft.AspNetCore.OData.Versioning v3.1.0添加API版本控制。

Now, my GET and GET{id} methods in my controller work correctly with versioning. 现在,我的控制器中的GET和GET {id}方法可以正确使用版本控制。 For example, I can get to the GET list endpoint method by using the URL 例如,我可以使用URL到达GET列表端点方法

~/api/v1/addresscompliancecodes

or 要么

~/api/addresscompliancecodes?api-version=1.0

However when I try to create a new record, the request routes to the correct method in the controller but now the request body content is not being passed to the POST controller method 但是,当我尝试创建新记录时,请求将路由到控制器中的正确方法,但是现在请求正文内容未传递给POST控制器方法

I have been following the examples in the Microsoft.ApsNetCore.OData.Versioning GitHub 我一直在遵循Microsoft.ApsNetCore.OData.Versioning GitHub中的示例

There is the HttpPost method in my controller; 我的控制器中有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);
    }

When I debug, the request routes to the controller method properly but the "record" variable is now null, whereas, before adding the code changes for API Versioning, it was correctly populated. 当我调试时,请求正确地路由到控制器方法,但是“ record”变量现在为null,而在为API Versioning添加代码更改之前,已正确填充了该变量。

I suspect it is how I am using the model builder since that code changed to support API versioning. 我怀疑这是我使用模型构建器的方式,因为该代码已更改为支持API版本控制。

Before trying to implement API Versioning, I was using a model builder class as shown below; 在尝试实现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();
    }

}

And a Startup.cs --> Configure method like what is shown in the snippet below; 还有一个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());



        });

And it worked with [FromBody] in the HttpPost method of the controller. 它与控制器的HttpPost方法中的[FromBody]一起使用。

However, in following the examples in the API Versioning OData GitHub, I am now using a Configuration class like what is shown below, rather than the model builder from before; 但是,在遵循API版本控制OData GitHub中的示例时,我现在使用的是类似下面所示的Configuration类,而不是以前的模型构建器。

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

And my Startup.cs --> Configure method is changed as shown below; 我的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);
        });


    }

If it is relevant, I have the following code in my Startup.cs -> ConfigureServices; 如果相关的话,我在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();
            });

I feel the issue is with the model is somehow not matching up correctly but I cannot see exactly why it isn't 我觉得问题在于模型无法正确匹配,但我无法确切知道为什么不匹配

UPDATE 3/18/19 - Additional Information 更新3/18/19-附加信息

Here is my entity class; 这是我的实体类;

[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; }
}

and the EntityBase class; 和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; }
}

And here is the request body from Postman; 这是邮递员的请求正文;

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

Any ideas? 有任何想法吗?

As it turned out, the problem was because I was not using camel case as my property names in the Postman request body. 事实证明,问题是因为我没有在邮差请求正文中使用驼峰大小写作为我的财产名称。 This was not an issue with Microsoft.AspNetCore.Odata alone but once I added the Microsoft.AspNetCore.Odata.Versioning NuGet package, it failed with the upper case starting character of the property names. 单独使用Microsoft.AspNetCore.Odata并不是一个问题,但是一旦添加了Microsoft.AspNetCore.Odata.Versioning NuGet程序包,它就会失败,并使用属性名称的大写开头字符。 It seems that Microsoft.AspNetCore.Odata.Versioning uses it's own MediaTypeFormatter that enables lower camel case. 似乎Microsoft.AspNetCore.Odata.Versioning使用它自己的MediaTypeFormatter来启用小写驼峰格式。 I discovered this in the following GitHub post; 我在以下GitHub帖子中发现了这一点; https://github.com/Microsoft/aspnet-api-versioning/issues/310 https://github.com/Microsoft/aspnet-api-versioning/issues/310

There is no custom MediaTypeFormatter, but the behavior did change in 3.0 as using camel casing is seemingly the default for most JSON-based APIs. 没有自定义MediaTypeFormatter,但是行为在3.0中确实发生了变化,因为使用骆驼套似乎是大多数基于JSON的API的默认设置。 This is easy to revert back however. 但是,这很容易还原。

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

The is also the place were you'd perform or change any other setup related to model builders. 这也是您执行或更改与模型构建器相关的任何其他设置的地方。 The factory method is called to create a new model builder per API version. 调用factory方法可为每个API版本创建一个新的模型构建器。

It's worth pointing out that you do not need to map routes twice. 值得指出的是,你不需要两次映射路线。 For demonstraton purposes, the by query string and by URL path are configured. 出于演示目的,配置了按查询字符串按URL路径 You should choose one or the other and remove the one that isn't used. 您应该选择其中一项,然后删除未使用的一项。

I hope that helps. 希望对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Microsoft.AspNetCore.OData是否支持API版本控制? - Does Microsoft.AspNetCore.OData support API versioning? 为什么我的HTTP POST正文内容被接收/处理为NULL? - Why is my HTTP POST Body content received/processed as NULL? Microsoft.AspNetCore不再可用吗? - Is Microsoft.AspNetCore no longer available? Microsoft.AspNetCore.OData 8:按约定找不到 controller - Microsoft.AspNetCore.OData 8: controller is not found by convention 为什么 Microsoft.AspNetCore.Http.StatusCodes 没有设计为枚举? - Why is Microsoft.AspNetCore.Http.StatusCodes not designed as an enum? Microsoft.AspNetCore.OData - 自定义注释 $metadata - Microsoft.AspNetCore.OData - Custom annotations $metadata 如何设置 Swashbuckle 与 Microsoft.AspNetCore.Mvc.Versioning - How to set up Swashbuckle vs Microsoft.AspNetCore.Mvc.Versioning Microsoft.AspNetCore.Mvc.Versioning如何默认为“最新”版本 - Microsoft.AspNetCore.Mvc.Versioning how to default to the “latest” version 命名空间“Microsoft.AspNetCore”中不存在类型或命名空间“OData” - The type or namespace 'OData' does not exist in the namespace 'Microsoft.AspNetCore' 从我的Web服务中读取Http POST正文内容? (.net 3.5) - Reading the Http POST body content from my web service? (.net 3.5)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM