Razor 用于验证消息的自定义HTML帮助程序

Razor 用于验证消息的自定义HTML帮助程序,razor,asp.net-core,Razor,Asp.net Core,我为验证消息的输出编写了一个定制的HTTML助手标记。它工作正常,但它始终存在 @Html.MyValidationMsg(m=>m.FirstName) public static IHtmlContent MyValidationMsg(此IHTML帮助器,表达式) { MemberExpression MemberExpression=expression.Body作为MemberExpression; var reqAttrib=memberExpression.Member .GetC

我为验证消息的输出编写了一个定制的HTTML助手标记。它工作正常,但它始终存在

@Html.MyValidationMsg(m=>m.FirstName)

public static IHtmlContent MyValidationMsg(此IHTML帮助器,表达式)
{
MemberExpression MemberExpression=expression.Body作为MemberExpression;
var reqAttrib=memberExpression.Member
.GetCustomAttributes(typeof(RequiredAttribute),false)
.Cast()
.SingleOrDefault();
var displayAttrib=memberExpression.Member
.GetCustomAttributes(typeof(DisplayAttribute),false)
.Cast()
.SingleOrDefault();
var errMsg=reqAttrib.ErrorMessage??displayAttrib.Name+“是必需的。”;
var content=new-HtmlContentBuilder()
.AppendHtml(“”)
.AppendHtml(“”)
.AppendHtml(“”)
.AppendHtml(“”)
.AppendHtml(“”)
.AppendHtml(“”)
.AppendHtml(“”)
.AppendHtml(“”)
.AppendHtml(“”)
.AppendHtml(“”)
.AppendHtml(errMsg)
.AppendHtml(“”)
.附录HTML(“”);
返回内容;
}
如何在Razor页面的初始加载时隐藏它,以及在字段无效时使其显示


感谢您的帮助

有两个原因导致该消息总是出现

  • 正如@Sonal Borkar所说,第一个原因是您的
    var errMsg=reqAttrib.erromessage??displayAttrib.Name+“是必需的。”
    使其返回一些值,即使根本没有记录
    [required]
    属性

    但不要将其更改为
    var errMsg=reqAttrib.ErrorMessage!=无效的displayAttrib.Name+“是必需的。”
    ,因为
    reqAttrib
    可能是
    null
    。相反,您可以按以下方式更改代码:

    var errMsg = reqAttrib==null ? 
        "": 
        reqAttrib?.ErrorMessage ?? displayName + " is required.";
    
        public static IHtmlContent MyValidationMsg<TModel, TProperty>(this IHtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
        {
            MemberExpression memberExpression = expression.Body as MemberExpression;
    
            var reqAttrib = memberExpression.Member
                        .GetCustomAttributes(typeof(RequiredAttribute), false)
                        .Cast<RequiredAttribute>()
                        .SingleOrDefault();
    
            var contentBuilder = new HtmlContentBuilder();
            // if the current property has no [Required] attribute, there's no need to display required message 
            if(reqAttrib == null ){return contentBuilder; }
    
    
            // check the value of current property 
            var compiled = expression.Compile();
            var model = (TModel) helper.ViewData.Model ;
            if(model == null){ 
                throw new Exception("No Model associated with the view !"); 
            }
            var propValue = (TProperty) compiled.Invoke(model);        
            // I just test nullable props here, you might custom it to fulfill your requirements, eg : whether the length of string matches
            if(propValue != null){ return contentBuilder; }
    
    
            var member = memberExpression.Member;
            var displayName= member
                        .GetCustomAttributes(typeof(DisplayAttribute), false)
                        .Cast<DisplayAttribute>()
                        .SingleOrDefault()
                        ?.Name             // might be null
                        ?? member.Name;    // fall back
            var errMsg = reqAttrib==null ? 
                "": 
                reqAttrib?.ErrorMessage ?? displayName + " is required.";
            if(String.IsNullOrEmpty(errMsg)){ return contentBuilder; }
            return contentBuilder
                    .AppendHtml("<div class=\"rvt-inline-alert rvt-inline-alert--standalone rvt-inline-alert--danger\">")
                    .AppendHtml("<span class=\"rvt-inline-alert__icon\">")
                    .AppendHtml("<svg aria-hidden=\"true\" xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\">")
                    .AppendHtml("<g fill=\"currentColor\">")
                    .AppendHtml("<path d=\"M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0ZM8,14a6,6,0,1,1,6-6A6,6,0,0,1,8,14Z\" />")
                    .AppendHtml("<path d=\"M10.83,5.17a1,1,0,0,0-1.41,0L8,6.59,6.59,5.17A1,1,0,0,0,5.17,6.59L6.59,8,5.17,9.41a1,1,0,1,0,1.41,1.41L8,9.41l1.41,1.41a1,1,0,0,0,1.41-1.41L9.41,8l1.41-1.41A1,1,0,0,0,10.83,5.17Z\"/>")
                    .AppendHtml("</g>")
                    .AppendHtml("</svg>")
                    .AppendHtml("</span>")
                    .AppendHtml("<span class=\"rvt-inline-alert__message\" role=\"alert\" id=\"radio-list-message\">")
                    .AppendHtml(errMsg)
                    .AppendHtml("</span>")
                    .AppendHtml("</div>");
        }
    
  • 其次,您忘了检查当前属性是否已经有值。假设我们有一个属性修饰了
    [Required]
    属性,并且它确实分配了一个值,那么我们不应该显示所需的消息,如“xxx需要”

  • 此外,您的代码中还存在其他一些
    null对象引用的bug

        var displayAttrib = memberExpression.Member
                .GetCustomAttributes(typeof(DisplayAttribute), false)    
                .Cast<DisplayAttribute>()
                .SingleOrDefault();                                      
    
        var errMsg = reqAttrib.ErrorMessage ?? displayAttrib.Name + " is required.";
    

    非常感谢@itminus花时间让我走上了正确的道路

    我最终完全是为了重写jquery.validate而划出了这条路径。还使用javascript/jquery操纵DOM以获得所需的结果

    错误消息的所需输出:

    <div class="rvt-inline-alert rvt-inline-alert--danger">
        <span class="rvt-inline-alert__icon">
            <svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
                <g fill="currentColor">
                    <path d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0ZM8,14a6,6,0,1,1,6-6A6,6,0,0,1,8,14Z"/>
                    <path d="M10.83,5.17a1,1,0,0,0-1.41,0L8,6.59,6.59,5.17A1,1,0,0,0,5.17,6.59L6.59,8,5.17,9.41a1,1,0,1,0,1.41,1.41L8,9.41l1.41,1.41a1,1,0,0,0,1.41-1.41L9.41,8l1.41-1.41A1,1,0,0,0,10.83,5.17Z"/>
                </g>
            </svg>
        </span>
        <span class="rvt-inline-alert__message" role="alert">Your Name is required.</span>
    </div>
    

    我猜var errMsg=reqAttrib.ErrorMessage??displayAttrib.Name+“是必需的。”;这将始终返回一些值。尝试下面的var errMsg=reqAttrib.ErrorMessage!=无效的displayAttrib.Name+“是必需的。”:“”;然后用JavaScript返回内容,如果ErrMSG.List.0是答案,但是尝试在进行这条路径之前考虑FuffTrimeValue:你用我的代码来窃取bug,“ITMIUS?!?!!!!!!!!!!你一定是疯了!!:)我不太了解表达式和compile()的情况。我需要更多的了解。然而,我并没有试图改变字段的验证方式。
    [Required]
    的默认例程对我来说很好。我只是想定制从
    生成的HTML输出——有更好的方法吗?一如既往——谢谢@Fraze我以为你在使用
    @(Html.MyValidationMsg(m=>lambda\u来获取你的属性))的
    MyValidationMsg()
    。因此,如果属性A已经有一个值,则无需显示“A是必需的”。@Fraze这里的
    编译
    调用
    用于调用表达式,以便我们可以获得属性的实际值。您是正确的。我使用的是这样的:
    @Html.MyValidationMsg(m=>User.Name)
    。这里我唯一的目标是将validator助手的HTML输出更改为代码中MyValidationMsg的输出。如果有更好的方法来控制HTML输出,那么也许我只是做错了?@Fraze可能做得不错!awesome
    $.validator.unobtrusive.options=设置
    
    <div class="rvt-inline-alert rvt-inline-alert--danger">
        <span class="rvt-inline-alert__icon">
            <svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true">
                <g fill="currentColor">
                    <path d="M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0ZM8,14a6,6,0,1,1,6-6A6,6,0,0,1,8,14Z"/>
                    <path d="M10.83,5.17a1,1,0,0,0-1.41,0L8,6.59,6.59,5.17A1,1,0,0,0,5.17,6.59L6.59,8,5.17,9.41a1,1,0,1,0,1.41,1.41L8,9.41l1.41,1.41a1,1,0,0,0,1.41-1.41L9.41,8l1.41-1.41A1,1,0,0,0,10.83,5.17Z"/>
                </g>
            </svg>
        </span>
        <span class="rvt-inline-alert__message" role="alert">Your Name is required.</span>
    </div>
    
    <script type="text/javascript">
        var settings = {
            errorElement: "span",
            errorClass: "rvt-validation-danger", //around textbox on error
            errorPlacement: function (error, element) {
    
                var avg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
                avg.setAttribute("width", "16");
                avg.setAttribute("height", "16");
                avg.setAttribute("viewBox", "0 0 16 16");
                avg.setAttribute("aria-hidden", "true");
    
                var g = document.createElement("g");
                g.setAttribute("fill", "currentColor");
    
                var p1 = document.createElement("path");
                p1.setAttribute("d", "M8,0a8,8,0,1,0,8,8A8,8,0,0,0,8,0ZM8,14a6,6,0,1,1,6-6A6,6,0,0,1,8,14Z");
    
                var p2 = document.createElement("path");
                p2.setAttribute("d", "M10.83,5.17a1,1,0,0,0-1.41,0L8,6.59,6.59,5.17A1,1,0,0,0,5.17,6.59L6.59,8,5.17,9.41a1,1,0,1,0,1.41,1.41L8,9.41l1.41,1.41a1,1,0,0,0,1.41-1.41L9.41,8l1.41-1.41A1,1,0,0,0,10.83,5.17Z");
    
                g.appendChild(p1);
                g.appendChild(p2);
                avg.appendChild(g);   
    
                var spanIcon = document.createElement("span");
                spanIcon.setAttribute("class", "rvt-inline-alert__icon");
                spanIcon.innerHTML += avg.outerHTML;
    
                var spanMsg = document.createElement("span");
                spanMsg.setAttribute("class", "rvt-inline-alert__message");
                spanMsg.setAttribute("role", "alert");
                spanMsg.innerHTML += error[0].innerHTML;           
    
                var c = document.createElement("div");
                c.setAttribute("class", "rvt-inline-alert rvt-inline-alert--danger");
                c.innerHTML += spanIcon.outerHTML + spanMsg.outerHTML;
                error.replaceWith(c);
            }
        };
    
        $.validator.unobtrusive.options = settings;
    </script>