IMetadataAware.OnMetadataCreated nunca se llama

I created attribute class to attach metadata to properties, so I can display tooltips for the form's input fields.

HelpAttribute implementos IMetadataAware:

Public Class HelpAttribute
    Inherits Attribute
    Implements System.Web.Mvc.IMetadataAware

    Public Sub New(text As String)
        _text = text
    End Sub

    Private _text As String
    Public ReadOnly Property Text As String
            Return _text
        End Get
    End Property

    Public Sub OnMetadataCreated(metadata As System.Web.Mvc.ModelMetadata) Implements System.Web.Mvc.IMetadataAware.OnMetadataCreated
        metadata.AdditionalValues.Add("HelpText", _text)
    End Sub
End Class

I utilize this metadata in my extension method:

Public Function HelpFor(Of TModel, TProperty)(ByVal htmlHelper As HtmlHelper(Of TModel), expression As Expression(Of Func(Of TModel, TProperty))) As MvcHtmlString
    Dim metaData = ModelMetadata.FromLambdaExpression(Of TModel, TProperty)(expression, htmlHelper.ViewData)

    If metaData.AdditionalValues.ContainsKey("HelpText") Then
        Dim helpText = metaData.AdditionalValues("HelpText")
        Return MvcHtmlString.Create(String.Format("<span class=""help""></span><div class=""tooltip"" style=""display: none""><div class=""border-top""></div><div class=""close""><a href=""#"">close</a></div><br class=""clear""><div class=""content"">{1}</div></div>", htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(metaData.PropertyName), helpText, metaData.DisplayName))
    End If

    Return MvcHtmlString.Create(String.Format("<span class=""no_help""></span>", htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(metaData.PropertyName), metaData.DisplayName))
End Function

So I can call Html.HelpFor for any of my model's properties and if it has appropriate metadata I display a help icon which shows the tooltip on click (js).

That all works fine as long as HelpAttribute is defined in the same assembly as the classes that I decorate their properties with. Today I had to move HelpAttribute to a separate dll (different namespace as well), so I did that, I referenced the project and expected it to work. I do not get any compiler errors, the app works fine, but it does not display the help icons. I debuggedd the code and I see that the constructor of HelpAttribute is called for different properties with a proper text, but OnMetadataCreated is never called. Does anyone have an idea why that is and how to fix it?

preguntado el 09 de marzo de 12 a las 15:03

3 Respuestas

Another reason this may not be called is if you have the wrong namespace referenced. So

using System.Web.ModelBinding;

will compile and not be hit, but you should be using

using System.Web.Mvc;

Respondido 02 Abr '15, 18:04

Thanks! I don't want to imagine how long it would take me to figure this out. - geriño

Uhuu. What would I do without you. - ucho

Once again I will answer my question myself. Apparently posting things on SO helps me structure the problem in my head. When I moved HelpAttribute to a seperate class library I had to reference System.Web.Mvc para IMetadataAware interface. I use .NET 4.0 and I automatically referenced MVC4 that I installed some time ago for testing purposes. It didn't get me any errors, it just did not work. When I changed System.web.Mvc to ver. 3.0 everything works smoothly.

respondido 09 mar '12, 15:03

    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Web;
    using System.Web.Mvc;

    namespace ColorPickerAttributeExample.Attributes
        [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
        public sealed class ColorPickerAttribute : Attribute, IMetadataAware
            private const string Template =
                "$('#{0}').ColorPicker({{onSubmit: function(hsb, hex, rgb, el) {{" +
                "var self = $(el); self.val(hex);self.ColorPickerHide();}}, onBeforeShow: function () " +
                "{{$(this).ColorPickerSetColor(this.value);}}}}).bind('keyup', function(){{ $(this).ColorPickerSetColor(this.value); }});";

            public const string ColorPicker = "_ColorPicker";

            private int _count;

            // if using IoC container, you could inject this into the attribute
            internal HttpContextBase Context
                get { return new HttpContextWrapper(HttpContext.Current); }

            public string Id
                get { return "jquery-colorpicker-" + _count; }

            #region IMetadataAware Members

            public void OnMetadataCreated(ModelMetadata metadata)
                IList<string> list = Context.Items["Scripts"] as IList<string> ?? new List<string>();
                _count = list.Count;

                metadata.TemplateHint = ColorPicker;
                metadata.AdditionalValues[ColorPicker] = Id;

                list.Add(string.Format(CultureInfo.InvariantCulture, Template, Id));

                Context.Items["Scripts"] = list;


    using ColorPickerAttributeExample.Attributes;
    using System;

    namespace ColorPickerAttributeExample.Models
        public class HomeModel
            public string ColorPicker { get; set; }
            public DateTime ColorPicker2 { get; set; }

@model dynamic

    var picker = ViewData.GetModelAttribute<ColorPickerAttribute>();
    if (picker != null)
        @Html.TextBoxFor(m => m, new {id = ViewData.ModelMetadata.AdditionalValues[ColorPickerAttribute.ColorPicker]})

Respondido el 20 de enero de 14 a las 17:01

The code posted here does not pertain to the question asked, it is just a boilerplate attribute with no consideration for the context of the OP's problem. Even if the code were to be of some use - it should not just be unceremoniously dumped without some explanation of what it does and how it answers the original question. - RobD

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.