Asp.Net WebForms एप्लिकेशन विकसित करने के लिए MEF (प्रबंधित एक्सटेंसीबिलिटी फ्रेमवर्क) का उपयोग करना

MEF एक्स्टेंसिबल एप्लिकेशन लिखने के लिए एक अच्छा ढांचा है। यह आपको एब्सट्रैक्शन से कार्यान्वयन को आसानी से अलग करने की अनुमति देता है, एप्लिकेशन के चालू होने (पुनर्मूल्यांकन) के दौरान कार्यान्वयन को जोड़ / हटा देता है, अमूर्त के कई कार्यान्वयन के साथ काम करता है, अलग-अलग अखंड अनुप्रयोगों को स्वतंत्र भागों में जोड़ता है, आदि।



एमईएफ कैसे काम करता है इसके अधिकांश उदाहरण कंसोल या WPF अनुप्रयोग हैं। क्यों? क्योंकि इस मामले में यह जीवन के लिए भागों को नियंत्रित करना सबसे आसान है। MEF खुद इस बात का ध्यान रखता है, और डेवलपर उदाहरण के कार्यों पर ध्यान केंद्रित करता है।



वेब अनुप्रयोगों में स्थिति मौलिक रूप से अलग है। डेवलपर्स पेज बनाने, नियंत्रण करने आदि के लिए ज़िम्मेदार नहीं हैं, क्योंकि Asp.net रनटाइम सब कुछ का ख्याल रखता है।



इस प्रकार, वेब अनुप्रयोगों के लिए MEF समर्थन को लागू करने के लिए, आपको दोनों टूल के एल्गोरिदम को संयोजित करना चाहिए।



ज्ञात समाधान



एक उपाय है कि MEF का उपयोग WebForms अनुप्रयोगों के लिए कैसे किया जा सकता है। लेकिन इस उदाहरण की कई महत्वपूर्ण सीमाएँ हैं।



उच्च स्तरीय वास्तुकला



समाधान का उद्देश्य एमईएफ कंटेनर के लिए फिर से विरासत तंत्र का उपयोग करने और HttpModule



और HttpHandler



लिए समर्थन प्रदान करने की आवश्यकता के बिना समर्थन को लागू करना है।



इस तथ्य के बावजूद कि मैंने ऊपर प्रस्तुत समाधान को अस्वीकार कर दिया है, मैं इसे आधार के रूप में उपयोग करने जा रहा हूं। इसका मतलब है कि मैं दो कंटेनरों का उपयोग करूंगा - स्थानीय (प्रति अनुरोध) और वैश्विक।



जब भी कोई अनुरोध आता है, asp.net रनटाइम अनुरोधित पृष्ठ या हैंडलर बनाता है और सभी निर्भर नियंत्रण बनाता है। मैं सुझाव देता हूं कि पेज के सभी हिस्सों को बनाने के तुरंत बाद आयातित तत्वों को इनिशियलाइज़ करना, और सभी इनिशियलाइज़्ड इंपोर्ट को स्थानीय कंटेनर में सेव करना।



दूसरी ओर, HttpModule



पूरे एप्लिकेशन की शुरुआत के तुरंत बाद एक बार बनाया HttpModule



। इस प्रकार, उनके लिए आयात जितनी जल्दी हो सके किया जाना चाहिए और सभी HttpModule



को वैश्विक कंटेनर में संग्रहीत किया जाना चाहिए।



कार्यान्वयन



पेज और नियंत्रण


पृष्ठ और उसकी सभी निर्भरताओं के लिए आयात ऑपरेशन करने के लिए, आपको अतिरिक्त HttpModule



उपयोग करना चाहिए। इस मॉड्यूल में, आपको वर्तमान अनुरोधित पृष्ठ के लिए Pre_Init



और Init



हैंडलर जोड़ना चाहिए। पहले हैंडलर में, पेज, मास्टर पेज और उपयोगकर्ता नियंत्रण के लिए रचना प्रदर्शन करना संभव हो जाता है। Init



ईवेंट आपको सर्वर नियंत्रण के लिए कंपोज़िशन निष्पादित करने की अनुमति देता है, जैसा कि Pre_Init



पर वे अभी तक मौजूद नहीं हैं।



एक उदाहरण:

public class ComposeContainerHttpModule : IHttpModule<br>{<br> public void Init(HttpApplication context)<br> {<br> context.PreRequestHandlerExecute += ContextPreRequestHandlerExecute;<br> }<br><br> private void ContextPreRequestHandlerExecute( object sender, EventArgs e)<br> {<br> Page page = HttpContext .Current.CurrentHandler as Page ;<br> if (page != null )<br> {<br> page.PreInit += Page_PreInit;<br> page.Init += Page_Init;<br> }<br> }<br><br> private void Page_Init( object sender, EventArgs e)<br> {<br> Page handler = sender as Page ;<br><br> if (handler != null )<br> {<br> CompositionBatch batch = new CompositionBatch();<br> batch = ComposeWebPartsUtils.BuildUpControls(batch, handler.Controls);<br> ContextualCompositionHost.Container.Compose(batch);<br> }<br> }<br><br> private void Page_PreInit( object sender, EventArgs e)<br> {<br> Page handler = sender as Page ;<br><br> if (handler != null )<br> {<br> CompositionBatch batch = new CompositionBatch();<br> batch = ComposeWebPartsUtils.BuildUp(batch, handler);<br> batch = ComposeWebPartsUtils.BuildUpUserControls(batch, handler.Controls);<br> batch = ComposeWebPartsUtils.BuildUpMaster(batch, handler.Master);<br> ContextualCompositionHost.Container.Compose(batch);<br> }<br> }<br><br> public void Dispose()<br> {<br> }<br>}<br> <br> * This source code was highlighted with Source Code Highlighter .





प्रारंभ में, आयात पृष्ठ के लिए किया जाता है, फिर उपयोगकर्ता नियंत्रण और मास्टर पृष्ठों के लिए, और बहुत अंत में, सर्वर नियंत्रण और उनके नियंत्रण के लिए एक पुनरावर्ती कार्य आयात करता है।



BuildUp(CompositionBatch batch, Object o)



विधि यह देखने के लिए जाँचती है कि क्या Object o



कोई आयातित आइटम है और इसे संरचना के लिए ऑब्जेक्ट की सूची में जोड़ता है। एक बार सभी नियंत्रणों को संसाधित कर लेने के बाद, कंटेनर को इनिशियलाइज़ करने के लिए ComposBatch ऑब्जेक्ट का उपयोग किया जा सकता है। उसके बाद, सभी आयात आरंभ किए जाएंगे और अनुरोध के जीवन भर उपलब्ध रहेंगे।



एक उदाहरण:

public static class ComposeWebPartsUtils<br>{<br> public static CompositionBatch BuildUp(CompositionBatch batch, Object o)<br> {<br> ComposablePart part = AttributedModelServices.CreatePart(o);<br><br> if (part.ImportDefinitions.Any())<br> {<br> if (part.ExportDefinitions.Any())<br> throw new Exception( string .Format( "'{0}': Handlers cannot be exportable" , o.GetType().FullName));<br><br> batch.AddPart(part);<br> }<br><br> return batch;<br> }<br><br> public static CompositionBatch BuildUpUserControls(CompositionBatch batch, ControlCollection controls)<br> {<br> foreach (Control c in controls)<br> {<br> if (c is UserControl)<br> batch = ComposeWebPartsUtils.BuildUp(batch, c);<br> batch = BuildUpUserControls(batch, c.Controls);<br> }<br><br> return batch;<br> }<br><br> public static CompositionBatch BuildUpControls(CompositionBatch batch, ControlCollection controls)<br> {<br> foreach (Control c in controls)<br> {<br> batch = ComposeWebPartsUtils.BuildUp(batch, c);<br> batch = BuildUpControls(batch, c.Controls);<br> }<br><br> return batch;<br> }<br><br> public static CompositionBatch BuildUpMaster(CompositionBatch batch, MasterPage master)<br> {<br> if (master != null )<br> batch = BuildUpMaster(ComposeWebPartsUtils.BuildUp(batch, master), master.Master);<br><br> return batch;<br> }<br>}<br> <br> * This source code was highlighted with Source Code Highlighter .





नोट:

मैं उसी तकनीक का उपयोग नहीं कर सकता जिसका उपयोग PageHandlerFactory



साइट (उदाहरण में PageHandlerFactory



विरासत में PageHandlerFactory



और GetHandler()



विधि से अधिलेखित किया गया है, क्योंकि) इस समय तक, पेज के लिए अभी तक कोई नियंत्रण नहीं बनाया गया है।



HttpHandler


हैंडलर के पास ऐसी घटनाएँ नहीं हैं जहाँ सभी आयात संतुष्ट हो सकें। उपयुक्त HandlerFactory



का उपयोग करना और HandlerFactory



GetHandler()



पद्धति को ओवरराइड करने के लिए आदर्श होगा HandlerFactory



कि HandlerFactory



उदाहरण में पृष्ठों के लिए किया गया था। और ऐसा वर्ग मौजूद है ( SimpleWebHandlerFactory



), लेकिन यह आंतरिक है। मुझे पता नहीं है कि Microsoft प्रोग्रामरों ने ऐसा किस कारण से किया है, लेकिन यह अजीब लगता है क्योंकि पृष्ठों का कारखाना सार्वजनिक है।



मैं अपने स्वयं के कारखाने SimpleWebHandlerFactory



लागू करने के बजाय SimpleWebHandlerFactory



ढांचे में मौजूद होने के अलावा कोई अन्य विकल्प नहीं देखता हूं। किसी भी HandlerFactory



का मुख्य लक्ष्य उस प्रकार को निर्धारित करना है जिसे वर्तमान अनुरोध के लिए तत्काल किया जाना चाहिए। HandlerFactory



केवल अनुरोध किए गए संसाधन के पार्सिंग के माध्यम से एक प्रकार प्राप्त कर सकता है। इसलिए मुझे एक Parser की जरूरत है जो HttpHandler



कोड को पार्स कर सके। सौभाग्य से, ऐसा पार्सर मौजूद है ( SimpleWebHandlerParser



), सार्वजनिक है, और मुझे केवल इसके लिए एक रैपर बनाने की आवश्यकता है ( WebHandlerParser



)।



निम्नलिखित एक अनुक्रम आरेख है जो HttpHandler



लिए एक रचना बनाने के लिए एल्गोरिथ्म के संचालन का वर्णन करता है



नीचे उन कक्षाओं का कोड है जो ऊपर वर्णित कार्यक्षमता को लागू करते हैं।

public class SimpleWebHandlerFactory : IHttpHandlerFactory<br>{<br> public virtual IHttpHandler GetHandler( HttpContext context, string requestType, string virtualPath, string path)<br> {<br> Type type = WebHandlerParser.GetCompiledType(context, virtualPath, path);<br> if (!( typeof (IHttpHandler).IsAssignableFrom(type)))<br> throw new HttpException( "Type does not implement IHttpHandler: " + type.FullName);<br><br> return Activator.CreateInstance(type) as IHttpHandler;<br> }<br><br> public virtual void ReleaseHandler(IHttpHandler handler)<br> {<br> }<br>}<br><br> internal class WebHandlerParser : SimpleWebHandlerParser<br>{<br> internal WebHandlerParser( HttpContext context, string virtualPath, string physicalPath)<br> : base (context, virtualPath, physicalPath)<br> {<br> }<br><br> public static Type GetCompiledType( HttpContext context, string virtualPath, string physicalPath)<br> {<br> WebHandlerParser parser = new WebHandlerParser(context, virtualPath, physicalPath);<br> Type type = parser.GetCompiledTypeFromCache();<br> if (type != null )<br> return type;<br> else <br> throw new HttpException( string .Format( "File '{0}' is not a web handler." , virtualPath));<br> }<br> <br> protected override string DefaultDirectiveName<br> {<br> get <br> {<br> return "webhandler" ;<br> }<br> }<br>}<br><br> public class ComposableWebHandlerFactory : SimpleWebHandlerFactory<br>{<br> public override IHttpHandler GetHandler( HttpContext context, string requestType, string virtualPath, string path)<br> {<br> IHttpHandler handler = base .GetHandler(context, requestType, virtualPath, path);<br><br> if (handler != null )<br> {<br> CompositionBatch batch = new CompositionBatch();<br> batch = ComposeWebPartsUtils.BuildUp(batch, handler);<br> ContextualCompositionHost.Container.Compose(batch);<br> }<br><br> return handler;<br> }<br>}<br> <br> * This source code was highlighted with Source Code Highlighter .





HttpModule


जैसा कि मैंने पहले उल्लेख किया है, सभी HttpModules



एप्लिकेशन की शुरुआत में बनाए जाते हैं। इस प्रकार, मुझे आवेदन शुरू होने के बाद रचना को सही बनाना होगा।

एक उदाहरण:

public class ScopedContainerHttpModule : IHttpModule<br>{<br> private CompositionContainer _container;<br><br> public void Init(HttpApplication app)<br> {<br> ComposeModules(app);<br> }<br><br> private void ComposeModules(HttpApplication app)<br> {<br> CompositionBatch batch = ComposeWebPartsUtils.BuildUpModules(app);<br> _container.Compose(batch);<br> }<br>}<br><br> public static class ComposeWebPartsUtils<br>{<br> public static CompositionBatch BuildUpModules(HttpApplication app)<br> {<br> CompositionBatch batch = new CompositionBatch();<br><br> for ( int i = 0; i < app.Modules.Count - 1; i++)<br> batch = BuildUp(batch, app.Modules.Get(i));<br><br> return batch;<br> }<br>} <br><br> * This source code was highlighted with Source Code Highlighter .





मुझे एक HttpApplication



ऑब्जेक्ट मिलता है, HttpApplication



सभी मॉड्यूल निकालें और इस जानकारी के आधार पर मैं वैश्विक कंटेनर को भरता हूं।



नतीजतन, मुझे किसी भी WebForms परियोजना के web.config फ़ाइल में कुछ लाइनें जोड़नी चाहिए ताकि मेरा समाधान काम करे।

< httpHandlers > <br> ......<br> < remove path ="*.ashx" verb ="*" /> <br> < add path ="*.ashx" verb ="*" type ="common.composition.WebExtensions.ComposableWebHandlerFactory, common.composition" /> <br> ......<br> </ httpHandlers > <br> < httpModules > <br> < add name ="ContainerCreator" type ="common.composition.WebExtensions.ScopedContainerHttpModule, common.composition" /> <br> ......<br> < add name ="ComposeContainerModule" type ="common.composition.WebExtensions.ComposeContainerHttpModule, common.composition" /> <br> </ httpModules > <br><br> * This source code was highlighted with Source Code Highlighter .





मैं * .ashx फ़ाइल हैंडलर को हटाता हूं, जो डिफ़ॉल्ट रूप से मौजूद है, और मेरा ( ComposableWebHandlerFactory



) जोड़ें।



मैं स्थानीय और वैश्विक कंटेनरों के लिए बुनियादी ढांचे को बनाने और शुरू करने के लिए एक ContainerCreator



मॉड्यूल जोड़ रहा हूं।



ComposeContainerModule



का उपयोग स्थानीय कंटेनर को आरंभ करने के लिए किया जाएगा।



वह सब है!



मुझे नियंत्रणों की विरासत का उपयोग करने की आवश्यकता नहीं थी, मुख्य कार्यक्रम में अतिरिक्त कोड लिखें। इस समाधान को वेब रूपों के आधार पर किसी भी वेब परियोजना में जोड़ा जा सकता है, और केवल web.config को अपडेट करने की आवश्यकता है ताकि सभी प्रस्तुत सुविधाएँ उपलब्ध हों।



उदाहरण



मैं एक डेमो का उपयोग कर रहा हूं, जिसे मैंने मामूली संशोधनों के साथ WebFomsAndMef उदाहरण से लिया था।



प्रत्येक एप्लिकेशन तत्व [PartCreationPolicy(CreationPolicy.NonShared)]



विशेषता के साथ SampleCompositionPart



वर्ग का आयात करता है, जो यह सुनिश्चित करता है कि SampleCompositionPart



एक नया उदाहरण आयात अधिनियम SampleCompositionPart



दौरान SampleCompositionPart



गया है। इस वर्ग में एक एकल Id



फ़ील्ड है जो मार्गदर्शक देता है।



आवेदन वर्तमान में प्रदर्शित तत्व के लिए गाइड मूल्य प्रदर्शित करता है - पृष्ठ, नियंत्रण, उपयोगकर्ता नियंत्रण, पेज मास्टर HttpHandler



और HttpModule







एक उदाहरण:

///PageSample.aspx <br><asp:Content ID= "BodyContent" runat= "server" ContentPlaceHolderID= "MainContent" ><br> <% =SamplePart.Id %><br></asp:Content><br> <br> ///PageSample.cs <br> public partial class PageSample : System.Web.UI. Page <br>{<br> [Import]<br> public SampleCompositionPart SamplePart<br> {<br> get ;<br> set ;<br> }<br>} <br><br> * This source code was highlighted with Source Code Highlighter .







सोर्स कोड यहां से डाउनलोड किया जा सकता है



मुझे उम्मीद है कि यह लेख asp.net WebForms अनुप्रयोगों में MEF का उपयोग करने में मदद करता है।



All Articles