2010-05-05 16 views
7

Quiero sobrescribir Html.TextBoxFor() con mi propia ayuda que tiene exactamente la misma firma (pero un espacio de nombre diferente, por supuesto): ¿es posible? Y, de ser así, ¿cómo?ASPNET MVC - ¿Anular Html.TextBoxFor (model.property) con un nuevo ayudante con la misma firma?

La razón de esto es que tengo más de 100 vistas en una aplicación ya existente, y quiero cambiar el comportamiento de TextBoxFor para que emita un atributo maxLength = n si la propiedad tiene un [StringLength (n)] anotación.

El código para la salida automática de maxlength = n está en esta pregunta: maxlength attribute of a text box from the DataAnnotations StringLength in Asp.Net MVC. Pero mi pregunta no es un duplicado: estoy intentando crear una solución más genérica: donde el DataAnnotaion fluye automáticamente al html sin necesidad de código adicional por parte de la persona que escribe la vista.

En la pregunta a la que se hace referencia, debe cambiar cada Html.TexBoxFor a Html.CustomTextBoxFor. Necesito hacerlo para que los TextBoxFor() 's existentes no necesiten cambiarse, por lo tanto, crear un helper con la misma firma: cambiar el comportamiento del método de ayuda, y todas las instancias existentes simplemente funcionarán sin ningún cambio (100 + vistas, al menos 500 TextBoxFor() s - no desea editar manualmente eso).

yo probamos este código: (Y tengo que repetirlo para cada una sobrecarga de TextBoxFor, pero una vez que la raíz del problema se resuelve, que va a ser 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 
     } 
    } 
} 

Pero estoy recibiendo un error de compilación en la vista en Html.TextBoxFor(): "La llamada es ambigua entre los siguientes métodos o propiedades" (por supuesto). ¿Hay alguna manera de hacer esto?

¿Existe un enfoque alternativo que me permita cambiar el comportamiento de Html.TextBoxFor, de modo que no sea necesario cambiar las vistas que ya lo usan?

+3

La función Buscar y reemplazar de Visual Studio es bastante potente. ¡Podría reemplazar todas las ocurrencias en su Solución de 'Html.TextBoxFor' con' Html.CustomTextBoxFor' en un solo clic! No debería necesitar editar manualmente ningún archivo para cambiar el nombre de un método. – CoderDennis

Respuesta

-3

Puede resolver esto con una edición en edición y un ModelMetadataProvider personalizado. (Perdón por no dar más información, aunque esto es bastante Googleable y espero que esto te lleve en la dirección correcta.)

+0

Todavía tendría que reemplazar todo el 'TextBoxFor' con' EditorFor'. –

+1

¿Por qué no simplemente proporciona un enlace? – Dan

4

No puedes tener dos métodos de extensión con el mismo nombre y la misma firma al mismo tiempo. Se podría poner su método de extensión en un espacio de nombres personalizado y utilizar este espacio de nombres en lugar de la que viene por defecto (System.Web.Mvc.Html) en su web.config:

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

pero si lo hace, perderá toda los otros métodos de extensión y deberá sobrescribirlos en su espacio de nombres personalizado.

+0

¿Cree que en lugar de eliminar System.Web.Mvc.Html Podría alias a otra cosa (ala usando Foo = namespace), y luego para todos los métodos que no necesito sobrescribir, simplemente puedo ir: YourCompany.Web.Mvc.Html LabelFor (args) { devuelve Foo.LabelFor (args); } ? –

+0

Hola Darin, estoy de acuerdo en que en este caso particular, anular una extensión no parece posible. Pero no estoy de acuerdo con su afirmación de que "no puede tener dos métodos de extensión con el mismo nombre y la misma firma al mismo tiempo". Si coloca su método de extensión en el mismo espacio de nombres (o pocos espacios de nombres en la jerarquía) de su clase consumidora, es muy posible. Hay un ejemplo que lo hace en la siguiente publicación: http://stackoverflow.com/questions/6688613/is-there-any-other-way-to-implement-overriding-not-virtual-and-override-in-cs/6688687 # 6688687 –

1

Respuesta breve, no, no se puede "reemplazar" un método de extensión existente.

Una respuesta más larga, podría ser capaz de hacerlo por un reflejo extremadamente malvado ... Aunque dudo mucho que incluso esto funcione. Algo en esta línea:

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