ASPNET MVC - переопределить Html.TextBoxFor (model.property) новым помощником с такой же подписью? - PullRequest
7 голосов
/ 05 мая 2010

Я хочу переопределить Html.TextBoxFor () моим собственным помощником, который имеет точно такую ​​же сигнатуру (но, конечно, другое пространство имен) - возможно ли это, и если да, то как?

Причина этого в том, что у меня более 100 представлений в уже существующем приложении, и я хочу изменить поведение TextBoxFor, чтобы он выводил атрибут maxLength = n, если свойство имеет аннотацию [StringLength (n)] .

Код для автоматического вывода maxlength = n в этом вопросе: атрибут maxlength текстового поля из DataAnnotations StringLength в Asp.Net MVC . Но мой вопрос не является дубликатом - я пытаюсь создать более общее решение: когда DataAnnotaion автоматически попадает в html без необходимости в дополнительном коде лицом, пишущим представление.

В указанном вопросе вы должны изменить каждый отдельный Html.TexBoxFor на Html.CustomTextBoxFor. Мне нужно сделать так, чтобы существующие TextBoxFor () не нуждались в изменении - следовательно, создается помощник с той же сигнатурой: измените поведение вспомогательного метода, и все существующие экземпляры будут просто работать без каких-либо изменений (100 + просмотров, не менее 500 TextBoxFor () s - не хочу редактировать это вручную).

Я попробовал этот код: (И мне нужно повторять его для каждой перегрузки TextBoxFor, но как только проблема с корнем будет решена, это будет тривиально)

namespace My.Helpers
{
    public static class CustomTextBoxHelper
    {
        public static MvcHtmlString TextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes, bool includeLengthIfAnnotated)
        {
                // implementation here
        }
    }
}

Но я получаю ошибку компилятора в представлении Html.TextBoxFor (): «Вызов неоднозначен между следующими методами или свойствами» (конечно). Есть ли способ сделать это?

Есть ли альтернативный подход, который позволил бы мне изменить поведение Html.TextBoxFor, чтобы не нужно было изменять представления, которые уже используют его?

Ответы [ 3 ]

4 голосов
/ 05 мая 2010

У вас не может быть двух методов расширения с одинаковым именем и одинаковой подписью одновременно. Вы можете поместить свой метод расширения в пользовательское пространство имен и использовать это пространство имен вместо стандартного (System.Web.Mvc.Html) в вашем файле web.config:

<pages>
    <namespaces>
        <!--<add namespace="System.Web.Mvc.Html"/>-->
        <add namespace="YourCompany.Web.Mvc.Html"/>
    </namespaces>
</pages>

но если вы сделаете это, вы потеряете все другие методы расширения и вам придется переопределить их в вашем пользовательском пространстве имен.

1 голос
/ 04 августа 2011

Короткий ответ, нет, вы не можете "заменить" существующий метод расширения.

Более длинный ответ, вы могли бы быть в состоянии сделать это с помощью какого-то крайне злого отражения ...Хотя я сильно сомневаюсь, что даже это сработает.Что-то вроде этого:

        // Get the handle for the RuntimeMethodInfo type
        var corlib = Assembly.GetAssembly(typeof (MethodInfo));
        var corlibTypes = corlib.GetModules().SelectMany(mod => mod.FindTypes((a, b) => true, null));
        Type rtmiType = corlibTypes.Where(t => t != null && t.FullName != null && t.FullName.Contains("Reflection.RuntimeMethodInfo")).First();

        // Find the extension method
        var methods = typeof (Html).GetMethods(BindingFlags.Static | BindingFlags.Public);
        foreach (var methodInfo in methods)
        {
            if (methodInfo.Name == "TextBoxFor")
            {
                // Try to monkeypatch this to be private instead of public
                var methodAttributes = rtmiType.GetField("m_methodAttributes", BindingFlags.NonPublic | BindingFlags.Instance);
                if(methodAttributes != null)
                {
                    var attr = methodAttributes.GetValue(methodInfo);
                    attr = ((MethodAttributes)attr) | MethodAttributes.Private;
                    methodAttributes.SetValue(methodInfo, attr);                
                }
            }
        }
0 голосов
/ 05 мая 2010

Вы можете решить эту проблему с помощью редактора шаблонов и пользовательского ModelMetadataProvider. (Извините, что не дал больше информации, хотя это вполне Googleable, и я надеюсь, что это направит вас в правильном направлении.)

...