ASPNET MVC - Override Html.TextBoxFor(model.property) with a new helper with same signature?

断了今生、忘了曾经 提交于 2019-12-23 08:56:09

问题


I want to override Html.TextBoxFor() with my own helper that has the exact same signature (but a different namespace of course) - is this possible, and if so, how?

The reason for this is that I have 100+ views in an already existing app, and I want to change the behaviour of TextBoxFor so that it outputs a maxLength=n attribute if the property has a [StringLength(n)] annotation.

The code for automatically outputting maxlength=n is in this question: maxlength attribute of a text box from the DataAnnotations StringLength in Asp.Net MVC. But my question is not a duplicate - I am trying creating a more generic solution: where the DataAnnotaion flows into the html automatically without any need for additional code by the person writing the view.

In the referenced question, you have to change every single Html.TexBoxFor to a Html.CustomTextBoxFor. I need to do it so that the existing TextBoxFor()'s do not need to be changed - hence creating a helper with the same signature: change the behaviour of the helper method, and all existing instances will just work without any changes (100+ views, at least 500 TextBoxFor()s - don't want to manually edit that).

I tried this code: (And I need to repeat it for each overload of TextBoxFor, but once the root problem is solved, that will be trivial)

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
        }
    }
}

But I am getting a compiler error in the view on Html.TextBoxFor(): "The call is ambiguous between the following methods or properties" (of course). Is there any way to do this?

Is there an alternative approach that would allow me to change the behaviour of Html.TextBoxFor, so that the views that already use it do not need to be changed?


回答1:


You cannot have two extension methods with the same name and the same signature at the same time. You could put your extension method into a custom namespace and use this namespace instead of the default one (System.Web.Mvc.Html) in your web.config:

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

but if you do this you will lose all the other extension methods and you will need to override them in your custom namespace.




回答2:


Short answer, no, you can't "replace" an existing extension method.

Longer answer, you might be able to do so by some extremely evil reflection...Although I highly doubt even this would work. Something along these lines:

        // 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);                
                }
            }
        }



回答3:


You can solve this with a editortemplate and a custom ModelMetadataProvider. (Sorry for not giving more info, though this is quite Googleable and I hope this will put you in the right direction.)



来源:https://stackoverflow.com/questions/2769948/aspnet-mvc-override-html-textboxformodel-property-with-a-new-helper-with-sam

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!