我正在开发一个使用Asp.Net MVC3的项目
在视图中我有@Html.ValidationSummary(true)
并且通常会产生
<div class="validation-summary-errors">
<ul>
<li>Something bad Happened!</li>
</ul>
</div>
如何将此ValidationSummary扩展到MyValidationSummary并生成如下所示的Html代码模板:
<div class="notification warning">
<span></span>
<div class="text"> <p>Something bad Happened!</p> </div>
</div>
答案 0 :(得分:131)
我的方法是使用自定义ValidationSummary.cshtml
:
@model ModelStateDictionary
@if(!Model.IsValid)
{
<div class="validation-summary-errors">
<ul>
@foreach (var modelError in
Model.SelectMany(keyValuePair => keyValuePair.Value.Errors))
{
<li>@modelError.ErrorMessage</li>
}
</ul>
</div>
}
将此部分视图放在您的共享文件夹中,并从您的代码中引用它:
@Html.Partial("_ValidationSummary", ViewData.ModelState);
这样你就可以完全控制你的HTML。
答案 1 :(得分:45)
此question详细说明了编写自定义验证摘要的过程。
修改强> 这将做你想要的:
public static class LinqExt
{
public static string MyValidationSummary(this HtmlHelper helper, string validationMessage="")
{
string retVal = "";
if (helper.ViewData.ModelState.IsValid)
return "";
retVal += "<div class='notification-warnings'><span>";
if (!String.IsNullOrEmpty(validationMessage))
retVal += helper.Encode(validationMessage);
retVal += "</span>";
retVal += "<div class='text'>";
foreach (var key in helper.ViewData.ModelState.Keys)
{
foreach(var err in helper.ViewData.ModelState[key].Errors)
retVal += "<p>" + helper.Encode(err.ErrorMessage) + "</p>";
}
retVal += "</div></div>";
return retVal.ToString();
}
}
代码是自我解释的;只需枚举模型状态错误并将错误包装在您选择的dom元素中。如果我使用它,则会出现错误:
<%:Html.MyValidationSummary()%>
它会在页面上显示html标签作为文本而不是呈现它。
<%=Html.MyValidationSummary()%>
这很好用。
答案 2 :(得分:22)
在flos's answer的基础上,我使它与微软的jQuery Unobtrusive Validation兼容,并添加了Bootstrap的3面板样式。这是新代码:
@model ModelStateDictionary
<div class="@(Html.ViewData.ModelState.IsValid ? "validation-summary-valid" : "validation-summary-errors") panel panel-danger"
data-valmsg-summary="true">
<div class="panel-heading">
Please, correct the following errors:
</div>
<div class="panel-body">
<ul>
@foreach(var modelError in Model.SelectMany(keyValuePair => keyValuePair.Value.Errors))
{
<li>@modelError.ErrorMessage</li>
}
</ul>
</div>
</div>
您可以在此详细阅读:
Creating a custom ASP.NET MVC @Html.ValidationSummary styled with Bootstrap 3 panel
我还创建了一个示例ASP.NET MVC项目,以显示此自定义ValidationSummary的运行情况。得到它:
https://github.com/leniel/AspNetMvcCustomHtmlValidationSummary
答案 3 :(得分:2)
只是在这里发布我的答案,因为它对我有用;)
我使用一个简单的扩展方法,它接受MvcHtmlString
并将其解码回HTML:
public static MvcHtmlString ToMvcHtmlString(this MvcHtmlString htmlString)
{
if (htmlString != null)
{
return new MvcHtmlString(HttpUtility.HtmlDecode(htmlString.ToString()));
}
return null;
}
为了探测这个问题,我将验证摘要帮助器添加到我的chstml中,如下所示:
@Html.ValidationSummary(true).ToMvcHtmlString()
这意味着,我可以将自定义HTML添加到我的验证摘要中:
ModelState.AddModelError("", "<p>This message can have html in it</p>");
我甚至可以在我的字段验证消息中添加自定义HTML:
ModelState.AddModelError("MyField", "<p>This message can have html in it</p>");
要使我的字段验证消息与HTML一起使用:
@Html.ValidationMessageFor(model => model.MyField).ToMvcHtmlString();
答案 4 :(得分:1)
添加相关样式:
.field-validation-error {
color: #b94a48;
}
.field-validation-valid {
display: none;
}
input.input-validation-error {
border: 1px solid #b94a48;
}
input[type="checkbox"].input-validation-error {
border: 0 none;
}
.validation-summary-errors {
color: #b94a48;
}
.validation-summary-valid {
display: none;
}
答案 5 :(得分:1)
我只需要为服务器端验证做一些类似的事情(比如检查文件内容),最后完全篡夺了@ Html.ValidationSummary并完成了相当不错的小工作。
我们有一个扩展Controller的BaseController类,我们在内部覆盖OnActionExecuting方法用于多种目的。 我们在ViewBag中为我们的错误消息创建一个新列表,并确保在任何操作运行之前初始化它。然后我们可以添加我们要显示的错误,并在屏幕上显示。
出于这个问题的目的,它看起来像这样。
AGPBI: {"kind":"simple","text":"UNEXPECTED TOP-LEVEL EXCEPTION:","sources":[{}]}
AGPBI: {"kind":"simple","text":"java.lang.RuntimeException: Exception parsing classes","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processClass(Main.java:752)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processFileBytes(Main.java:718)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.access$1200(Main.java:85)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main$FileBytesConsumer.processFileBytes(Main.java:1645)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processOne(Main.java:672)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processAllFiles(Main.java:542)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.runMultiDex(Main.java:366)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.run(Main.java:275)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.main(Main.java:245)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.Main.main(Main.java:106)","sources":[{}]}
AGPBI: {"kind":"simple","text":"Caused by: com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.parseClass(Main.java:764)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.access$1500(Main.java:85)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main$ClassParserTask.call(Main.java:1684)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processClass(Main.java:749)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\t... 12 more","sources":[{}]}
AGPBI: {"kind":"simple","text":"UNEXPECTED TOP-LEVEL EXCEPTION:","sources":[{}]}
AGPBI: {"kind":"simple","text":"java.lang.RuntimeException: Exception parsing classes","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processClass(Main.java:752)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processFileBytes(Main.java:718)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.access$1200(Main.java:85)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main$FileBytesConsumer.processFileBytes(Main.java:1645)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processOne(Main.java:672)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processAllFiles(Main.java:569)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.runMultiDex(Main.java:366)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.run(Main.java:275)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.main(Main.java:245)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.Main.main(Main.java:106)","sources":[{}]}
AGPBI: {"kind":"simple","text":"Caused by: com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.parseClass(Main.java:764)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.access$1500(Main.java:85)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main$ClassParserTask.call(Main.java:1684)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\tat com.android.dx.command.dexer.Main.processClass(Main.java:749)","sources":[{}]}
AGPBI: {"kind":"simple","text":"\t... 12 more","sources":[{}]}
AGPBI: {"kind":"simple","text":"2 errors; aborting","sources":[{}]}
然后在我们的_Layout.cshtml中添加以下@RenderBody()
public class BaseController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (ViewBag.ErrorsList == null)
{
ViewBag.ErrorsList = new List<string>();
}
}
}
现在每当我们想要显示为验证错误消息的服务器端发生错误时,我们只需将其添加到ViewBag.ErrorsList
@if(ViewBag.ErrorsList.Count > 0)
{
<div class="container margin-top-10 alert alert-danger">
<h3><i class="glyphicon glyphicon-warning-sign"></i></h3><br/>
@foreach (string error in @ViewBag.ErrorsList)
{
@error <br/>
}
</div>
@RenderBody()
}
瞧,一个自定义容器,用于服务器端验证错误消息,包含您想要的任何样式,错误的传递方式与ValidationSummary相同。
答案 6 :(得分:0)
我想只显示顶级消息,而不是其他内容。我们已经在下面的字段旁边进行了验证。使用@ Leniel-Macaferi解决方案解决这个问题,这是我使用jQuery验证的方法:(添加了style =“display:none;”)
<div class="@(Html.ViewData.ModelState.IsValid ? "validation-summary-valid" : "validation-summary-errors")"
data-valmsg-summary="true">
<div>
There are still some fields not filled in before we can submit this. Please correct.
</div>
<div style="display: none;">
<ul>
@foreach (var modelError in Model.SelectMany(keyValuePair => keyValuePair.Value.Errors))
{
<li>@modelError.ErrorMessage</li>
}
</ul>
</div>
</div>