在验证期间注入非用户提交的数据以供使用

时间:2017-01-09 21:36:41

标签: validation asp.net-core

据我所知,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);

    //...
}

1 个答案:

答案 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())
    );
}

进一步的文件:

我不认为官方文档有关于自定义模型绑定器的文章,但遗憾的是。