एमईएफ कैसे काम करता है इसके अधिकांश उदाहरण कंसोल या WPF अनुप्रयोग हैं। क्यों? क्योंकि इस मामले में यह जीवन के लिए भागों को नियंत्रित करना सबसे आसान है। MEF खुद इस बात का ध्यान रखता है, और डेवलपर उदाहरण के कार्यों पर ध्यान केंद्रित करता है।
वेब अनुप्रयोगों में स्थिति मौलिक रूप से अलग है। डेवलपर्स पेज बनाने, नियंत्रण करने आदि के लिए ज़िम्मेदार नहीं हैं, क्योंकि Asp.net रनटाइम सब कुछ का ख्याल रखता है।
इस प्रकार, वेब अनुप्रयोगों के लिए MEF समर्थन को लागू करने के लिए, आपको दोनों टूल के एल्गोरिदम को संयोजित करना चाहिए।
ज्ञात समाधान
एक उपाय है कि MEF का उपयोग WebForms अनुप्रयोगों के लिए कैसे किया जा सकता है। लेकिन इस उदाहरण की कई महत्वपूर्ण सीमाएँ हैं।
- डेवलपर्स को सभी नियंत्रणों, पृष्ठों और उपयोगकर्ता नियंत्रणों को फिर से इनहेरिट करना चाहिए, जो हमेशा संभव नहीं होता है
- यह उदाहरण
HttpModule
औरHttpHandler
का समर्थन करने के लिए एक समाधान प्रदान नहीं करता है
उच्च स्तरीय वास्तुकला
समाधान का उद्देश्य एमईएफ कंटेनर के लिए फिर से विरासत तंत्र का उपयोग करने और
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 का उपयोग करने में मदद करता है।