एमवीसी 4 या 5 के साथ MEF - प्लगेबल आर्किटेक्चर (2014)


80

मैं ऑर्चर्ड सीएमएस जैसे प्लगेबल आर्किटेक्चर के साथ MVC4 / MVC5 एप्लिकेशन बनाने की कोशिश कर रहा हूं। इसलिए मेरे पास एक एमवीसी एप्लिकेशन है जो स्टार्टअप प्रोजेक्ट होगा और ऑउटफिट, नेवीगेशन आदि का ध्यान रखेगा। इसके बाद अलग-अलग मॉड्यूल बनाए जाएंगे, जैसे कि asp.net क्लास लाइब्रेरीज़ या अलग-अलग mvc प्रोजेक्ट्स को छीन लिया गया है और इसमें कंट्रोलर, व्यूज़, डेटा रिपोज़ आदि हैं।

मैंने सारा दिन वेब पर ट्यूटोरियल में जाने और नमूने आदि डाउनलोड करने में बिताया है और पाया है कि केनी के पास सबसे अच्छा उदाहरण है - http://kennytordeur.blogspot.in/2012/08/mef-in-aspnet-mvc-4-and -webapi.html

यदि मैं उन DLL के संदर्भ जोड़ता हूं, तो मैं मॉड्यूल (अलग DLL) से नियंत्रकों को आयात करने में सक्षम हूं। लेकिन एमईएफ का उपयोग करने के पीछे कारण रनटाइम पर मॉड्यूल को जोड़ने में सक्षम है। मैं चाहता हूं कि डीएलएल को स्टार्टअप परियोजना में एक ~ / मॉड्यूल // निर्देशिका में कॉपी किए जाने वाले विचारों के साथ (मैं ऐसा करने में कामयाब रहा) और एमईएफ सिर्फ उन्हें उठाएगा। MEF को इन पुस्तकालयों को बनाने के लिए संघर्ष करना।

ASP.NET MVC 4.0 नियंत्रकों और MEF के इस उत्तर में बताया गया है कि MefContrib भी है , इन दोनों को एक साथ कैसे लाया जाए? जो मैं करने की कोशिश कर रहा हूँ अगली बात है। लेकिन मुझे आश्चर्य है कि एमईएफ एमवीसी के साथ बॉक्स से बाहर काम नहीं करता है।

क्या किसी को भी (MefContrib के साथ या बिना) एक समान आर्किटेक्चर मिला है? शुरू में मैंने ऑर्चर्ड सीएमएस को हटाने और इसे एक ढांचे के रूप में उपयोग करने के बारे में भी सोचा था लेकिन यह बहुत जटिल है। WebAPI2 का लाभ लेने के लिए MVC5 में ऐप विकसित करना अच्छा होगा।


1
क्या आपको MVC5 के साथ काम करने के लिए यह सेटअप मिला है? मैं एमवीसी 5 के साथ एक ही चीज़ को सेटअप करने की कोशिश कर रहा हूं। आपकी मदद की सराहना की जाती है
जूनियर

1
यहाँ एक प्रतिस्पर्धा उदाहरण है जिसमें EF को लागू करने वाले संस्करण हैं और ASP.net Seems पूरा करते हैं। codeproject.com/Articles/1109475/…
ब्राउनी नोनी

अधिक अनुप्रयोग MEF का उपयोग क्यों नहीं करते हैं? हर कोई इस पर अपना रोल करने लगता है।
जॉनी

जवाबों:


105

मैंने एक ऐसी परियोजना पर काम किया है, जिसमें आपके द्वारा वर्णित समान प्लग-योग्य आर्किटेक्चर था और इसमें उन्हीं तकनीकों का उपयोग किया गया था। ASP.NET MVC और MEF। हमारे पास एक होस्ट ASP.NET MVC एप्लिकेशन था जिसने प्रमाणीकरण, प्राधिकरण और सभी अनुरोधों को संभाला। हमारे प्लगइन्स (मॉड्यूल) को एक उप-फ़ोल्डर में कॉपी किया गया था। प्लगइन्स ASP.NET MVC एप्लिकेशन भी थे जिनके अपने मॉडल, नियंत्रक, विचार, सीएसएस और जेएस फाइलें थीं। ये कदम हैं जो हमने इसे काम करने के लिए अनुसरण किए हैं:

MEF की स्थापना

हमने एमईएफ पर आधारित इंजन बनाया जो सभी कंपार्टेबल पार्ट्स को एप्लिकेशन स्टार्ट पर डिस्क्राइब करता है और कंपोजेबल पार्ट्स का कैटलॉग बनाता है। यह एक ऐसा कार्य है जो केवल एक बार आवेदन शुरू होने पर किया जाता है। इंजन को सभी प्लग करने योग्य भागों की खोज करने की आवश्यकता है, कि हमारे मामले binमें मेजबान एप्लिकेशन के Modules(Plugins)फ़ोल्डर में या फ़ोल्डर में स्थित थे ।

public class Bootstrapper
{
    private static CompositionContainer CompositionContainer;
    private static bool IsLoaded = false;

    public static void Compose(List<string> pluginFolders)
    {
        if (IsLoaded) return;

        var catalog = new AggregateCatalog();

        catalog.Catalogs.Add(new DirectoryCatalog(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")));

        foreach (var plugin in pluginFolders)
        {
            var directoryCatalog = new DirectoryCatalog(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules", plugin));
            catalog.Catalogs.Add(directoryCatalog);

        }
        CompositionContainer = new CompositionContainer(catalog);

        CompositionContainer.ComposeParts();
        IsLoaded = true;
    }

    public static T GetInstance<T>(string contractName = null)
    {
        var type = default(T);
        if (CompositionContainer == null) return type;

        if (!string.IsNullOrWhiteSpace(contractName))
            type = CompositionContainer.GetExportedValue<T>(contractName);
        else
            type = CompositionContainer.GetExportedValue<T>();

        return type;
    }
}

यह उस वर्ग का नमूना कोड है जो सभी MEF भागों की खोज करता है। फ़ाइल में विधि Composeसे कक्षा की विधि को कहा जाता है । कोड सादगी के लिए कम किया गया है।Application_StartGlobal.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        var pluginFolders = new List<string>();

        var plugins = Directory.GetDirectories(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Modules")).ToList();

        plugins.ForEach(s =>
        {
            var di = new DirectoryInfo(s);
            pluginFolders.Add(di.Name);
        });

        AreaRegistration.RegisterAllAreas();
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        Bootstrapper.Compose(pluginFolders);
        ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
        ViewEngines.Engines.Add(new CustomViewEngine(pluginFolders));
    }
}

यह माना जाता है कि सभी प्लगइन्स को फ़ोल्डर के एक अलग उप-फ़ोल्डर में कॉपी किया Modulesजाता है जो होस्ट एप्लिकेशन की जड़ में स्थित है। प्रत्येक प्लगइन सबफ़ोल्डर में प्रत्येक Viewsफ़ोल्डर से उप-फ़ोल्डर और DLL शामिल हैं। Application_Startऊपर की विधि में भी कस्टम नियंत्रक कारखाने और कस्टम व्यू इंजन को इनिशियलाइज़ किया गया है जिसे मैं नीचे परिभाषित करूंगा।

नियंत्रक कारखाना बनाना जो एमईएफ से पढ़ता है

यहाँ कस्टम नियंत्रक कारखाने को परिभाषित करने के लिए कोड है जो अनुरोध को संभालने के लिए नियंत्रक की खोज करेगा:

public class CustomControllerFactory : IControllerFactory
{
    private readonly DefaultControllerFactory _defaultControllerFactory;

    public CustomControllerFactory()
    {
        _defaultControllerFactory = new DefaultControllerFactory();
    }

    public IController CreateController(RequestContext requestContext, string controllerName)
    {
        var controller = Bootstrapper.GetInstance<IController>(controllerName);

        if (controller == null)
            throw new Exception("Controller not found!");

        return controller;
    }

    public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
    {
        return SessionStateBehavior.Default;
    }

    public void ReleaseController(IController controller)
    {
        var disposableController = controller as IDisposable;

        if (disposableController != null)
        {
            disposableController.Dispose();
        }
    }
}

इसके अतिरिक्त प्रत्येक नियंत्रक को Exportविशेषता के साथ चिह्नित किया जाना चाहिए :

[Export("Plugin1", typeof(IController))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Plugin1Controller : Controller
{
    //
    // GET: /Plugin1/
    public ActionResult Index()
    {
        return View();
    }
}

Exportविशेषता निर्माता का पहला पैरामीटर अद्वितीय होना चाहिए क्योंकि यह अनुबंध नाम निर्दिष्ट करता है और विशिष्ट रूप से प्रत्येक नियंत्रक की पहचान करता है। PartCreationPolicyNonShared करने के लिए सेट किया जाना चाहिए क्योंकि नियंत्रकों से अधिक अनुरोध के लिए पुन: उपयोग नहीं किया जा सकता।

व्यू इंजन बनाना जो प्लगइन्स से विचारों को जानना जानता है

कस्टम व्यू इंजन के निर्माण की आवश्यकता है क्योंकि कन्वेंशन द्वारा व्यू इंजन केवल Viewsहोस्ट एप्लिकेशन के फ़ोल्डर में विचारों के लिए दिखता है । चूंकि प्लगइन्स अलग Modulesफ़ोल्डर में स्थित हैं , इसलिए हमें वहां भी देखने के लिए व्यू इंजन को बताने की आवश्यकता है।

public class CustomViewEngine : RazorViewEngine
{
    private List<string> _plugins = new List<string>();

    public CustomViewEngine(List<string> pluginFolders)
    {
        _plugins = pluginFolders;

        ViewLocationFormats = GetViewLocations();
        MasterLocationFormats = GetMasterLocations();
        PartialViewLocationFormats = GetViewLocations();
    }

    public string[] GetViewLocations()
    {
        var views = new List<string>();
        views.Add("~/Views/{1}/{0}.cshtml");

        _plugins.ForEach(plugin =>
            views.Add("~/Modules/" + plugin + "/Views/{1}/{0}.cshtml")
        );
        return views.ToArray();
    }

    public string[] GetMasterLocations()
    {
        var masterPages = new List<string>();

        masterPages.Add("~/Views/Shared/{0}.cshtml");

        _plugins.ForEach(plugin =>
            masterPages.Add("~/Modules/" + plugin + "/Views/Shared/{0}.cshtml")
        );

        return masterPages.ToArray();
    }
}

प्लगइन्स में दृढ़ता से टाइप किए गए विचारों के साथ समस्या को हल करें

केवल उपरोक्त कोड का उपयोग करके, हम अपने प्लगइन्स (मॉड्यूल) में दृढ़ता से टाइप किए गए विचारों का उपयोग नहीं कर सकते, क्योंकि मॉडल binफ़ोल्डर के बाहर मौजूद थे । इस समस्या को हल करने के लिए निम्न लिंक का अनुसरण करें


1
कैसे प्रत्येक व्यक्ति मॉड्यूल के लिए कस्टम मार्ग के बारे में? मुझे लगता है कि प्रत्येक moduleneed को रिटेबल और ग्लोबल असैक्स का रेफरी प्राप्त करने के लिए रूट इंटरफ़ेस होना चाहिए जिसमें रूट इंटरफ़ेस मॉड्यूल फ़ोल्डर और कोर दोनों में दिखेगा।
शारिफ y

3
हमने हल किया कि प्रत्येक प्लगइन के लिए अलग क्षेत्र निर्धारित करके। प्रत्येक प्लगइन में हमने एक वर्ग बनाया था जो कि एरियाग्रिगेशन से विरासत में मिला था और RegisterArea पद्धति को ओवरराइड करके हम उन मार्गों को परिभाषित करने में सक्षम थे जिन्हें हम प्लगइन्स में उपयोग करना चाहते थे।
इलिजा डिमोव

10
क्या आपको इस समाधान के लिए कहीं नमूना परियोजना मिली है?
cPDesign

2
मैं cpoDesign से सहमत हूं। एक नमूना परियोजना अच्छी होगी
क्रिस

2
मैं यह भी मानता हूं कि GitHub पर नमूना परियोजना डाउनलोड करने के लिए बहुत अच्छा होगा :)
Kbdavis07

5

बस इस बात से अवगत रहें कि MEF के कंटेनर में एक "अच्छी सुविधा" होती है, जो किसी भी आईडीसोपयोगी वस्तु के संदर्भ को बनाए रखता है, और इससे बड़ी मेमोरी रिसाव हो सकता है। कथित तौर पर स्मृति रिसाव को इस nuget के साथ संबोधित किया जा सकता है - http://nuget.org/packages/NCode.Composition.DisposableParts.Sign


ड्राईआईक कहने का एक और कारण बेहतर है :)
हसन तारेक

3

वहाँ परियोजनाएं हैं जो एक प्लगइन वास्तुकला को लागू करती हैं। आप इनमें से किसी एक का उपयोग करना चाहते हैं या उनके स्रोत कोड पर एक नज़र डाल सकते हैं कि वे इन चीजों को कैसे पूरा करते हैं:

इसके अलावा, बाहरी विधानसभाओं में नियंत्रक पर 404 एक दिलचस्प दृष्टिकोण ले रहा है। मैंने सिर्फ सवाल पढ़कर बहुत कुछ सीखा।

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