ASP.NET MVC3自定义验证信息行为 [英] ASP.NET MVC3 Custom Validation Message Behaviour

查看:132
本文介绍了ASP.NET MVC3自定义验证信息行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我已经习惯使用的形式显示错误验证程序的asp.net web表单模型即将<跨度标题=用户名是必需的> *< / SPAN>

我很清楚MVC3验证器是如何工作的开箱即用,所以请没有更多的解释回答验证在MVC3是如何工作的,因为我是pretty确保我有一个钉。我试图做到的是有一个显示为span标记的标题验证错误消息,如图中的第一段。

我设法在MVC3复制本,但如果我做了它的方式遵循最佳实践我不知道。我想AP preciate任何输入,是否有更好的方法来完成同样的事情。这将是真正伟大的,如果它可以在不修改jquery.validate.unobtrusive.js来完成。

所以,我所做的是:

1)将验证消息为*
2)隐藏,而其有效的验证消息
3)增加了一个新的属性,以确定是否将消息添加为标题
4)增加了2线标记code到ONERROR检查是否显示在标题中的错误信息,如果是这样做的。

  @ Html.ValidationMessageFor(M = GT; m.Email,*,新{data_val_usetitle =真})[CSHTML][的CSS]点域验证,有效的{显示:无;}.js文件]功能的onError(错误,inputElement){//'这'是表单元素
            VAR容器= $(本).find([数据valmsg换='+ inputElement [0]。名称+']),
                取代= $ .parseJSON(container.attr(数据valmsg替换))!= =假,
                useTitle = $ .parseJSON(container.attr(数据-VAL-usetitle))==假的!; /* 新队 */            container.removeClass(现场验证,有效)addClass(现场验证错误)。
            error.data(unobtrusiveContainer容器);            如果(替换){
                container.empty();
                error.removeClass(输入验证错误)appendTo(集装箱)。
            }
            其他{
                如果(useTitle)container.attr(称号,error.text()); /* 新队 */
                error.hide();
            }
        }


解决方案

我觉得你所做的是最彻底的方法。周围有修改jquery.validate.unobtrusive.js因为MVC扩展不按动态发光的javascript的老同学asp.net方法没办法。

我刚刚完成创建我自己的自定义的验证扩展calld ValidationIconFor(),使单个图像上显示其标题设置为错误的消息,我已经用你的code以上的修改版本。

jquery.validate.unobtrusive.js

 函数的onError(错误,inputElement){//'这'是表单元素
    VAR容器= $(本).find([数据valmsg换='+ inputElement [0]。名称+']),
        取代= $ .parseJSON(container.attr(数据valmsg替换))!= =假,
        useTitle = $ .parseJSON(container.attr(数据-VAL-usetitle))==假的!;    container.removeClass(现场验证,有效)addClass(现场验证错误)。
    error.data(unobtrusiveContainer容器);    如果(替换){
        container.empty();
        如果(useTitle)
            container.attr(称号,error.text());
        其他
            error.removeClass(输入验证错误)appendTo(集装箱)。
    }
    其他{
        如果(useTitle)
            container.attr(称号,error.text());
        error.hide();
    }
}

ValidationExtensions.cs

 公共静态类ValidationExtensions
{
    私人静态字符串_resourceClassKey;    公共静态字符串ResourceClassKey
    {
        得到
        {
            返回_resourceClassKey?的String.Empty;
        }
        组
        {
            _resourceClassKey =价值;
        }
    }    私有静态FieldValidationMetadata ApplyFieldValidationMetadata(的HtmlHelper的HtmlHelper,ModelMetadata modelMetadata,串MODELNAME)
    {
        FormContext formContext = htmlHelper.ViewContext.FormContext;
        FieldValidationMetadata fieldMetadata = formContext.GetValidationMetadataForField(MODELNAME,真/ * * createIfNotFound /);        //写规则上下文对象
        IEnumerable的< ModelValidator>验证= ModelValidatorProviders.Providers.GetValidators(modelMetadata,htmlHelper.ViewContext);
        的foreach(在validators.SelectMany(V =&GT ModelClientValidationRule规则; v.GetClientValidationRules()))
        {
            fieldMetadata.ValidationRules.Add(规则);
        }        返回fieldMetadata;
    }    私人静态字符串GetInvalidPropertyValueResource(HttpContextBase的HttpContext)
    {
        字符串resourceValue = NULL;
        如果(String.IsNullOrEmpty(ResourceClassKey)及!&安培;!(HttpContext的= NULL))
        {
            //如果用户指定一个ResourceClassKey尝试加载他们指定的资源。
            //如果类键无效,一个异常将被抛出。
            //如果类键是有效的,但资源没有找到,则返回null,在这种
            //情况下,将回落到MVC默认的错误消息。
            resourceValue = httpContext.GetGlobalResourceObject(ResourceClassKey,InvalidPropertyValue,CultureInfo.CurrentUICulture)的字符串;
        }
        返回resourceValue? 值{0}是无效的。
    }    私人静态字符串GetUserErrorMessageOrDefault(HttpContextBase HttpContext的,ModelError错误的ModelState ModelState中)
    {
        如果(!String.IsNullOrEmpty(error.ErrorMessage))
        {
            返回error.ErrorMessage;
        }
        如果(ModelState中== NULL)
        {
            返回null;
        }        字符串attemptedValue =(modelState.Value!= NULL)? modelState.Value.AttemptedValue:空;
        返回的String.Format(CultureInfo.CurrentCulture,GetInvalidPropertyValueResource(HttpContext的),attemptedValue);
    }    【超级pressMessage(Microsoft.Design,CA1006:DoNotNestGenericTypesInMemberSignatures,理由=这是泛型类型的适当筑巢)]
    公共静态MvcHtmlString ValidationIconFor<的TModel,TProperty>(此的HtmlHelper<的TModel>的HtmlHelper,防爆pression< Func键<的TModel,TProperty>>前pression)
    {
        返回ValidationIconFor(的HtmlHelper,前pression,空/ * * validationMessage /,新RouteValueDictionary());
    }    【超级pressMessage(Microsoft.Design,CA1006:DoNotNestGenericTypesInMemberSignatures,理由=这是泛型类型的适当筑巢)]
    公共静态MvcHtmlString ValidationIconFor<的TModel,TProperty>(此的HtmlHelper<的TModel>的HtmlHelper,防爆pression< Func键<的TModel,TProperty>>前pression,串validationMessage)
    {
        返回ValidationIconFor(的HtmlHelper,前pression,validationMessage,新RouteValueDictionary());
    }    【超级pressMessage(Microsoft.Design,CA1006:DoNotNestGenericTypesInMemberSignatures,理由=这是泛型类型的适当筑巢)]
    公共静态MvcHtmlString ValidationIconFor<的TModel,TProperty>(此的HtmlHelper<的TModel>的HtmlHelper,防爆pression< Func键<的TModel,TProperty>>前pression,串validationMessage,对象htmlAttributes)
    {
        返回ValidationIconFor(的HtmlHelper,前pression,validationMessage,HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }    【超级pressMessage(Microsoft.Design,CA1006:DoNotNestGenericTypesInMemberSignatures,理由=这是泛型类型的适当筑巢)]
    公共静态MvcHtmlString ValidationIconFor<的TModel,TProperty>(此的HtmlHelper<的TModel>的HtmlHelper,防爆pression< Func键<的TModel,TProperty>>前pression,串validationMessage,IDictionary的<字符串对象> htmlAttributes)
    {
        返回ValidationMessageHelper(的HtmlHelper,
                                       ModelMetadata.FromLambdaEx pression(如pression,htmlHelper.ViewData)
                                       防爆pressionHelper.GetEx pressionText(如pression)
                                       validationMessage,
                                       htmlAttributes);
    }    【超级pressMessage(Microsoft.Globalization,CA1308:NormalizeStringsToUppercase,理由=标准化为小写是JavaScript和HTML值的共同要求)]
    私有静态MvcHtmlString ValidationMessageHelper(此的HtmlHelper的HtmlHelper,ModelMetadata modelMetadata,串前pression,串validationMessage,IDictionary的<字符串对象> htmlAttributes)
    {
        字符串MODELNAME = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(如pression);
        FormContext formContext = htmlHelper.ViewContext.FormContext;        如果(htmlHelper.ViewData.ModelState.ContainsKey(MODELNAME)及!&安培; formContext == NULL)
        {
            返回null;
        }        ModelState中的ModelState = htmlHelper.ViewData.ModelState [MODELNAME]
        ModelErrorCollection modelErrors =(ModelState中== NULL)?空:modelState.Errors;
        ModelError modelError =(((modelErrors == NULL)||(modelErrors.Count == 0))空:?!modelErrors.FirstOrDefault(M = GT; String.IsNullOrEmpty(m.ErrorMessage))?? modelErrors [0]) ;        如果(modelError == NULL和放大器;&安培; formContext == NULL)
        {
            返回null;
        }        TagBuilder建设者=新TagBuilder(IMG);
        builder.MergeAttributes(htmlAttributes);
        builder.AddCssClass((modelError = NULL)HtmlHelper.ValidationMessageCssClassName!?HtmlHelper.ValidationMessageValidCssClassName);        如果(!String.IsNullOrEmpty(validationMessage))
        {
            builder.Attributes.Add(称号,validationMessage);
        }
        否则,如果(modelError!= NULL)
        {
            builder.Attributes.Add(称号,GetUserErrorMessageOrDefault(htmlHelper.ViewContext.HttpContext,modelError,ModelState中));
        }        如果(formContext!= NULL)
        {
            布尔replaceValidationMessageContents = String.IsNullOrEmpty(validationMessage);            如果(htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
            {
                builder.MergeAttribute(数据valmsg换,MODELNAME);
                builder.MergeAttribute(数据valmsg替换,replaceValidationMessageContents.ToString()ToLowerInvariant());
                builder.MergeAttribute(数据-VAL-usetitle,真);
            }
            其他
            {
                FieldValidationMetadata fieldMetadata = ApplyFieldValidationMetadata(的HtmlHelper,modelMetadata,MODELNAME);
                //规则将已经被写入到元数据对象
                fieldMetadata.ReplaceValidationMessageContents = replaceValidationMessageContents; //只有在没有明确指定消息替换内容                //客户端验证总是需要一个ID
                builder.GenerateId(MODELNAME +_validationMessage);
                fieldMetadata.ValidationMessageId = builder.Attributes [ID];
            }
        }        返回builder.ToMvcHtmlString(TagRenderMode.Normal);
    }
}内部静态类TagBuilderExtensions
{
    内部静态MvcHtmlString ToMvcHtmlString(这TagBuilder tagBuilder,TagRenderMode renderMode)
    {
        返回新MvcHtmlString(tagBuilder.ToString(renderMode));
    }
}

Coming from the asp.net webforms model I'm used to using validators which display an error in the form <span title="Username is Required">*</span>.

I'm quite clear how the MVC3 validators work out of the box, so please no more answers explaining how validators work in MVC3 as I'm pretty sure I have that nailed. What I am trying to accomplish is have the validation error message showing as the title of the span tag as shown in the first paragraph.

I have managed to replicate this in MVC3 but am not sure if the way I have done it follows best practise. I would appreciate any input as to whether there is a better way to accomplish the same thing. It would be really great if it could be done without modifying jquery.validate.unobtrusive.js.

So what I have done is:

1) Set the validation message to "*" 2) Hidden the validation message while its valid 3) Added a new attribute to determine whether to add the message as the title 4) Added 2 lines of flagged code to onError to check whether to display the error message in the title, and if so to do so.

[.cshtml]    @Html.ValidationMessageFor(m => m.Email, "*", new { data_val_usetitle = "true" })

[.css]    .field-validation-valid {display:none;}

.js]        function onError(error, inputElement) {  // 'this' is the form element
            var container = $(this).find("[data-valmsg-for='" + inputElement[0].name + "']"),
                replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false,
                useTitle = $.parseJSON(container.attr("data-val-usetitle")) !== false; /* New Line */

            container.removeClass("field-validation-valid").addClass("field-validation-error");
            error.data("unobtrusiveContainer", container);

            if (replace) {
                container.empty();
                error.removeClass("input-validation-error").appendTo(container);
            }
            else {
                if (useTitle) container.attr("title", error.text()); /* New Line */
                error.hide();
            }
        }

解决方案

I think what you've done is the cleanest way. There is no way around modifying jquery.validate.unobtrusive.js because MVC extensions don't follow the old school asp.net methodology of emitting javascript on the fly.

I just finished creating my own custom validation extension calld ValidationIconFor() so that a single image is displayed with its title set to the error message and I've used a modified version of your code above.

jquery.validate.unobtrusive.js:

function onError(error, inputElement) {  // 'this' is the form element
    var container = $(this).find("[data-valmsg-for='" + inputElement[0].name + "']"),
        replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false,
        useTitle = $.parseJSON(container.attr("data-val-usetitle")) !== false;

    container.removeClass("field-validation-valid").addClass("field-validation-error");
    error.data("unobtrusiveContainer", container);

    if (replace) {
        container.empty();
        if (useTitle)
            container.attr("title", error.text());
        else
            error.removeClass("input-validation-error").appendTo(container);
    }
    else {
        if (useTitle)
            container.attr("title", error.text());
        error.hide();
    }
}

ValidationExtensions.cs:

public static class ValidationExtensions
{
    private static string _resourceClassKey;

    public static string ResourceClassKey
    {
        get
        {
            return _resourceClassKey ?? String.Empty;
        }
        set
        {
            _resourceClassKey = value;
        }
    }

    private static FieldValidationMetadata ApplyFieldValidationMetadata(HtmlHelper htmlHelper, ModelMetadata modelMetadata, string modelName)
    {
        FormContext formContext = htmlHelper.ViewContext.FormContext;
        FieldValidationMetadata fieldMetadata = formContext.GetValidationMetadataForField(modelName, true /* createIfNotFound */);

        // write rules to context object
        IEnumerable<ModelValidator> validators = ModelValidatorProviders.Providers.GetValidators(modelMetadata, htmlHelper.ViewContext);
        foreach (ModelClientValidationRule rule in validators.SelectMany(v => v.GetClientValidationRules()))
        {
            fieldMetadata.ValidationRules.Add(rule);
        }

        return fieldMetadata;
    }

    private static string GetInvalidPropertyValueResource(HttpContextBase httpContext)
    {
        string resourceValue = null;
        if (!String.IsNullOrEmpty(ResourceClassKey) && (httpContext != null))
        {
            // If the user specified a ResourceClassKey try to load the resource they specified.
            // If the class key is invalid, an exception will be thrown.
            // If the class key is valid but the resource is not found, it returns null, in which
            // case it will fall back to the MVC default error message.
            resourceValue = httpContext.GetGlobalResourceObject(ResourceClassKey, "InvalidPropertyValue", CultureInfo.CurrentUICulture) as string;
        }
        return resourceValue ?? "The value '{0}' is invalid.";
    }

    private static string GetUserErrorMessageOrDefault(HttpContextBase httpContext, ModelError error, ModelState modelState)
    {
        if (!String.IsNullOrEmpty(error.ErrorMessage))
        {
            return error.ErrorMessage;
        }
        if (modelState == null)
        {
            return null;
        }

        string attemptedValue = (modelState.Value != null) ? modelState.Value.AttemptedValue : null;
        return String.Format(CultureInfo.CurrentCulture, GetInvalidPropertyValueResource(httpContext), attemptedValue);
    }

    [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
    public static MvcHtmlString ValidationIconFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        return ValidationIconFor(htmlHelper, expression, null /* validationMessage */, new RouteValueDictionary());
    }

    [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
    public static MvcHtmlString ValidationIconFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage)
    {
        return ValidationIconFor(htmlHelper, expression, validationMessage, new RouteValueDictionary());
    }

    [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
    public static MvcHtmlString ValidationIconFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, object htmlAttributes)
    {
        return ValidationIconFor(htmlHelper, expression, validationMessage, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
    public static MvcHtmlString ValidationIconFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, IDictionary<string, object> htmlAttributes)
    {
        return ValidationMessageHelper(htmlHelper,
                                       ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData),
                                       ExpressionHelper.GetExpressionText(expression),
                                       validationMessage,
                                       htmlAttributes);
    }

    [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Normalization to lowercase is a common requirement for JavaScript and HTML values")]
    private static MvcHtmlString ValidationMessageHelper(this HtmlHelper htmlHelper, ModelMetadata modelMetadata, string expression, string validationMessage, IDictionary<string, object> htmlAttributes)
    {
        string modelName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(expression);
        FormContext formContext = htmlHelper.ViewContext.FormContext;

        if (!htmlHelper.ViewData.ModelState.ContainsKey(modelName) && formContext == null)
        {
            return null;
        }

        ModelState modelState = htmlHelper.ViewData.ModelState[modelName];
        ModelErrorCollection modelErrors = (modelState == null) ? null : modelState.Errors;
        ModelError modelError = (((modelErrors == null) || (modelErrors.Count == 0)) ? null : modelErrors.FirstOrDefault(m => !String.IsNullOrEmpty(m.ErrorMessage)) ?? modelErrors[0]);

        if (modelError == null && formContext == null)
        {
            return null;
        }

        TagBuilder builder = new TagBuilder("img");
        builder.MergeAttributes(htmlAttributes);
        builder.AddCssClass((modelError != null) ? HtmlHelper.ValidationMessageCssClassName : HtmlHelper.ValidationMessageValidCssClassName);

        if (!String.IsNullOrEmpty(validationMessage))
        {
            builder.Attributes.Add("title", validationMessage);
        }
        else if (modelError != null)
        {
            builder.Attributes.Add("title", GetUserErrorMessageOrDefault(htmlHelper.ViewContext.HttpContext, modelError, modelState));
        }

        if (formContext != null)
        {
            bool replaceValidationMessageContents = String.IsNullOrEmpty(validationMessage);

            if (htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
            {
                builder.MergeAttribute("data-valmsg-for", modelName);
                builder.MergeAttribute("data-valmsg-replace", replaceValidationMessageContents.ToString().ToLowerInvariant());
                builder.MergeAttribute("data-val-usetitle", "true");
            }
            else
            {
                FieldValidationMetadata fieldMetadata = ApplyFieldValidationMetadata(htmlHelper, modelMetadata, modelName);
                // rules will already have been written to the metadata object
                fieldMetadata.ReplaceValidationMessageContents = replaceValidationMessageContents; // only replace contents if no explicit message was specified

                // client validation always requires an ID
                builder.GenerateId(modelName + "_validationMessage");
                fieldMetadata.ValidationMessageId = builder.Attributes["id"];
            }
        }

        return builder.ToMvcHtmlString(TagRenderMode.Normal);
    }
}

internal static class TagBuilderExtensions
{
    internal static MvcHtmlString ToMvcHtmlString(this TagBuilder tagBuilder, TagRenderMode renderMode)
    {
        return new MvcHtmlString(tagBuilder.ToString(renderMode));
    }
}

这篇关于ASP.NET MVC3自定义验证信息行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆