在ASP.NET Core中绑定源参数推断

时间:2018-07-19 12:59:44

标签: c# asp.net-core asp.net-core-mvc

我目前正在将项目从ASP.NET WebAPI 5.2.6(OWIN)升级到ASP.NET Core 2.1.1(Kestrel)。

我们的项目是一个单页应用程序,我们通过WebAPI与客户端进行通信。因此,我想用新的ApiController属性注释控制器。

不幸的是,似乎binding source parameter inference不能按预期工作(至少对我而言)。我根据文档假设,复杂类型(例如我的LoginRequest)被推断为[FromBody]

代码(控制器和启动程序)

// AccountController.cs

[Route("/account"), ApiController]
public class AccountController : ControllerBase
{
    [HttpPost("backendLogin"), AllowAnonymous]
    public async Task<ActionResult<LoginResponse>> BackendLogin(LoginRequest lr)
    {
        await Task.CompletedTask.ConfigureAwait(false); // do some business logic
        return Ok(new LoginResponse {UserId = "123"});
    }

    // Models

    public class LoginRequest {
        public string Email { get; set; }
        public string Password { get; set; }
    }

    public class LoginResponse {
        public string UserId { get; set; }
    }
}

// Startup.cs

public void ConfigureServices(IServiceCollection services) {
    services.AddMvcCore()
                    .AddJsonFormatters(settings => {
                        settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
                        settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
                        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    })
                    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.Configure<ApiBehaviorOptions>(options => {
        // options.SuppressConsumesConstraintForFormFileParameters = true;
        // options.SuppressInferBindingSourcesForParameters = true;
        // options.SuppressModelStateInvalidFilter = true;
    });
}

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

问题

通过Ajax调用(Content-Type: application/x-www-form-urlencoded;)从客户端调用控制器会导致响应400(错误请求),内容为{"":["The input was not valid."]}。在服务器上,我得到以下跟踪输出: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor: Information: Executing ObjectResult, writing value of type 'Microsoft.AspNetCore.Mvc.SerializableError'.

如果我将options.SuppressInferBindingSourcesForParameters中的ConfigureServices更改为true,它似乎可以工作。这很奇怪,因为此设置应禁用绑定推断,或者我是否误解了某些内容?这是ASP.NET核心中的错误还是我遗漏了一些东西?

顺便说一句。如果我省略ApiController属性,它也可以工作,但是我想这不是解决此问题的真正方法。 此外,如果我不需要在客户端进行任何更改(添加标头,更改内容类型等),我会很高兴,因为那里有很多Ajax调用,而我只想升级服务器端组件。

1 个答案:

答案 0 :(得分:2)

我也在官方的ASP.NET Core MVC存储库中问了这个问题。

其中一个成员(pranavkm)返回了answer,我在这里引用一下:

  

ApiController是为REST客户端特定方案而设计的,并非针对基于浏览器(形式化编码)的请求而设计。 FromBody假定为JSON \ XML请求主体,它将尝试对其进行序列化,而这不是您希望使用表单url编码的内容的方式。使用香草(非ApiController)是这里的方法。

因此,现在我将省略[ApiController]属性。 在以后的步骤中,我可以将客户端调用更改为使用JSON主体,以便读取属性。