Access model data in AddValidation method asp.net core custom validation

*爱你&永不变心* 提交于 2019-12-10 17:34:50

问题


I am following this example: https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation and trying to implement my own custom attribute for validation.

Now, the viewmodel has two fields that I wish to access from inside this method, so that they can be rendered with the "data-val" attributes. My question is, how can I get say a property called "Myprop" from context here? When I debug I can se the information under context.ActionContext.ViewData.Model but I have no way of getting that info other then during the debug when I use Visual Studio "quick watch" feature. The custom attributes are on properties that are on the 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:


I ran into a similar problem. The short answer is that you can't from there. You only have access to the metadata from there, not the actual model. The reason for this is that your model metadata and validation based on it are done on first time use, and then cached. So you'll never be able to change what validation rules to return based on the model via an attribute decorator.

If you need to dynamically decide which client side data-val-* attributes to render based off the instance/content of your model, you would need to inherit from DefaultValidationHtmlAttributeProvider, instead of using attributes, and override the AddValidationAttributes method. It's the only way I've found to do this so far. This is because inside of this method, you have access to the 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);
        }
    }
}

And then register this class in the ConfigureServices() of your Startup

public void ConfigureServices(IServiceCollection services)
{
    //All your other DI stuff here

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

The downside, is that if you have multiple models you need to do this for, it gets really ugly really fast. If anyone has found a better method, I'd love to hear it :-)



来源:https://stackoverflow.com/questions/45939333/access-model-data-in-addvalidation-method-asp-net-core-custom-validation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!