C# mvc3 ValidationSummary排除属性错误IValidatableObject
我的模型(类A)有一个类型为b的属性(称为b),实现了C# mvc3 ValidationSummary排除属性错误IValidatableObject,c#,asp.net-mvc-3,validationsummary,C#,Asp.net Mvc 3,Validationsummary,我的模型(类A)有一个类型为b的属性(称为b),实现了IValidatableObject 视图已获得@Html.ValidationSummary(true) 在验证摘要中,我希望排除与属性相关的错误。 在类B中,IValidatableObject实现正在返回没有成员名的ValidationResult 但是由于类B是类a上的属性,因此不会显示来自IValidatableObject的类B有效性错误 如何显示B类非属性验证错误?挖掘MVC3的源代码并进行编辑以允许包含属性 @Html.Val
IValidatableObject
视图已获得@Html.ValidationSummary(true)
在验证摘要中,我希望排除与属性相关的错误。
在类B中,IValidatableObject
实现正在返回没有成员名的ValidationResult
但是由于类B是类a上的属性,因此不会显示来自IValidatableObject
的类B有效性错误
如何显示B类非属性验证错误?挖掘MVC3的源代码并进行编辑以允许包含属性
@Html.ValidationSummary(new [] { "PropertyName" })
将包括名为PropertyName的属性
@Html.ValidationSummary(new [] { "ArrayName[]" })
将包括属性ArrayName[0]、ArrayName[1]等
@Html.ValidationSummary(new [] { "ArrayName[]", "PropertyName" })
两者都包括在内
public static MvcHtmlString ValidationSummary(this HtmlHelper htmlHelper, string[] includePropertyErrors)
{
return ValidationSummary(htmlHelper, includePropertyErrors, null, null);
}
public static MvcHtmlString ValidationSummary(this HtmlHelper htmlHelper, string[] includePropertyErrors, string message)
{
return ValidationSummary(htmlHelper, includePropertyErrors, message, null);
}
public static MvcHtmlString ValidationSummary(this HtmlHelper htmlHelper, string[] includePropertyErrors, string message, IDictionary<string, object> htmlAttributes)
{
if (htmlHelper == null)
{
throw new ArgumentNullException("htmlHelper");
}
FormContext formContext = htmlHelper.ViewContext.ClientValidationEnabled ? htmlHelper.ViewContext.FormContext : null;
if (htmlHelper.ViewData.ModelState.IsValid)
{
if (formContext == null)
{ // No client side validation
return null;
}
// TODO: This isn't really about unobtrusive; can we fix up non-unobtrusive to get rid of this, too?
if (htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
{ // No client-side updates
return null;
}
}
string messageSpan;
if (!string.IsNullOrEmpty(message))
{
TagBuilder spanTag = new TagBuilder("span");
spanTag.SetInnerText(message);
messageSpan = spanTag.ToString(TagRenderMode.Normal) + Environment.NewLine;
}
else
{
messageSpan = null;
}
StringBuilder htmlSummary = new StringBuilder();
TagBuilder unorderedList = new TagBuilder("ul");
IEnumerable<ModelState> modelStates = from ms in htmlHelper.ViewData.ModelState
where ms.Key == htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix ||
includePropertyErrors.Any(property =>
{
string prefixedProperty = string.IsNullOrEmpty(htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix) ? property : htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix + "." + property;
if (property.EndsWith("[]"))
{
return prefixedProperty.Substring(0, property.Length - 2) == Regex.Replace(ms.Key, @"\[[^\]]+\]", string.Empty);
}
else
{
return property == ms.Key;
}
})
select ms.Value;
if (modelStates != null)
{
foreach (ModelState modelState in modelStates)
{
foreach (ModelError modelError in modelState.Errors)
{
string errorText = GetUserErrorMessageOrDefault(htmlHelper.ViewContext.HttpContext, modelError);
if (!String.IsNullOrEmpty(errorText))
{
TagBuilder listItem = new TagBuilder("li");
listItem.SetInnerText(errorText);
htmlSummary.AppendLine(listItem.ToString(TagRenderMode.Normal));
}
}
}
}
if (htmlSummary.Length == 0)
{
htmlSummary.AppendLine(@"<li style=""display:none""></li>");
}
unorderedList.InnerHtml = htmlSummary.ToString();
TagBuilder divBuilder = new TagBuilder("div");
divBuilder.MergeAttributes(htmlAttributes);
divBuilder.AddCssClass((htmlHelper.ViewData.ModelState.IsValid) ? HtmlHelper.ValidationSummaryValidCssClassName : HtmlHelper.ValidationSummaryCssClassName);
divBuilder.InnerHtml = messageSpan + unorderedList.ToString(TagRenderMode.Normal);
if (formContext != null)
{
if (!htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
{
// client val summaries need an ID
divBuilder.GenerateId("validationSummary");
formContext.ValidationSummaryId = divBuilder.Attributes["id"];
formContext.ReplaceValidationSummary = false;
}
}
return new MvcHtmlString(divBuilder.ToString(TagRenderMode.Normal));
}
private static string GetUserErrorMessageOrDefault(HttpContextBase httpContext, ModelError error)
{
return string.IsNullOrEmpty(error.ErrorMessage) ? null : error.ErrorMessage;
}
public static MvcHtmlString ValidationSummary(此HtmlHelper HtmlHelper,字符串[]包含属性错误)
{
返回ValidationSummary(htmlHelper,includePropertyErrors,null,null);
}
公共静态MvcHtmlString验证摘要(此HtmlHelper HtmlHelper,字符串[]包括属性错误,字符串消息)
{
返回ValidationSummary(htmlHelper,includePropertyErrors,message,null);
}
公共静态MvcHtmlString验证摘要(此HtmlHelper HtmlHelper,字符串[]包括属性错误、字符串消息、IDictionary HtmlAttribute)
{
如果(htmlHelper==null)
{
抛出新ArgumentNullException(“htmlHelper”);
}
FormContext FormContext=htmlHelper.ViewContext.ClientValidationEnabled?htmlHelper.ViewContext.FormContext:null;
if(htmlHelper.ViewData.ModelState.IsValid)
{
if(formContext==null)
{//没有客户端验证
返回null;
}
//TODO:这并不是关于不引人注目的问题,我们能把不引人注目的问题也解决掉吗?
if(htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
{//没有客户端更新
返回null;
}
}
字符串消息跨度;
如果(!string.IsNullOrEmpty(消息))
{
标记生成器span标记=新标记生成器(“span”);
spanTag.SetInnerText(消息);
messageSpan=spanTag.ToString(TagRenderMode.Normal)+Environment.NewLine;
}
其他的
{
messageSpan=null;
}
StringBuilder htmlSummary=新建StringBuilder();
标记生成器无序列表=新标记生成器(“ul”);
IEnumerable ModelState=来自htmlHelper.ViewData.ModelState中的ms
其中ms.Key==htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix||
includePropertyErrors.Any(属性=>
{
string prefixedProperty=string.IsNullOrEmpty(htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix)?属性:htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix+“+”+属性;
if(property.EndsWith(“[]”)
{
返回prefixedProperty.Substring(0,property.Length-2)=Regex.Replace(ms.Key,@“\[^\]]+\]”,string.Empty);
}
其他的
{
返回属性==ms.Key;
}
})
选择ms.Value;
if(modelStates!=null)
{
foreach(ModelState中的ModelState)
{
foreach(modelState.Errors中的ModelError ModelError)
{
字符串errorText=GetUserErrorMessageOrDefault(htmlHelper.ViewContext.HttpContext,modelError);
如果(!String.IsNullOrEmpty(errorText))
{
标记生成器列表项=新标记生成器(“li”);
listItem.SetInnerText(errorText);
htmlSummary.AppendLine(listItem.ToString(TagRenderMode.Normal));
}
}
}
}
if(htmlSummary.Length==0)
{
htmlSummary.AppendLine(@“”;
}
unorderedList.InnerHtml=htmlSummary.ToString();
标记生成器divBuilder=新标记生成器(“div”);
divBuilder.MergeAttributes(HtmlatAttributes);
divBuilder.AddCssClass((htmlHelper.ViewData.ModelState.IsValid)?htmlHelper.ValidationSummaryValidCssClassName:htmlHelper.ValidationSummaryCssClassName);
divBuilder.InnerHtml=messageSpan+unorderedList.ToString(TagRenderMode.Normal);
if(formContext!=null)
{
如果(!htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
{
//客户val摘要需要一个ID
divBuilder.GenerateId(“validationSummary”);
formContext.ValidationSummaryId=divBuilder.Attributes[“id”];
formContext.ReplaceValidationSummary=false;
}
}
返回新的MvcHtmlString(divBuilder.ToString(TagRenderMode.Normal));
}
私有静态字符串GetUserErrorMessageOrDefault(HttpContextBase httpContext,ModelError错误)
{
返回字符串.IsNullOrEmpty(error.ErrorMessage)?null:error.ErrorMessage;
}
让我们从我们知道的开始:
如描述所示,如果我们有我们的模型:
型号A:
public class A
{
public B ModelB { get; set; }
}
public class B : IValidatableObject
{
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
List<ValidationResult> errors = new List<ValidationResult>();
if (string.IsNullOrEmpty(Name)) {
errors.Add(new ValidationResult("Please enter your name"));
}
return errors;
}
}
@model A
@Html.ValidationSummary(true)
@using (Html.BeginForm())
{
@Html.EditorFor(model => model.ModelB.Name)
<input type="submit" value="submit" />
}
型号B:
public class A
{
public B ModelB { get; set; }
}
public class B : IValidatableObject
{
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
List<ValidationResult> errors = new List<ValidationResult>();
if (string.IsNullOrEmpty(Name)) {
errors.Add(new ValidationResult("Please enter your name"));
}
return errors;
}
}
@model A
@Html.ValidationSummary(true)
@using (Html.BeginForm())
{
@Html.EditorFor(model => model.ModelB.Name)
<input type="submit" value="submit" />
}
然后,当绑定到A
模型时,DefaultModelBinder
将查找名为ModelB.Name
的属性,它将成功地找到并绑定到该属性
但是,由DefaultModelBinder
对A
模型执行的模型验证将调用为模型
@Html.EditorFor(model => model.ModelB, null, "")
<input class="text-box single-line" id="Name" name="Name" type="text" value="" />
[HttpPost]
public ActionResult Index(A modelA, B modelB)
{
modelA.ModelB = modelB;
if (ModelState.IsValid)
{
return RedirectToAction("NextAction");
}
return View();
}
@Html.EditorFor(model => model.Name, null, "modelA.Name")
[Promote("prop1.SubProp1 Prop2")]
public ActionResult MyMethod( ...
public class PromoteAttribute : ActionFilterAttribute
{
string[] expressions;
public PromoteAttribute(string toPromote)
{
expressions = toPromote.Split(' ');
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
ModelStateDictionary modelState=filterContext.Controller.ViewData.ModelState;
foreach(var x in expressions)
{
if (modelState.ContainsKey(x))
{
var entry = modelState[x];
if (entry.Errors.Count == 0) continue;
foreach (var error in entry.Errors) modelState.AddModelError("", error.ErrorMessage);
}
}
}
}
public class ClassA
{
[Required]
public string Name { get; set; }
public ClassB CBProp { get; set; }
}
public class ClassB:IValidatableObject
{
[Required]
public string MyProperty { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!string.IsNullOrWhiteSpace(MyProperty) && MyProperty.Length > 10)
yield return new ValidationResult("MaxLength reached");
}
}
public class HomeController : Controller
{
[HttpGet]
public ActionResult Test()
{
ClassA ca = new ClassA();
return View(ca);
}
[HttpPost]
public ActionResult Test(ClassA ca)
{
return View(ca);
}
}
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>ClassA</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
@Html.EditorFor(m => m.CBProp, "TestB")
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div class="editor-label">
@Html.LabelFor(model => model.MyProperty)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.MyProperty)
@Html.ValidationMessageFor(model => model.MyProperty)
</div>
@Html.ValidationSummary(true) /// true, will excludePropertyErrors
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!string.IsNullOrWhiteSpace(MyProperty) && MyProperty.Length > 10)
yield return new ValidationResult("MaxLength reached", new List<string> { "MyProperty" });
}
ModelState.AddModelError("", "This is a summary level error text for the model");
ModelState.AddModelError("b", "This is a 'summary' error for the property named b");