views:

176

answers:

3

I've putted a Description attribute on my property,but the Description property on the ModelMetada is null anyway.

[Description("sss")]
public int Id { get; set; }

BTW Is I've putted corect?

EDIT

I've had a look at the MVC source. It doesn't seem to be a bug. The decsription attribute is just never used. There is a property in the Metadata class but this property is never set or called. The CreateMetadata method has no code to work with the decription attribute.The solution would be to override the create method and also edit the templates.

A: 

The correct attribute is DisplayNameAttribute. You can do your own attribute, but it must derive from DisplayNameAttribute.

Davi
+1  A: 

I have this problem too - I am using the DescriptionAttibute to set a long description, for use in a tooltip. The idea is to use the 'title' attribute to display a tooltip when the user hovers over the display name.

So in my Metadata class I have:

[Description("Force print even if data is incomplete")]
[DisplayName("Print Anyway?")]
public bool PrintAnyway { get; set; }

Then, in a custom LabelFor() function, I have this code:

public static MvcHtmlString LabelWithTooltip<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
    TagBuilder label = new TagBuilder("label");
    label.SetInnerText(metadata.DisplayName ?? metadata.PropertyName);
    label.Attributes.Add("title", metadata.Description);
    return MvcHtmlString.Create(label.ToString());
}

The strange this is, metadata.DisplayName returns the correct display name ("Print Anyway?"), but metadata.Description returns null, always.

I've been pulling my hair out over this - is this a bug in MVC 2? I'm on .NET 4 and IIS 7.5, but I can't see why this wouldn't work..? Does the metadata load the Description property from somewhere else? It loads the other properties from the annotations..

Ben Green
I edited the post.Please have a look..
+2  A: 

While trying to find how to get this working I came across a blog post that said neither Description nor Watermark are usable with the present incarnation of the DataAnnotations framework.

I came up with a workaround that looks roughly like this:

(Disclaimer: this code is edited from my compiling version to remove it from a metadata provider built through composition so it may not compile directly without some touchups.)

public class CustomDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<System.Attribute> attributes, System.Type containerType, System.Func<object> modelAccessor, System.Type modelType, string propertyName)
    {
        var baseModelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
        var result = new CustomMetadata(modelMetadataProvider, containerType, modelAccessor, modelType, propertyName, attributes.OfType<DisplayColumnAttribute>().FirstOrDefault(), attributes)
        {
            TemplateHint = !string.IsNullOrEmpty(templateName) ?                              templateName : baseModelMetaData.TemplateHint,
            HideSurroundingHtml = baseModelMetaData.HideSurroundingHtml,
            DataTypeName = baseModelMetaData.DataTypeName,
            IsReadOnly = baseModelMetaData.IsReadOnly,
            NullDisplayText = baseModelMetaData.NullDisplayText,
            DisplayFormatString = baseModelMetaData.DisplayFormatString,
            ConvertEmptyStringToNull = baseModelMetaData.ConvertEmptyStringToNull,
            EditFormatString = baseModelMetaData.EditFormatString,
            ShowForDisplay = baseModelMetaData.ShowForDisplay,
            ShowForEdit = baseModelMetaData.ShowForEdit,
            DisplayName = baseModelMetaData.DisplayName
        };
        return result;
    }
}

public class CustomMetadata : DataAnnotationsModelMetadata
{
    private string _description;

    public CustomMetadata(DataAnnotationsModelMetadataProvider provider, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName, DisplayColumnAttribute displayColumnAttribute, IEnumerable<Attribute> attributes)
            : base(provider, containerType, modelAccessor, modelType, propertyName, displayColumnAttribute)
        {
            var descAttr = attributes.OfType<DescriptionAttribute>().SingleOrDefault();
                    _description = descAttr != null ? descAttr.Description : "";
        }

        // here's the really important part
        public override string Description
        {
            get
            {
                return _description;
            }
            set
            {
                _description = value;
            }
        }
}

Then in your Global.asax in Application_Start or wherever you register your model metadata providers:

ModelMetadataProviders.Current = new CustomMetadataProvider();
cfeduke