0

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

在过滤器属性内部 - 为了仅在所需页面中设置验证器,我正在这样做(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 2.MoveNext() +578 System.Linq.d1.MoveNext() +643
System.Linq.<SelectManyIterator>d__14

_14 1 clientRules, IDictionary 2 htmlAttributes) +1050 System.Web.Mvc.Html.InputExtensions.TextBoxFor(HtmlHelper 1 表达式,字符串格式,IDictionary`2 htmlAttributes) +202 ASP._Page_Views_Home_Index_cshtml.Execute() 在 c:\interpub\wwwroot\Views\Home\Index .cshtml:472.MoveNext() +578
System.Web.Mvc.UnobtrusiveValidationAttributesGenerator.GetValidationAttributes(IEnumerable
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

1 htmlHelper, Expression

该属性的完整源代码为:

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)
        {
            // ...
        }
    }

我做对了吗?我的目标(要明确一点)是仅在修饰的操作中启用验证器提供程序,而在其他操作中它不应该存在于验证器提供程序集合中。

谢谢!

4

1 回答 1

1

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

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

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

这应该可以解决问题。

于 2013-08-07T21:35:16.050 回答