如何显示DisplayAttribute.Description属性值?

我有一个模型类,像这样的属性:

[Display(Name = "Phone", Description="Hello World!")] public string Phone1 { get; set; } 

在我的视图中显示一个标签并渲染一个文本框是非常简单的:

 @Html.LabelFor(model => model.Organization.Phone1) @Html.EditorFor(model => model.Organization.Phone1) @Html.ValidationMessageFor(model => model.Organization.Phone1) 

但是,如何呈现Description注释属性的值,即“Hello World!”?

我结束了这样一个帮手:

 using System; using System.Linq.Expressions; using System.Web.Mvc; public static class MvcHtmlHelpers { public static MvcHtmlString DescriptionFor<TModel, TValue>(this HtmlHelper<TModel> self, Expression<Func<TModel, TValue>> expression) { var metadata = ModelMetadata.FromLambdaExpression(expression, self.ViewData); var description = metadata.Description; return MvcHtmlString.Create(string.Format(@"<span>{0}</span>", description)); } } 

感谢那些带领我走向正确方向的人。 🙂

使用本文中关于如何显示窗体中字段的可视提示的技巧 ,可以通过以下方式访问该值:

 @Html.TextBoxFor( model => model.Email , new { title = ModelMetadata.FromLambdaExpression<RegisterModel , string>( model => model.Email , ViewData ).Description } ) 

我正要使用接受的答案 ,但它不适用于ASP.NET Core 1/2(又名MVC 6),因为ModelMetadata.FromLambdaExpression不再存在,并已被移动到ExpressionMetadataProvider (也用法已被略微改变)。

这是一个更新的扩展方法,您可以使用ASP.NET Core 1.1&2

 using System; using System.Linq.Expressions; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; public static class HtmlExtensions { public static IHtmlContent DescriptionFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) { if (html == null) throw new ArgumentNullException(nameof(html)); if (expression == null) throw new ArgumentNullException(nameof(expression)); var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression, html.ViewData, html.MetadataProvider); if (modelExplorer == null) throw new InvalidOperationException($"Failed to get model explorer for {ExpressionHelper.GetExpressionText(expression)}"); return new HtmlString(modelExplorer.Metadata.Description); } } 

ASP.NET Core 1

对于ASP.NET Core 1,相同的代码可以工作,但是您需要使用不同的命名空间:

 using System; using System.Linq.Expressions; using Microsoft.AspNet.Html.Abstractions; using Microsoft.AspNet.Mvc.ViewFeatures; 

用法

 @Html.DescriptionFor(model => model.Phone1) 

你将不得不写一个自定义的帮助器来反映你的模型,给出Description属性的值。

只通过检查(即我没有testing过),但是:

 var attrib = (DisplayAttribute)Attribute.GetCustomAttribute( member, typeof(DisplayAttribute)); var desc = attrib == null ? "" : attrib.GetDescription() 
 @ViewData.ModelMetadata.Properties .Where(m => m.PropertyName == "Phone1").FirstOrDefault().Description 

所以,如果你使用bootstrap,就像

 <div class="form-group col-sm-6"> @Html.LabelFor(m => m.Organization.Phone1) @Html.EditorFor(m => m.Organization.Phone1) <p class="help-block"> @ViewData.ModelMetadata.Properties .Where(m => m.PropertyName == "DayCount").FirstOrDefault().Description </p> </div> 

在ASP.NET MVC核心,你可以使用新的标签助手,这使得你的HTML看起来像… HTML 🙂

喜欢这个:

 <div class="form-group row"> <label asp-for="Name" class="col-md-2 form-control-label"></label> <div class="col-md-10"> <input asp-for="Name" class="form-control" aria-describedby="Name-description" /> <span asp-description-for="Name" class="form-text text-muted" /> <span asp-validation-for="Name" class="text-danger" /> </div> </div> 

注1:您可以在input元素中使用aria-describedby属性,因为该id将在具有asp-description-for属性的span元素中自动创build。

注2:在Bootstrap 4中, form-texttext-mutedreplace了块级帮助文本的v3 help-block类。

要发生这种奇迹,你只需要创build一个新的标签助手:

 using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; /// <summary> /// <see cref="ITagHelper"/> implementation targeting &lt;span&gt; elements with an <c>asp-description-for</c> attribute. /// Adds an <c>id</c> attribute and sets the content of the &lt;span&gt; with the Description property from the model data annotation DisplayAttribute. /// </summary> [HtmlTargetElement("span", Attributes = DescriptionForAttributeName)] public class SpanDescriptionTagHelper : TagHelper { private const string DescriptionForAttributeName = "asp-description-for"; /// <summary> /// Creates a new <see cref="SpanDescriptionTagHelper"/>. /// </summary> /// <param name="generator">The <see cref="IHtmlGenerator"/>.</param> public SpanDescriptionTagHelper(IHtmlGenerator generator) { Generator = generator; } /// <inheritdoc /> public override int Order { get { return -1000; } } [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; } protected IHtmlGenerator Generator { get; } /// <summary> /// An expression to be evaluated against the current model. /// </summary> [HtmlAttributeName(DescriptionForAttributeName)] public ModelExpression DescriptionFor { get; set; } /// <inheritdoc /> /// <remarks>Does nothing if <see cref="DescriptionFor"/> is <c>null</c>.</remarks> public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } var metadata = DescriptionFor.Metadata; if (metadata == null) { throw new InvalidOperationException(string.Format("No provided metadata ({0})", DescriptionForAttributeName)); } output.Attributes.SetAttribute("id", metadata.PropertyName + "-description"); if( !string.IsNullOrWhiteSpace( metadata.Description)) { output.Content.SetContent(metadata.Description); output.TagMode = TagMode.StartTagAndEndTag; } } } 

并使您的标签助手可用于所有我们的剃刀视图。 将addTagHelper指令添加到Views/_ViewImports.cshtml文件中:

 @addTagHelper "*, YourAssemblyName" 

注1:用您的项目的程序集名称replaceYourAssemblyName

注2:你只需要做一次,为所有你的标签助手!

有关Tag Helpers的更多信息,请访问: https : //docs.asp.net/en/latest/mvc/views/tag-helpers/intro.html

而已! 玩新的标签助手!

除了Jakob Gade'a伟大的答案:

如果您需要支持DescriptionAttribute而不是DisplayAttribute ,那么如果我们重写MetadataProvider, 他的优秀解决scheme仍然可行:

 public class ExtendedModelMetadataProvider : DataAnnotationsModelMetadataProvider { protected override ModelMetadata CreateMetadata(IEnumerable<System.Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) { //Possible Multiple Enumerations on IEnumerable fix var attributeList = attributes as IList<System.Attribute> ?? attributes.ToList(); //Default behavior var data = base.CreateMetadata(attributeList, containerType, modelAccessor, modelType, propertyName); //Bind DescriptionAttribute var description = attributeList.SingleOrDefault(a => typeof(DescriptionAttribute) == a.GetType()); if (description != null) { data.Description = ((DescriptionAttribute)description).Description; } return data; } } 

这需要注册在Global.asax.csApplication_Start方法中:

 ModelMetadataProviders.Current = new ExtendedModelMetadataProvider(); 

…如果您希望将描述作为表单标签中的工具提示,请添加如下标签助手:

 using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; /// <summary> /// <see cref="ITagHelper"/> implementation targeting &lt;label&gt; elements with an <c>asp-for</c> attribute. /// Adds a <c>title</c> attribute to the &lt;label&gt; with the Description property from the model data annotation DisplayAttribute. /// </summary> [HtmlTargetElement("label", Attributes = ForAttributeName)] public class LabelTitleTagHelper : TagHelper { private const string ForAttributeName = "asp-for"; /// <summary> /// Creates a new <see cref="LabelTitleTagHelper"/>. /// </summary> /// <param name="generator">The <see cref="IHtmlGenerator"/>.</param> public LabelTitleTagHelper(IHtmlGenerator generator) { Generator = generator; } /// <inheritdoc /> public override int Order { get { return -1000; } } [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; } protected IHtmlGenerator Generator { get; } /// <summary> /// An expression to be evaluated against the current model. /// </summary> [HtmlAttributeName(ForAttributeName)] public ModelExpression TitleFor { get; set; } /// <inheritdoc /> /// <remarks>Does nothing if <see cref="TitleFor"/> is <c>null</c>.</remarks> public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } var metadata = TitleFor.Metadata; if (metadata == null) { throw new InvalidOperationException(string.Format("No provided metadata ({0})", ForAttributeName)); } if (!string.IsNullOrWhiteSpace(metadata.Description)) output.Attributes.SetAttribute("title", metadata.Description); } } 

这将使用模型的数据注释DisplayAttributeDescription属性创build一个新的title属性。

美丽的部分是,你不需要触摸你生成的脚手架意见! 因为这个标签助手的目标是已经存在的label元素的asp-for属性!

HANDL的答案,更新为ASP.NET Core 2.0

 using System; using System.Linq.Expressions; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; public static class HtmlExtensions { public static IHtmlContent DescriptionFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) { if (html == null) throw new ArgumentNullException(nameof(html)); if (expression == null) throw new ArgumentNullException(nameof(expression)); var modelExplorer = ExpressionMetadataProvider.FromLambdaExpression(expression, html.ViewData, html.MetadataProvider); if (modelExplorer == null) throw new InvalidOperationException($"Failed to get model explorer for {ExpressionHelper.GetExpressionText(expression)}"); return new HtmlString(modelExplorer.Metadata.Description); } } 

你总是可以像这样创build自己的自定义扩展:

  public static MvcHtmlString ToolTipLabel (string resourceKey, string text, bool isRequired, string labelFor = "", string labelId = "",string className="") { string tooltip = string.Empty; StringBuilder sb = new StringBuilder(); if (!string.IsNullOrEmpty(resourceKey)) { var resources = GetAllResourceValues(); if (resources.ContainsKey(resourceKey)) { tooltip = resources[resourceKey].Value; } } sb.Append("<label"); if (!string.IsNullOrEmpty(labelFor)) { sb.AppendFormat(" for=\"{0}\"", labelFor); } if (!string.IsNullOrEmpty(labelId)) { sb.AppendFormat(" Id=\"{0}\"", labelId); } if (!string.IsNullOrEmpty(className)) { sb.AppendFormat(" class=\"{0}\"", className); } if (!string.IsNullOrEmpty(tooltip)) { sb.AppendFormat(" data-toggle='tooltip' data-placement='auto left' title=\"{0}\"",tooltip); } if (isRequired) { sb.AppendFormat("><em class='required'>*</em> {0} </label></br>", text); } else { sb.AppendFormat(">{0}</label></br>", text); } return MvcHtmlString.Create(sb.ToString()); } 

并可以像这样看待它:

 @HtmlExtension.ToolTipLabel(" "," ",true," "," "," ")