मैं ASP.NET में अधिक नियंत्रण कैसे ले सकता हूं?


124

मैं एक बहुत, बहुत ही सरल "माइक्रो-वेबैप" बनाने की कोशिश कर रहा हूं, जो मुझे संदेह है कि कुछ स्टैक ओवरफ्लो के लिए ब्याज की होगी यदि मैं कभी भी इसे प्राप्त करता हूं। मैं इसे अपने C # में गहराई साइट पर होस्ट कर रहा हूं, जो कि वैनिला ASP.NET 3.5 है (यानी MVC नहीं)।

प्रवाह बहुत सरल है:

  • यदि कोई उपयोगकर्ता किसी ऐसे URL के साथ ऐप में प्रवेश करता है जो सभी मापदंडों को निर्दिष्ट नहीं करता है (या यदि उनमें से कोई भी अमान्य है) तो मैं उपयोगकर्ता इनपुट नियंत्रणों को प्रदर्शित करना चाहता हूं। (केवल दो हैं।)
  • यदि कोई उपयोगकर्ता किसी ऐसे URL के साथ ऐप में प्रवेश करता है जिसमें सभी आवश्यक पैरामीटर हैं, तो मैं परिणाम और इनपुट नियंत्रण प्रदर्शित करना चाहता हूं (इसलिए वे मापदंडों को बदल सकते हैं)

यहाँ मेरी स्व-आवेधित आवश्यकताएं हैं (डिजाइन और कार्यान्वयन का मिश्रण):

  • मैं पोस्ट के बजाय GET का उपयोग करने के लिए सबमिशन चाहता हूं, ज्यादातर उपयोगकर्ता पृष्ठ को आसानी से बुकमार्क कर सकते हैं।
  • मैं नहीं चाहता कि URL प्रस्तुत करने के बाद मूर्खतापूर्ण रूप से समाप्त हो जाए, उस पर बाहरी बिट्स और टुकड़ों के साथ। बस मुख्य URL और वास्तविक पैरामीटर कृपया।
  • आदर्श रूप से मैं जावास्क्रिप्ट की आवश्यकता से बचना चाहता हूँ। इस ऐप में इसका कोई अच्छा कारण नहीं है।
  • मैं रेंडर समय और सेट मान आदि के दौरान नियंत्रणों का उपयोग करने में सक्षम होना चाहता हूं। विशेष रूप से, मैं नियंत्रण के डिफ़ॉल्ट मानों को पारित किए गए पैरामीटर मानों में सेट करने में सक्षम होना चाहता हूं, अगर ASP.NET स्वचालित रूप से ऐसा नहीं कर सकता है। मेरे लिए (अन्य प्रतिबंधों के भीतर)।
  • मैं खुद को सभी पैरामीटर सत्यापन करने के लिए खुश हूं, और मुझे सर्वर साइड घटनाओं के तरीके की ज्यादा जरूरत नहीं है। बटन आदि की घटनाओं को संलग्न करने के बजाय पृष्ठ लोड पर सब कुछ सेट करना वास्तव में सरल है।

इसमें से अधिकांश ठीक है, लेकिन मैंने व्यूस्टेट को पूरी तरह से हटाने और बाकी उपयोगी कार्यक्षमता को बनाए रखने का कोई तरीका नहीं पाया है । इस ब्लॉग पोस्ट से पोस्ट का उपयोग करते हुए मैंने व्यूस्टेट के लिए कोई वास्तविक मूल्य प्राप्त करने से बचने में कामयाब रहा है - लेकिन यह अभी भी URL पर एक पैरामीटर के रूप में समाप्त होता है, जो वास्तव में बदसूरत दिखता है।

अगर मैं इसे ASP.NET फॉर्म (यानी बाहर निकालता runat="server"हूं) के बजाय एक सादा HTML फॉर्म बनाता हूं, तो मुझे कोई जादू देखने को नहीं मिलता है - लेकिन फिर मैं प्रोग्राम को नियंत्रित रूप से एक्सेस नहीं कर सकता।

मैं ASP.NET की अधिकांश अनदेखी करके और LINQ से XML के साथ XML दस्तावेज़ का निर्माण और कार्यान्वयन करके यह सब कर सकता थाIHttpHandler । हालांकि यह थोड़ा निम्न स्तर का लगता है।

मुझे एहसास है कि मेरी समस्याओं को या तो मेरी बाधाओं को दूर करने के द्वारा हल किया जा सकता है (जैसे कि POST का उपयोग करना और अधिशेष पैरामीटर की देखभाल नहीं करना) या ASP.NET MVC का उपयोग करके, लेकिन क्या मेरी आवश्यकताएं वास्तव में अनुचित हैं?

हो सकता है कि ASP.NET सिर्फ पैमाने पर नहीं है नीचे एप्लिकेशन की इस तरह के लिए? हालांकि यह एक बहुत ही संभावित विकल्प है: मैं सिर्फ बेवकूफ हूं, और ऐसा करने का एक बिल्कुल सरल तरीका है जो मुझे अभी तक नहीं मिला है।

कोई विचार, कोई भी? (क्यू टिप्पणी कैसे शक्तिशाली गिर रहे हैं, आदि। यह ठीक है - मुझे आशा है कि मैंने कभी भी ASP.NET विशेषज्ञ होने का दावा नहीं किया है, क्योंकि सच्चाई काफी विपरीत है ...)


16
"क्यू टिप्पणी कैसे शक्तिशाली गिर रहे हैं" - हम सभी अज्ञानी हैं, बस अलग अलग चीजों की। मैंने हाल ही में यहां भाग लेना शुरू किया है, लेकिन मैं सभी बिंदुओं से अधिक प्रश्न की प्रशंसा करता हूं। आप स्पष्ट रूप से अभी भी सोच रहे हैं और सीख रहे हैं। आप के लिए यश।
duffymo

15
मुझे नहीं लगता कि मैं कभी किसी ऐसे व्यक्ति पर ध्यान दूंगा जिसने सीखना छोड़ दिया :)
जॉन स्कीट

1
सामान्य मामले में सच है। कंप्यूटर विज्ञान में बहुत सही है।
मेहरदाद अफश्री

3
और क्या आपकी अगली किताब "गहराई में ASP.NET" होगी? :-P
१०:३० बजे

20
हाँ, यह 2025 में होने वाला है;)
जॉन स्कीट

जवाबों:


76

यह समाधान आपको संपूर्णता में नियंत्रणों को प्रोग्रामेटिक एक्सेस प्रदान करेगा, जिसमें नियंत्रणों पर सभी विशेषताएँ शामिल हैं। इसके अलावा, URL पर केवल टेक्स्ट बॉक्स मान दिखाई देंगे, इसलिए आपका GET अनुरोध URL अधिक "सार्थक" होगा

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="JonSkeetForm.aspx.cs" Inherits="JonSkeetForm" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Jon Skeet's Form Page</title>
</head>
<body>
    <form action="JonSkeetForm.aspx" method="get">
    <div>
        <input type="text" ID="text1" runat="server" />
        <input type="text" ID="text2" runat="server" />
        <button type="submit">Submit</button>
        <asp:Repeater ID="Repeater1" runat="server">
            <ItemTemplate>
                <div>Some text</div>
            </ItemTemplate>
        </asp:Repeater>
    </div>
    </form>
</body>
</html>

फिर अपने कोड-पीछे आप PageLad पर अपनी जरूरत का हर काम कर सकते हैं

public partial class JonSkeetForm : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        text1.Value = Request.QueryString[text1.ClientID];
        text2.Value = Request.QueryString[text2.ClientID];
    }
}

यदि आप ऐसा फॉर्म नहीं चाहते हैं runat="server", तो आपको HTML नियंत्रणों का उपयोग करना चाहिए। अपने उद्देश्यों के लिए काम करना आसान है। बस नियमित रूप से HTML टैग का उपयोग करें और runat="server"उन्हें एक आईडी दें और दें। फिर आप उन्हें बिना प्रोग्राम और कोड के एक्सेस कर सकते हैं ViewState

केवल नकारात्मक पक्ष यह है कि आपके पास "मददगार" ASP.NET सर्वर जैसे कई नियंत्रण नहीं होंगे GridView। मैंने Repeaterअपने उदाहरण में एक शामिल किया क्योंकि मैं यह मान रहा हूं कि आप उसी पृष्ठ पर फ़ील्ड्स को परिणाम के रूप में रखना चाहते हैं और (मेरी जानकारी के लिए) एक Repeaterएकमात्र डेटाबाउंड नियंत्रण है runat="server"जो फॉर्म टैग में एक विशेषता के बिना चलेगा ।


1
मुझे इतने कम क्षेत्र मिले हैं कि इसे मैन्युअल रूप से करना वास्तव में आसान है :) कुंजी यह थी कि मुझे नहीं पता था कि मैं सामान्य HTML नियंत्रणों के साथ रनैट = सर्वर का उपयोग कर सकता हूं। मैंने अभी तक परिणामों को लागू नहीं किया है, लेकिन यह आसान सा है। लगभग वहाँ!
जॉन स्कीट

दरअसल, पेज स्तर पर EnableViewState = "गलत" सेट करने पर भी एक <form runat = "सर्वर"> __VIEWSTATE (और कुछ अन्य) छिपे हुए फ़ील्ड को जोड़ देगा। यह तरीका है यदि आप पृष्ठ पर ViewState को ढीला करना चाहते हैं। Url मित्रता के लिए, urlrewriting एक विकल्प हो सकता है।
सेर्गी डेमियन

1
पुनर्लेखन की कोई आवश्यकता नहीं। यह उत्तर ठीक काम करता है (हालांकि इसका मतलब "उपयोगकर्ता" की आईडी के साथ एक नियंत्रण है - किसी कारण से मैं इसकी आईडी से अलग से एक टेक्स्टबॉक्स नियंत्रण का नाम नहीं बदल सकता)।
जॉन स्कीट

1
बस पुष्टि करने के लिए, यह वास्तव में बहुत अच्छी तरह से काम किया। बहुत बहुत धन्यवाद!
जॉन स्कीट

14
लगता है जैसे आपको इसे सिर्फ क्लासिक एस्प में लिखा जाना चाहिए था!
स्कॉट जूल 9'09

12

आप अपने FORM टैग में रनैट = "सर्वर" का उपयोग न करके निश्चित रूप से सही रास्ते पर (IMHO) हैं। इसका मतलब यह है कि आपको इस उदाहरण में सीधे Request.QueryString से मान निकालने होंगे।

.Aspx पृष्ठ में ही:

<%@ Page Language="C#" AutoEventWireup="true" 
     CodeFile="FormPage.aspx.cs" Inherits="FormPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>ASP.NET with GET requests and no viewstate</title>
</head>
<body>
    <asp:Panel ID="ResultsPanel" runat="server">
      <h1>Results:</h1>
      <asp:Literal ID="ResultLiteral" runat="server" />
      <hr />
    </asp:Panel>
    <h1>Parameters</h1>
    <form action="FormPage.aspx" method="get">
    <label for="parameter1TextBox">
      Parameter 1:</label>
    <input type="text" name="param1" id="param1TextBox" value='<asp:Literal id="Param1ValueLiteral" runat="server" />'/>
    <label for="parameter1TextBox">
      Parameter 2:</label>
    <input type="text" name="param2" id="param2TextBox"  value='<asp:Literal id="Param2ValueLiteral" runat="server" />'/>
    <input type="submit" name="verb" value="Submit" />
    </form>
</body>
</html>

और कोड-पीछे में:

using System;

public partial class FormPage : System.Web.UI.Page {

        private string param1;
        private string param2;

        protected void Page_Load(object sender, EventArgs e) {

            param1 = Request.QueryString["param1"];
            param2 = Request.QueryString["param2"];

            string result = GetResult(param1, param2);
            ResultsPanel.Visible = (!String.IsNullOrEmpty(result));

            Param1ValueLiteral.Text = Server.HtmlEncode(param1);
            Param2ValueLiteral.Text = Server.HtmlEncode(param2);
            ResultLiteral.Text = Server.HtmlEncode(result);
        }

        // Do something with parameters and return some result.
        private string GetResult(string param1, string param2) {
            if (String.IsNullOrEmpty(param1) && String.IsNullOrEmpty(param2)) return(String.Empty);
            return (String.Format("You supplied {0} and {1}", param1, param2));
        }
    }

यहाँ ट्रिक यह है कि हम ASP.NET लिटरल्स का उपयोग टेक्स्ट इनपुट्स के मान = "" विशेषताओं के अंदर कर रहे हैं, इसलिए टेक्स्ट-बॉक्सों को स्वयं रनैट = "सर्वर" नहीं करना है। फिर परिणाम एक एएसपी: पैनल के अंदर लपेटे जाते हैं, और पृष्ठ लोड पर दृश्यमान संपत्ति सेट करती है कि आप कोई परिणाम प्रदर्शित करना चाहते हैं या नहीं।


यह बहुत अच्छी तरह से काम करता है, लेकिन URL, StackOverflow के अनुसार अनुकूल नहीं होंगे।
मेहरदाद आफश्री

1
मुझे लगता है कि यूआरएल काफी अनुकूल होगा, मुझे लगता है ... यह वास्तव में एक अच्छा समाधान है।
जॉन स्कीट

अर्घ, मैंने आपके ट्वीट्स पहले पढ़े थे, इस पर शोध किया था, और अब मैं आपके प्रश्न को बाथटब के लिए अपने सूक्ष्म बच्चों को तैयार करने से चूक गया ... :-)
splattne

2

ठीक जॉन, पहले देखने का मुद्दा:

अगर 2.0 से किसी भी प्रकार का आंतरिक कोड परिवर्तन है, तो मैंने जाँच नहीं की है, लेकिन यहाँ बताया गया है कि कुछ साल पहले मैंने किस तरह के दृष्टिकोण से छुटकारा पाया था। वास्तव में उस छिपे हुए क्षेत्र को HtmlForm के अंदर हार्डकोड किया गया है, इसलिए आपको अपने नए को प्राप्त करना चाहिए और अपने रेंडर को अपने द्वारा कॉल करना चाहिए। ध्यान दें कि यदि आप सादे पुराने इनपुट नियंत्रणों से चिपके रहते हैं तो __eventtarget और __eventtarget को भी छोड़ सकते हैं (जो मुझे लगता है कि आप चाहते हैं क्योंकि यह क्लाइंट पर JS की आवश्यकता नहीं होने में मदद करता है):

protected override void RenderChildren(System.Web.UI.HtmlTextWriter writer)
{
    System.Web.UI.Page page = this.Page;
    if (page != null)
    {
        onFormRender.Invoke(page, null);
        writer.Write("<div><input type=\"hidden\" name=\"__eventtarget\" id=\"__eventtarget\" value=\"\" /><input type=\"hidden\" name=\"__eventargument\" id=\"__eventargument\" value=\"\" /></div>");
    }

    ICollection controls = (this.Controls as ICollection);
    renderChildrenInternal.Invoke(this, new object[] {writer, controls});

    if (page != null)
        onFormPostRender.Invoke(page, null);
}

तो आप उन 3 स्टैटिक मेथडइन्फो को प्राप्त करें और उस व्यूस्टेट भाग को लंघन करके बाहर बुलाएं;)

static MethodInfo onFormRender;
static MethodInfo renderChildrenInternal;
static MethodInfo onFormPostRender;

और यहां आपके फॉर्म का टाइप कंस्ट्रक्टर है:

static Form()
{
    Type aspNetPageType = typeof(System.Web.UI.Page);

    onFormRender = aspNetPageType.GetMethod("OnFormRender", BindingFlags.Instance | BindingFlags.NonPublic);
    renderChildrenInternal = typeof(System.Web.UI.Control).GetMethod("RenderChildrenInternal", BindingFlags.Instance | BindingFlags.NonPublic);
    onFormPostRender = aspNetPageType.GetMethod("OnFormPostRender", BindingFlags.Instance | BindingFlags.NonPublic);
}

अगर मुझे आपका सवाल सही लग रहा है, तो आप यह भी चाहते हैं कि POST का इस्तेमाल आपके फॉर्म की कार्रवाई के रूप में न हो, तो यहां बताया गया है कि आप ऐसा कैसे करेंगे:

protected override void RenderAttributes(System.Web.UI.HtmlTextWriter writer)
{
    writer.WriteAttribute("method", "get");
    base.Attributes.Remove("method");

    // the rest of it...
}

मुझे लगता है कि यह बहुत ज्यादा है। मुझे बताएं कि यह कैसे जाता है।

संपादित करें: मैं पृष्ठ देखने के तरीकों को भूल गया:

तो आपका कस्टम फ़ॉर्म: HtmlForm को उसका ब्रांड नया सार (या नहीं) पेज मिलता है: System.Web.UI.PATE: P

protected override sealed object SaveViewState()
{
    return null;
}

protected override sealed void SavePageStateToPersistenceMedium(object state)
{
}

protected override sealed void LoadViewState(object savedState)
{
}

protected override sealed object LoadPageStateFromPersistenceMedium()
{
    return null;
}

इस मामले में मैं तरीकों को सील कर देता हूं क्योंकि आप पृष्ठ को सील नहीं कर सकते हैं (भले ही यह सार नहीं है स्कॉट गुथ्री इसे अभी तक एक और पी में लपेट देगा) लेकिन आप अपने फॉर्म को सील कर सकते हैं।


इसके लिए धन्यवाद - हालांकि यह बहुत काम की तरह लगता है। डैन के समाधान ने मेरे लिए ठीक काम किया, लेकिन अधिक विकल्प रखना हमेशा अच्छा होता है।
जॉन स्कीट

1

क्या आपने POST को खत्म करने के बारे में नहीं सोचा है, बल्कि फॉर्म POSTed होने पर एक उपयुक्त GET url पर पुनर्निर्देशित कर रहे हैं। यही है, GET और POST दोनों को स्वीकार करें, लेकिन POST पर GET अनुरोध का निर्माण करें और इसे पुनर्निर्देशित करें। यदि आप इसे पृष्ठ-स्वतंत्र बनाना चाहते हैं तो इसे पृष्ठ पर या HttpModule के माध्यम से नियंत्रित किया जा सकता है। मुझे लगता है कि इससे चीजें बहुत आसान हो जाएंगी।

संपादित करें: मेरा मानना ​​है कि आपके पास पृष्ठ पर EnableViewState = "false" सेट है।


अछा सुझाव। ठीक है, इसे करने के लिए मजबूर होने के संदर्भ में भयानक विचार, लेकिन इसके संदर्भ में अच्छा शायद काम कर रहा है :) कोशिश करेंगे ...
जॉन स्कीट

और हाँ, मैंने सभी जगह EnableViewState = false की कोशिश की है। यह पूरी तरह से इसे अक्षम नहीं करता है, बस इसे नीचे काट देता है।
जॉन स्कीट

जॉन: यदि आप शापित सर्वर नियंत्रण (कोई रनैट = "सर्वर") का उपयोग नहीं करते हैं और आपके पास <फॉर्म रनैट = "सर्वर"> बिल्कुल नहीं है, तो ViewState परेशानी नहीं होगी। इसलिए मैंने कहा कि सर्वर नियंत्रण का उपयोग न करें। आप हमेशा Request.Form संग्रह का उपयोग कर सकते हैं।
मेहरदाद अफश्री

लेकिन बिना रनैट = सर्वर पर नियंत्रण के, यह एक मूल्य है कि जब फिर से नियंत्रण करने के लिए मूल्य को प्रचारित किया जाए। सौभाग्य से, HTML रनैट = सर्वर के साथ अच्छी तरह से काम करता है।
जॉन स्कीट

1

मैं एक HTTP मॉड्यूल बनाऊंगा जो रूटिंग को संभालता है (एमवीसी के समान लेकिन परिष्कृत नहीं, सिर्फ एक दो ifकथन) और इसे aspxया ashxपन्नों को सौंप दें । aspxपृष्ठ टेम्पलेट को संशोधित करना आसान होने के बाद से इसे पसंद किया जाता है। मैं हालांकि WebControlsमें उपयोग नहीं होगा aspx। बस Response.Write

वैसे, चीजों को सरल बनाने के लिए, आप मॉड्यूल में पैरामीटर सत्यापन कर सकते हैं (जैसा कि यह रूटिंग के साथ कोड साझा करता है) और इसे सहेजने HttpContext.Itemsऔर फिर उन्हें पृष्ठ में प्रस्तुत करने के लिए। यह सभी घंटी और सीटी के बिना एमवीसी की तरह बहुत काम करेगा। यह वही है जो मैंने ASP.NET MVC दिनों से पहले किया था।


1

मुझे वास्तव में पूरी तरह से पृष्ठ वर्ग को पूरी तरह से त्यागने की खुशी हुई है और बस हर अनुरोध को यूआरएल के आधार पर एक बड़े स्विच केस के साथ सौंप दिया गया है। Evey "पेज" एक html टेम्पलेट और एसी # ऑब्जेक्ट बन जाता है। टेम्प्लेट क्लास मैच प्रतिनिधि के साथ एक रेगेक्स का उपयोग करता है जो एक प्रमुख संग्रह के खिलाफ तुलना करता है।

लाभ:

  1. यह वास्तव में तेज़ है, यहां तक ​​कि एक recompile के बाद, लगभग कोई अंतराल नहीं है (पृष्ठ वर्ग बड़ा होना चाहिए)
  2. नियंत्रण वास्तव में दानेदार (एसईओ के लिए महान है, और जेएस के साथ अच्छी तरह से खेलने के लिए डोम का क्राफ्टिंग है)
  3. प्रस्तुति तर्क से अलग है
  4. jQuery का कुल नियंत्रण html है

bummers:

  1. साधारण सामग्री में थोड़ा अधिक समय लगता है कि एक एकल टेक्स्ट बॉक्स को कई स्थानों पर कोड की आवश्यकता होती है, लेकिन यह वास्तव में अच्छी तरह से स्केल करता है
  2. यह हमेशा पृष्ठ दृश्य के साथ करने के लिए प्रलोभन देता है जब तक कि मैं एक दृश्य (urgh) नहीं देखता हूं तब तक मैं वास्तविकता में वापस आ जाता हूं।

जॉन, हम शनिवार की सुबह एसओ पर क्या कर रहे हैं :)?


1
यहां शनिवार की शाम है। क्या यह ठीक है? (मैं अपनी पोस्टिंग समय / दिन, btw का एक बिखरा हुआ ग्राफ देखना पसंद करूंगा ...)
जॉन स्कीट

1

मैंने सोचा था कि एस्प: पुनरावर्तक नियंत्रण अप्रचलित था।

ASP.NET टेम्प्लेट इंजन अच्छा है, लेकिन आप आसानी से एक लूप के साथ दोहराने को पूरा कर सकते हैं ...

<form action="JonSkeetForm.aspx" method="get">
<div>
    <input type="text" ID="text1" runat="server" />
    <input type="text" ID="text2" runat="server" />
    <button type="submit">Submit</button>
    <% foreach( var item in dataSource ) { %>
        <div>Some text</div>   
    <% } %>
</div>
</form>

ASP.NET प्रपत्र ठीक है, विजुअल स्टूडियो से अच्छा समर्थन है, लेकिन यह रनैट = "सर्वर" चीज है, यह गलत है। देखने के लिए।

मेरा सुझाव है कि आप एक नज़र डालते हैं कि ASP.NET MVC को क्या महान बनाता है, जो यह सब दूर फेंकने के बिना ASP.NET प्रपत्र दृष्टिकोण से दूर चला जाता है।

तुम भी अपने स्वयं के निर्माण प्रदाता सामान लिख सकते हैं NHaml जैसे कस्टम विचारों को संकलित करने के लिए। मुझे लगता है कि आपको अधिक नियंत्रण के लिए यहां देखना चाहिए और बस HTTP रैपिंग के लिए ASP.NET रनटाइम पर भरोसा करते हुए और CLR होस्टिंग वातावरण के रूप में। यदि आप एकीकृत मोड चलाते हैं तो आप HTTP अनुरोध / प्रतिक्रिया में भी हेरफेर कर पाएंगे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.