c# एमवीसी 4 या 5 के साथ एमईएफ-प्लग करने योग्य वास्तुकला(2014)




asp.net .net (3)

मैं ऑर्कर्ड सीएमएस जैसे प्लग-इन आर्किटेक्चर के साथ एक एमवीसी 4 / एमवीसी 5 एप्लीकेशन बनाने की कोशिश कर रहा हूं। तो मेरे पास एक एमवीसी एप्लीकेशन है जो स्टार्टअप प्रोजेक्ट होगा और ऑथ, नेविगेशन इत्यादि का ख्याल रखेगा। फिर एएसपीनेट क्लास लाइब्रेरीज़ के रूप में अलग-अलग बनाए गए कई मॉड्यूल होंगे या एमवीसी परियोजनाओं को तोड़ दिया जाएगा और नियंत्रक, विचार, डेटा रिपोज इत्यादि होंगे।

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

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

इस जवाब में एएसपी.नेट एमवीसी 4.0 कंट्रोलर और एमईएफ में बताया गया है कि मेफकंट्रिब भी है , इन दोनों को एक साथ कैसे लाया जाए? जो अगली बात मैं कोशिश करने जा रहा हूं। लेकिन मुझे हैरान है कि एमईएफ एमवीसी के साथ बॉक्स से बाहर काम नहीं करता है।

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


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

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


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


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

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

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 फ़ोल्डर के रूट में स्थित Modules फ़ोल्डर के एक अलग उप-फ़ोल्डर में कॉपी किया गया है। प्रत्येक प्लगइन सबफ़ोल्डर में Views उप-फ़ोल्डर और प्रत्येक प्लगइन से डीएल शामिल होता है। उपरोक्त 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 विशेषता कन्स्ट्रक्टर का पहला पैरामीटर अद्वितीय होना चाहिए क्योंकि यह अनुबंध नाम निर्दिष्ट करता है और विशिष्ट रूप से प्रत्येक नियंत्रक की पहचान करता है। PartCreationPolicy को NonShared पर सेट किया जाना चाहिए क्योंकि एकाधिक अनुरोधों के लिए नियंत्रकों का पुन: उपयोग नहीं किया जा सकता है।

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

कस्टम व्यू इंजन का निर्माण आवश्यक है क्योंकि सम्मेलन द्वारा व्यू इंजन होस्ट होस्ट के 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 फ़ोल्डर के बाहर मौजूद थे। इस समस्या को हल करने के लिए निम्न link का पालन link





mef