Estoy tratando de escribir un ayudante en Razor que se parezca a lo siguiente:
@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class
Desafortunadamente, el analizador cree que <Tes el comienzo de un elemento HTML y termino con un error de sintaxis. ¿Es posible crear un ayudante con Razor que sea un método genérico? Si es así, ¿cuál es la sintaxis?
asp.net-mvc
generics
asp.net-mvc-3
razor
mkedobbs
fuente
fuente

static, a menos que los detalles de implementación lo prohíban; la razón es que uno podría usar ayudantes de extensión genéricos :@helper Foo<T>(this T o) where T : IBar { }Respuestas:
No, esto no es posible actualmente. En su lugar, podría escribir un ayudante HTML normal.
public static MvcHtmlString DoSomething<T, U>( this HtmlHelper htmlHelper, Expression<Func<T, U>> expr ) where T : class { ... }y entonces:
@(Html.DoSomething<SomeModel, string>(x => x.SomeProperty))o si está apuntando al modelo como primer argumento genérico:
public static MvcHtmlString DoSomething<TModel, TProperty>( this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expr ) where TModel : class { ... }lo que le permitirá invocarlo así (asumiendo, por supuesto, que su vista está fuertemente tipada, pero esa es una suposición segura porque todas las vistas deben estar fuertemente tipadas de todos modos :-)):
fuente
Esto se puede lograr dentro de un archivo de ayuda con la
@functionssintaxis, pero si desea la legibilidad de estilo navaja a la que se refiere, también deberá llamar a un ayudante habitual para que ajuste y termine el HTML.Tenga en cuenta que las funciones en un archivo Helper son estáticas, por lo que aún deberá pasar la instancia de HtmlHelper desde la página si tiene la intención de usar sus métodos.
por ejemplo, Views \ MyView.cshtml:
App_Code \ MyHelper.cshtml:
@using System.Web.Mvc; @using System.Web.Mvc.Html; @using System.Linq.Expressions; @functions { public static HelperResult DoSomething<TModel, TItem>(HtmlHelper<TModel> html, Expression<Func<TModel, TItem>> expr) { return TheThingToDo(html.LabelFor(expr), html.EditorFor(expr), html.ValidationMessageFor(expr)); } } @helper TheThingToDo(MvcHtmlString label, MvcHtmlString textbox, MvcHtmlString validationMessage) { <p> @label <br /> @textbox @validationMessage </p> } ...fuente
System.Web.WebPages.Html.HtmlHelperlugar deSystem.Web.Mvc.HtmlHelper. Existe una excelente posibilidad de que laWebPagesversión no sea adecuada para usted, ya que la mayoría de los métodos de extensión están escritos en contraSystem.Web.Mvc.HtmlHelper. Además, no existe ningunaUrlpropiedad yUrlHelperrequiere unaRequestContextque no está disponible en laWebPagesversión. Con todo, probablemente tendrá que pasar elMvcHtmlHelper.{MyMvcProject}\App_Code`. It doesn't work as advertised when you place it elsewhere. The error *Cannot access non-static method 'TheThingToDo' in static context* disappears when you moveMyHelper.cshtml` enApp_Code.DoSomethingdebe ser estático, de modo que pueda llamar@MyHelper.DoSomething(..)en su vista. Si lo convierte en no estático, deberá crear una instancia deMyHelperfirst.En todos los casos, el
TModelserá el mismo (el modelo declarado para la vista), y en mi caso, elTValueiba a ser el mismo, por lo que pude declarar el tipo de argumento Expresión:@helper FormRow(Expression<Func<MyViewModel, MyClass>> expression) { <div class="form-group"> @(Html.LabelFor(expression, new { @class = "control-label col-sm-6 text-right" })) <div class="col-sm-6"> @Html.EnumDropDownListFor(expression, new { @class = "form-control" }) </div> @Html.ValidationMessageFor(expression) </div> }Si los campos de su modelo son todos
string, puede reemplazarlosMyClassconstring.Puede que no sea malo definir dos o tres ayudantes con el
TValuedefinido, pero si tiene más que generarían un código desagradable, realmente no encontré una buena solución. Intenté envolver el@helperdesde una función que puse dentro del@functions {}bloque, pero nunca logré que funcionara en ese camino.fuente
TModelque probablemente lo sepas de antemano.si su principal problema es obtener el valor del atributo de nombre para el enlace mediante la expresión lambda
@Html.TextBoxFor(x => x.MyPoperty), y si su componente tiene etiquetas html muy complejas y debe implementarse en el asistente de afeitar, ¿por qué no crear un método de extensiónHtmlHelper<TModel>para resolver el nombre de enlace:namespace System.Web.Mvc { public static class MyHelpers { public static string GetNameForBinding<TModel, TProperty> (this HtmlHelper<TModel> model, Expression<Func<TModel, TProperty>> property) { return ExpressionHelper.GetExpressionText(property); } } }su ayudante de afeitado debe ser como de costumbre:
@helper MyComponent(string name) { <input name="@name" type="text"/> }entonces aquí puedes usarlo
fuente
@Htm.IdForpero necesita un proceso adicional para convertirlo en string (.ToHtmlString()) donde el asistente requiere string