ModelValidatorProviders基于页面

时间:2013-08-07 16:10:05

标签: asp.net-mvc-4

我创建了自定义ModelValidatorProvider,它只能在站点中的某些特定操作中处于活动状态。 为了做到这一点,我创建了一个自定义属性,扩展了“FilterAttribute”,并在OnAuthorize中设置了验证器。

在filter属性中 - 为了仅在所需页面中设置验证器,我这样做(PostAttributeModelValidatorProvider是验证器提供者)。

        var provider = (from p in ModelValidatorProviders.Providers
                        where p is PostAttributeModelValidatorProvider
                        select p).FirstOrDefault();
        if (provider != null)
        {
            ModelValidatorProviders.Providers.Remove(provider);
        }

        if (EnableAttributesValidation)
        {
            ModelValidatorProviders.Providers.Add(new PostAttributeModelValidatorProvider() { BypassRequiredFieldsValidation = this.BypassRequiredFieldsValidation });
        }

我面临的问题是有时候(我无法确切地发现它何时出错 - 但我相信当两次使用尝试访问网站或触发此操作的页面时会发生这种情况)存在冲突在我正在做的删除和添加操作之间,因为那 - 我收到了一个错误:

  

索引超出了数组的范围。

相关的堆栈跟踪是:

  

[IndexOutOfRangeException:索引超出了数组的范围。]   System.Collections.Generic.Enumerator.MoveNext()+112
  System.Linq.d_ 71 1.MoveNext() +643
System.Linq.<SelectManyIterator>d__14
2.MoveNext()+ 578   System.Linq.d
_14 2.MoveNext() +578
System.Web.Mvc.UnobtrusiveValidationAttributesGenerator.GetValidationAttributes(IEnumerable
1   clientRules,IDictionary 2 results) +440
System.Web.Mvc.HtmlHelper.GetUnobtrusiveValidationAttributes(String name, ModelMetadata metadata) +280
System.Web.Mvc.Html.InputExtensions.InputHelper(HtmlHelper htmlHelper, InputType inputType, ModelMetadata metadata, String name, Object value, Boolean useViewData, Boolean isChecked, Boolean setId, Boolean isExplicitValue, String format, IDictionary
2 htmlAttributes)+1050
  System.Web.Mvc.Html.InputExtensions.TextBoxFor(HtmlHelper 1 htmlHelper, Expression 1表达式,字符串格式,IDictionary`2   htmlAttributes)+202 ASP._Page_Views_Home_Index_cshtml.Execute()in   C:\ interpub \ wwwroot的\视图\主页\ Index.cshtml:47

该属性的完整源代码是:

public class InitializePostAttributesResolverAttribute : FilterAttribute, IAuthorizationFilter
{
    public InitializePostAttributesResolverAttribute()
        : this(true, false)
    {

    }

    public InitializePostAttributesResolverAttribute(bool enableAttributesValidation, bool bypassRequiredFieldsValidation)
    {
        this.EnableAttributesValidation = enableAttributesValidation;
        this.BypassRequiredFieldsValidation = bypassRequiredFieldsValidation;
    }

    /// <summary>
    /// Should the attributes input be validated
    /// </summary>
    public bool EnableAttributesValidation { get; set; }


    /// <summary>
    /// Gets or sets the value whether we should bypass the required fields validation
    /// </summary>
    /// <remarks>
    /// This value should be set to true only if you would like to skip on required fields validation.
    /// We should use this value when searching.
    /// </remarks>
    public bool BypassRequiredFieldsValidation { get; set; }

    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        ModelMetadataProviders.Current = new PostAttributeModelMetadataProvider();

        var provider = (from p in ModelValidatorProviders.Providers
                        where p is PostAttributeModelValidatorProvider
                        select p).FirstOrDefault();
        if (provider != null)
        {
            ModelValidatorProviders.Providers.Remove(provider);
        }

        if (EnableAttributesValidation)
        {
            ModelValidatorProviders.Providers.Add(new PostAttributeModelValidatorProvider() { BypassRequiredFieldsValidation = this.BypassRequiredFieldsValidation });
        }
    }
}

并为其使用示例

    //
    // POST: /Post/Publish/5

    [InitializePostAttributesResolver]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Publish(PublishViewModel model)
    {
        if (ModelState.IsValid)
        {
            // ...
        }
    }

我做得对吗?我的目标(只是为了清楚)是仅在装饰的动作中启用验证器提供者,而在其他操作中它不应该存在于验证器提供者集合中。

谢谢!

1 个答案:

答案 0 :(得分:1)

ModelValidatorProviders.Providers是一个静态属性,因此无法以这种方式实现线程安全。

相反,您应该在启动时将自定义ModelValidatorProvider添加到列表中,但是使提供程序依赖于模型上的特定属性或其属性(与DataAnnotation属性相同的逻辑)。

[MyCustomValidation]
public class MyModel
{
     public string MyProperty { get; set; }
}

这应该可以解决问题。