自定义模型绑定器未针对 ASP.NET Core 2 中的单个属性触发

Posted

技术标签:

【中文标题】自定义模型绑定器未针对 ASP.NET Core 2 中的单个属性触发【英文标题】:Custom model binder not firing for a single property in ASP.NET Core 2 【发布时间】:2019-09-04 06:16:22 【问题描述】:

我已经尝试过this,但我不认为这是我的情况。 This 也不起作用。

我正在使用 ASP.NET Core 2 Web API。我刚刚创建了一个虚拟模型绑定器(现在它的作用无关紧要):

public class SanitizeModelBinder : IModelBinder

    public Task BindModelAsync(ModelBindingContext bindingContext)
    
        if (bindingContext == null)
        
            throw new ArgumentNullException(nameof(bindingContext));
        

        var modelName = bindingContext.ModelName;

        return Task.CompletedTask;
    

现在,我有一个模型。这个:

public class UserRegistrationInfo

    public string Email  get; set; 

    [ModelBinder(BinderType = typeof(SanitizeModelBinder))]
    public string Password  get; set; 

还有一个动作方法:

[AllowAnonymous]
[HttpPost("register")]
public async Task<IActionResult> RegisterAsync([FromBody] UserRegistrationInfo registrationInfo)

    var validationResult = validateEmailPassword(registrationInfo.Email, registrationInfo.Password);
    if (validationResult != null) 
    
        return validationResult;
    

    var user = await _authenticationService.RegisterAsync(registrationInfo.Email, registrationInfo.Password);

    if (user == null)
    
        return StatusCode(StatusCodes.Status500InternalServerError, "Couldn't save the user.");
    
    else
    
        return Ok(user);
    

如果我从客户端发出 post 请求,我的自定义模型绑定器不会被触发,并且在 action 方法中继续执行。

我尝试过的事情:

ModelBinder 属性应用于整个模型对象:

[ModelBinder(BinderType = typeof(SanitizeModelBinder))]
public class UserRegistrationInfo

    public string Email  get; set; 
    public string Password  get; set; 

这可行,但对于整个对象,我不希望这样。我希望默认模型绑定器完成其工作,然后仅将我的自定义模型绑定器应用于某些属性。

我读到 here 是 FromBody 的错,所以我将它从操作方法中删除。它也不起作用。

我尝试在此处将ModelBinder 属性更改为BindProperty

public class UserRegistrationInfo

    public string Email  get; set; 

    [BindProperty(BinderType = typeof(SanitizeModelBinder))]
    public string Password  get; set; 

但它不起作用。

令人失望的是,本来应该很简单的事情变得相当繁琐,而且分散在几个博客和 github 问题上的信息根本没有帮助。所以,如果你能帮助我,那将不胜感激。

【问题讨论】:

有趣,也许你刚刚发现了一个错误。您的代码看起来正确 (docs.microsoft.com/en-us/aspnet/core/mvc/advanced/…)。在 MVC 存储库中创建问题可能会更好。您也可以尝试使用较新的版本来确定。 删除[FromBody] 后会发生什么?通过这样做,您实际上是从 JSON 正文切换到 application/x-www-form-urlencoded 正文,所以当您删除它时您是否也在更改正文的格式? @KirkLarkin 不,我刚刚删除了[FromBody] 并在操作方法中设置了一个断点。执行操作方法,但不执行自定义模型绑定器。 那么当你这样做时,EmailPassword 有值吗?我想知道这种变化是否真的意味着什么都没有受到任何约束,因为您发送的 JSON 是预期的application/x-www-form-urlencoded(假设您正在使用 JSON)。 这确认您需要自定义 JsonConverter 而不是自定义 IModelBinder。当你说你有时,你并没有真正删除 [FromBody],因为 [ApiController] 推断它。 【参考方案1】:

对于ModelBinder,您需要在客户端使用application/x-www-form-urlencoded,在服务器端使用[FromForm]

对于ApiController,其默认绑定是JsonConverter

按照以下步骤操作:

    改变动作

    [AllowAnonymous]
    [HttpPost("register")]
    public async Task<IActionResult> RegisterAsync([FromForm]UserRegistrationInfo registrationInfo)
    
        return Ok(registrationInfo);
    
    

    角度

    post(url: string, model: any): Observable <any> 
        let formData: FormData = new FormData(); 
        formData.append('id', model.id); 
        formData.append('applicationName', model.applicationName); 
        return this._http.post(url, formData)
            .map((response: Response) => 
                return response;
            ).catch(this.handleError); 
    
    

对于将json 与自定义绑定一起使用,您可以自定义格式化程序,并参考Custom formatters in ASP.NET Core Web API

【讨论】:

我赞成你的回答,因为它显示了解决问题的另一种方法(我很感激),但我的想法是稍后使用移动应用程序中的相同 API,我不知道它是否让移动应用程序发送 URL 编码数据非常合适。以 JSON 格式发送有效负载似乎更“标准”。 @amedina for formdata,它发送请求正文中的数据而不是 url 编码数据。 FormDataJson 是绑定数据的两个选项。两者都是标准的。如果你更喜欢json,你需要自定义jsoninput formatter。 @TaoZhuo 我知道它将正文内的数据作为 URL 编码的表单数据发送,我的意思是。我将尝试自定义 JSON 输入格式化程序方法。请在您的回答中提及使用自定义 JSON 格式化程序的可能性,以便其他人知道这一点,我将其标记为已接受的答案。

以上是关于自定义模型绑定器未针对 ASP.NET Core 2 中的单个属性触发的主要内容,如果未能解决你的问题,请参考以下文章

将自定义模型绑定器应用于 asp.net 核心中的对象属性

Asp.net Core 模型绑定器接受布尔类型的随机整数

asp.net core mvc 2中抽象类的模型绑定器

.NET Core 自定义模型绑定器调用默认模型绑定器

复杂对象和模型绑定器 ASP.NET MVC

为啥 ASP.Net MVC 模型绑定器将空 JSON 数组绑定到 null?