简体   繁体   中英

How-to set the Description property of the ModelMetadata

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.

This is an old post, but ran into this as well have have a slightly different solution than cfeduke. Figured I'd post it in case anyone else happens by here.

At least in MVC 3, you don't need to define a custom metadata type, just the provider. Reading through the MVC source code, metadata isn't build from all possible attributes, just a few:

DisplayAttribute provides:

  • Description
  • ShortDisplayName
  • Watermark
  • Order

The DescriptionAttribute isn't checked for at all so if defined on your model, the metadata will reflect null. If you're having problems with metadata attributes not being set, check that the provider actually reads that.

class MyDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var metaData = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);

        // Description - The default provider reads the description from DisplayAttribute.
        // Here we check for a description attribute as well.  This will overwrite anything
        // set before as we assume a Description attribute is more specific.
        DescriptionAttribute descriptionAttribute = attributes.OfType<DescriptionAttribute>().FirstOrDefault();
        if (descriptionAttribute != null)
        {
            metaData.Description = descriptionAttribute.Description;
        }

        return metaData;
    }
}

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();

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

If you're using MVC 3 you can use [AdditionalMetadata("AttributeName", "AttributeValue")] for custom attributes.

In your extension methods you can then do something like:

if (ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).AdditionalValues.ContainsKey("AttributeName")) {    
 return ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).AdditionalValues["AttributeName"].ToString()    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM