在AddValidation方法中访问模型数据asp.net核心自定义验证

时间:2017-08-29 12:35:41

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

我正在关注此示例:https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation并尝试实现自己的自定义属性进行验证。

现在,viewmodel有两个我希望从这个方法中访问的字段,因此它们可以使用" data-val"属性。我的问题是,我怎么能说出一个名为" Myprop"来自上下文?当我调试时,我可以查看context.ActionContext.ViewData.Model下的信息,但是当我使用Visual Studio&#34时,我无法获得其他信息。#34; quick watch"特征。自定义属性位于viewmodel上的属性上。

public void AddValidation(ClientModelValidationContext context)
{
    if (context == null)
    {
       throw new ArgumentNullException(nameof(context));
    }

    MergeAttribute(context.Attributes, "data-val", "true");
    MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());

    var year = _year.ToString(CultureInfo.InvariantCulture);
    MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
}

1 个答案:

答案 0 :(得分:2)

我遇到了类似的问题。简短的回答是,你不能来自。您只能从那里访问元数据,而不是实际模型。原因是您的模型元数据和基于它的验证是在首次使用时完成的,然后进行缓存。因此,您永远无法通过属性修饰器根据模型更改要返回的验证规则。

如果您需要根据模型的实例/内容动态决定要呈现哪些客户端data-val-*属性,则需要继承DefaultValidationHtmlAttributeProvider,而不是使用属性,并覆盖AddValidationAttributes方法。这是迄今为止我发现的唯一方法。这是因为在此方法中,您可以访问ModelExplorer

public class CustomValidationHtmlAttributeProvider : DefaultValidationHtmlAttributeProvider
{
    private readonly IModelMetadataProvider metadataProvider;

    public CustomValidationHtmlAttributeProvider(IOptions<MvcViewOptions> optionsAccessor, IModelMetadataProvider metadataProvider, ClientValidatorCache clientValidatorCache)
        : base(optionsAccessor, metadataProvider, clientValidatorCache)
    {
        this.metadataProvider = metadataProvider;
    }

    public override void AddValidationAttributes(ViewContext viewContext, ModelExplorer modelExplorer, IDictionary<string, string> attributes)
    {
        //base implimentation
        base.AddValidationAttributes(viewContext, modelExplorer, attributes);

        //re-create the validation context (since it's encapsulated inside of the base implimentation)
        var context = new ClientModelValidationContext(viewContext, modelExplorer.Metadata, metadataProvider, attributes);

        //Only proceed if it's the model you need to do custom logic for
        if (!(modelExplorer.Container.Model is MyViewModelClass model) || !modelExplorer.Metadata.PropertyName == "Myprop") return;

        //Do stuff!
        var validationAttributeAdapterProvider = viewContext.HttpContext.RequestServices.GetRequiredService<IValidationAttributeAdapterProvider>();

        if (model.Myprop)
        {
            var validationAdapter = (RequiredAttributeAdapter)validationAttributeAdapterProvider.GetAttributeAdapter(new RequiredAttribute(), null);
            validationAdapter.Attribute.ErrorMessage = "You not enter right stuff!";
            validationAdapter.AddValidation(context);
        }
    }
}

然后在ConfigureServices()

Startup中注册此课程
public void ConfigureServices(IServiceCollection services)
{
    //All your other DI stuff here

    //register the new ValidationHtmlAttributeProvider
    services.AddSingleton<ValidationHtmlAttributeProvider, PseudoAttributeValidationHtmlAttributeProvider>();
}

缺点是,如果你有多个模型你需要这样做,它真的很难实现。如果有人找到了更好的方法,我很乐意听到: - )

相关问题