据我所知,ASP.Net Core在调用相关的控制器动作方法之前执行模型状态验证。这意味着action方法中的代码在验证之前没有机会向模型添加数据。
在验证之前,为视图模型访问其他非用户提交的数据的ASP.Net Core方法是什么?
我正在尝试做什么(不起作用)。
视图模型的Validate
方法期望数据位于ValidOptions
。但是,由于验证发生在控制器可以设置此属性之前,验证会导致视图模型抛出ArgumentNullException
。
// From the Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Process([Bind("SelectedId")]ViewModels.Import details)
{
// data needed for validation
details.ValidOptions = await service.ImportTypes.ToListAsync();
if (ModelState.ValidationState != ModelValidationState.Valid) {
// ...
}
}
// From ViewModels.Import
public IEnumerable<Option> ValidOptions { get; set; }
public int SelectdId {get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// throws ArgumentNullException because ValidOptions hasn't been set when this is executed
var option = ValidOptions.Single(t => t.Id == SelectdId);
//...
}
答案 0 :(得分:0)
可能有很多方法可以让猫在这里去皮。但对您来说最简单的可能是自定义模型粘合剂。这是补充&#34;的一种方式。或者在模型撞击控制器之前更改模型的绑定。我会说有些人认为在模型绑定点调用外部服务/存储库是非常糟糕的做法,但它确实有用并且可以派上用场。
您需要实现一个继承自IModelBinder的类。
public class MyViewModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
//Bind here. Including calling external services if you want.
}
}
然后你需要实现一个提供者,这基本上说&#34;当&#34;绑定。
public class MyViewModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(MyViewModel))
return new MyViewModelBinder();
return null;
}
}
在startup.cs的configure方法中,需要将提供程序添加到ModelBinderProviders列表中。
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc(config =>
config.ModelBinderProviders.Add(new MyViewModelBinderProvider())
);
}
进一步的文件:
我不认为官方文档有关于自定义模型绑定器的文章,但遗憾的是。