क्या रेजर के साथ जेनेरिक @ हेपर विधि बनाना संभव है?


89

मैं रेजर में एक सहायक लिखने की कोशिश कर रहा हूं जो निम्नलिखित की तरह दिखता है:

@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class

दुर्भाग्य से, पार्सर सोचता है कि <Tएक HTML तत्व की शुरुआत है और मैं एक सिंटैक्स त्रुटि के साथ समाप्त होता हूं। क्या रेजर के साथ एक सहायक बनाना संभव है जो एक सामान्य विधि है? यदि हां, तो वाक्य रचना क्या है?


अभी भी वर्तमान एमवीसी 4 रिलीज में तय नहीं है। :(
एलेक्स ड्रेस्को

1
यह अभी भी VS2012 में कैसे तय नहीं हुआ है?
एलेक्स ड्रेस्को 19

7
अच्छाई, मैं इसे जोड़ने के लिए इंतजार नहीं कर सकता; मुझे आशा है कि यह प्राथमिकता सूची में " कल इसे लागू करें " के आसपास है । आंशिक रूप से ऑफ-टॉपिक, लेकिन इसके साथ-साथ, मैं यह देखना चाहूंगा कि उत्पन्न वर्ग हैं static, जब तक कि कार्यान्वयन विवरण इसे प्रतिबंधित नहीं करते हैं; कारण यह है कि क्या कोई जेनेरिक एक्सटेंशन हेल्पर्स का उपयोग कर सकता है :@helper Foo<T>(this T o) where T : IBar { }
दान लूग

जवाबों:


52

नहीं, यह वर्तमान में संभव नहीं है। आप इसके बजाय एक सामान्य HTML सहायक लिख सकते हैं।

public static MvcHtmlString DoSomething<T, U>(
    this HtmlHelper htmlHelper, 
    Expression<Func<T, U>> expr
) where T : class
{
    ...
}

और फिर:

@(Html.DoSomething<SomeModel, string>(x => x.SomeProperty))

या यदि आप पहले सामान्य तर्क के रूप में मॉडल को लक्षित कर रहे हैं:

public static MvcHtmlString DoSomething<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper, 
    Expression<Func<TModel, TProperty>> expr
) where TModel : class
{
    ...
}

जो आपको इसे इस तरह से लागू करने की अनुमति देगा (निश्चित रूप से यह मानते हुए कि आपका दृष्टिकोण दृढ़ता से टाइप किया गया है, लेकिन यह एक सुरक्षित धारणा है क्योंकि सभी दृश्य किसी भी तरह से टाइप किए जाने चाहिए :-)):

@Html.DoSomething(x => x.SomeProperty)

10
उम्मीद है कि यह कुछ ऐसा है जो वे रेजर सहायकों के भविष्य के संस्करण में जोड़ते हैं। एक पारंपरिक सहायक की पठनीयता @helper सिंटैक्स की तुलना में बहुत कम है।
mkedobbs

2
हाँ मान गया। पुरानी पद्धति को वापस लेना न केवल बेकार है, बल्कि आपके सहायकों को मनमाने ढंग से विभाजित करता है!
जॉर्ज आर

127

यह है के साथ एक सहायक फाइल के अंदर प्राप्त करने के लिए संभव @functionsवाक्य रचना लेकिन अगर आप चाहते हैं उस्तरा शैली पठनीयता क्या आप बात कर रहे हैं भी एचटीएमएल फिट और खत्म करने के लिए एक नियमित रूप से सहायक कॉल करने के लिए की आवश्यकता होगी।

ध्यान दें कि हेल्पर फ़ाइल में फ़ंक्शंस स्थिर हैं, इसलिए आपको अभी भी पृष्ठ से HtmlHelper उदाहरण में पास करने की आवश्यकता होगी यदि आप इसके तरीकों का उपयोग करने का इरादा कर रहे थे।

उदाहरण के लिए \ MyView.cshtml

@MyHelper.DoSomething(Html, m=>m.Property1)
@MyHelper.DoSomething(Html, m=>m.Property2)
@MyHelper.DoSomething(Html, m=>m.Property3)

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

यह पूर्ण है। धन्यवाद।
केन स्मिथ

आपको विधि को स्थिर बनाने की आवश्यकता नहीं है, और इस प्रकार आपको अपने Html / Url / Model आदि को पास करने की भी आवश्यकता नहीं है
भेड़

12
@ शेफी, यह केवल आधा सच है। आप सही हैं कि आप उन्हें गैर-स्थिर बना सकते हैं, लेकिन आप केवल System.Web.WebPages.Html.HtmlHelperइसके बजाय प्राप्त करते हैं System.Web.Mvc.HtmlHelper। एक उत्कृष्ट मौका है कि WebPagesसंस्करण आपके लिए उपयुक्त नहीं होगा, क्योंकि अधिकांश विस्तार विधियों के खिलाफ लिखा गया है System.Web.Mvc.HtmlHelper। इसके अलावा, कोई Urlसंपत्ति नहीं है, और UrlHelperइसके RequestContextलिए WebPagesसंस्करण में अनुपलब्ध होने की आवश्यकता है । सब सब में आप शायद में पारित करने के लिए जा रहे हैं Mvc HtmlHelper
Kirk Woll

1
सहायक App_Code फ़ोल्डर का हिस्सा होना चाहिए ??
विशाल शर्मा

1
हां, इस फाइल को {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 move MyHelper.cshtml` में रखा जाना चाहिए App_CodeDoSomethingस्थिर होना चाहिए, ताकि आप @MyHelper.DoSomething(..)अपने विचार में कॉल कर सकें । यदि आप इसे गैर-स्थिर बनाते हैं, तो आपको MyHelperपहले एक उदाहरण बनाने की आवश्यकता होगी ।
ग्रिल्स

3

सभी मामलों में TModelएक ही (दृश्य के लिए घोषित मॉडल) होगा, और मेरे मामले में, एक TValueही होने वाला था, इसलिए मैं अभिव्यक्ति तर्क प्रकार की घोषणा करने में सक्षम था:

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

अपने मॉडल क्षेत्रों सभी कर रहे हैं string, तो आप बदल सकते हैं MyClassके साथ string

परिभाषित के साथ दो या तीन सहायकों को परिभाषित करना बुरा नहीं हो सकता TValueहै, लेकिन अगर आपके पास कोई और है जो कुछ बदसूरत कोड उत्पन्न करेगा, तो मुझे वास्तव में एक अच्छा समाधान नहीं मिला। मैंने @helperउस फ़ंक्शन से रैप करने की कोशिश की , जिसे मैंने @functions {}ब्लॉक के अंदर रखा था , लेकिन मुझे कभी भी उस रास्ते पर काम करने के लिए नहीं मिला।


स्पष्ट रूप से जब आप इसके बारे में सोचते हैं - अगर यह TModelआप इसे पहले से जानते हैं।
ta.speot.is 6

0

यदि आपकी मुख्य समस्या लैंबडा अभिव्यक्ति का उपयोग करके बाइंडिंग के लिए नाम विशेषता मान प्राप्त करना है @Html.TextBoxFor(x => x.MyPoperty), तो ऐसा लगता है , और यदि आपके घटक में बहुत जटिल HTML टैग हैं और इसे रेजर हेल्पर पर लागू किया जाना चाहिए, तो HtmlHelper<TModel>इसे हल करने के लिए केवल एक एक्सटेंशन विधि क्यों न बनाएं बाध्यकारी नाम:

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

आपका रेज़र हेल्पर हमेशा की तरह होना चाहिए:

@helper MyComponent(string name)
{
    <input name="@name" type="text"/>
}

फिर यहां आप इसका उपयोग कर सकते हैं

@TheHelper.MyComponent(Html.GetNameForBinding(x => x.MyProperty))

क्या यह @ Html.IdFor (...) नहीं है?
एलेक्स ड्रेस्को

हां, आप @Htm.IdForइसे स्ट्रिंग में बदलने के लिए अतिरिक्त प्रक्रिया की आवश्यकता कर सकते हैं ( .ToHtmlString()जहां सहायक को स्ट्रिंग की आवश्यकता है
ktutnik
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.