自定义模型绑定器未针对 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]
并在操作方法中设置了一个断点。执行操作方法,但不执行自定义模型绑定器。
那么当你这样做时,Email
和 Password
有值吗?我想知道这种变化是否真的意味着什么都没有受到任何约束,因为您发送的 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 forformdata
,它发送请求正文中的数据而不是 url 编码数据。 FormData
和 Json
是绑定数据的两个选项。两者都是标准的。如果你更喜欢json
,你需要自定义jsoninput formatter。
@TaoZhuo 我知道它将正文内的数据作为 URL 编码的表单数据发送,我的意思是。我将尝试自定义 JSON 输入格式化程序方法。请在您的回答中提及使用自定义 JSON 格式化程序的可能性,以便其他人知道这一点,我将其标记为已接受的答案。以上是关于自定义模型绑定器未针对 ASP.NET Core 2 中的单个属性触发的主要内容,如果未能解决你的问题,请参考以下文章