MVC 4 ile MEF ya da 5 Takılabilir Mimarisi (2014)
Orchard CMS gibi bir takılabilir mimarisi ile MVC4/MVC5 bir uygulama oluşturmak için çalışıyorum. Projenin başlangıç ve auth, navigasyon vb ilgilenecek olan bir MVC uygulama var. Sonra ASP.NET sınıf kitaplıkları gibi birden çok modül ayrı olarak inşa edilecek ya da soyunmuş mvc projeleri ve denetleyicileri, görünümler, veri repo vb var.
Web ve indirme örnekler vb eğitimler geçiyor bütün gün geçirdim ve Kenny - http://kennytordeur.blogspot.in/2012/08/mef-in-aspnet-mvc-4-and-webapi.html en iyi örnek olduğunu buldu
Eğer bu DLL referans eklerseniz modülleri(ayrı DLL) denetleyicileri almak mümkün duyuyorum. Ama MEF kullanarak arkasındaki nedeni zamanında modülleri eklemek için güçlü olmak. Projenin başlangıç ~/// Modülleri bir dizine kopyalanması manzarası ile birlikte Silmek istiyorum (bunu başardım) ve MEF sadece onları almak. Mücadele MEF yük bu kütüphaneler yapmak.
Bu cevap anlatıldığı gibi de MefContrib denemek üzereyim bir sonraki şey ASP.NET MVC 4.0 Controllers and MEF, how to bring these two together?. Ama MEF bakmıyor MVC ile kutunun dışında çalışmak şaşırdım.
Benzer bir mimari çalışma (veya MefContrib olmadan) var mı? Ya bak ben olabilecek herhangi bir mevcut çerçeve biliyor musunuz? Başlangıçta ben bile Orchard CMS sıyırma ve bir çerçeve olarak kullanmayı düşündüm ama çok karmaşık. Ayrıca MVC5 uygulaması geliştirmek için iyi olurdu WebAPİ2 yararlanmak için.
CEVAP
Tarif ettiğin gibi benzer bir takılabilir mimarisi olan bir proje üzerinde çalıştım ve aynı teknolojileri ASP.NET MVC
MEF
kullandı. Kimlik denetimi ele MVC uygulama, yetkilendirme ve tüm istekleri ASP.NET bir ev sahibi vardı. Eklentiler(modüller) alt klasör kopyalandı. Eklentileri de kendi modelleri, kontrolörler, manzaralı, css ve js dosyaları vardı 7 ** uygulamalar yapıldı. Bu da iş yapmak için takip ettiğimiz adımlar şunlardır:
MEF kurma
Uygulama başlangıçta bütün birleştirilebilir parçalar saptadığı motor MEF
göre yarattık ve birleştirilebilir parçaların bir katalog oluşturur. Bu yalnızca bir kez uygulama başlangıç pefromed bir iştir. Motor bizim durumumuzda da Modules(Plugins)
klasöründeki host bin
klasöründe uygulama ya da bulunan tüm plugable parçaları, keşfetmek ister.
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;
}
}
Bu tüm MEF bölümleri keşfi gerçekleştiren sınıf örnek kodu. Sınıf Compose
yöntemi Global.asax.cs
dosyasında Application_Start
yöntemi denir. Kod basitlik için azalır.
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));
}
}
Tüm eklentileri alt-klasör ana bilgisayar uygulamasının kök dizininde bulunan Modules
klasör ayrı kopyalanır varsayılmıştır. Her eklenti klasörü Views
alt klasör ve her eklenti dll
içerir. Ayrıca özel denetleyicisi fabrika ve aşağıda tarif etmem olacak özel bir görünüm motoru başlatılır yukarıda Application_Start
yöntemi.
MEF okur denetleyicisi fabrika oluşturma
İsteği işlemek için gereken denetleyicisi keşfedeceksiniz ki: burada özel kumanda fabrika tanımlama kodu
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();
}
}
}
Ayrıca her denetleyici Export
öznitelik ile işaretlenmiş olmalıdır:
[Export("Plugin1", typeof(IController))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class Plugin1Controller : Controller
{
//
// GET: /Plugin1/
public ActionResult Index()
{
return View();
}
}
Export
öznitelik oluşturucu ilk parametre sözleşme adını belirtir ve eşsiz her Denetleyici olarak tanımlar çünkü benzersiz olmalıdır. PartCreationPolicy
kontrolörleri, birden çok kişi için yeniden kullanılamaz çünkü Paylaşılmayan için ayarlanmış olması gerekir.
Görünüm Altyapısı oluşturma eklentileri manzarası bulmak için bilir
Özel görünüm altyapısı oluşturulması kongre tarafından görünüm motoru ana uygulama Views
klasör sadece görünüm görünüyor, çünkü gereklidir. Eklentileri Modules
ayrı klasörde olduğu için, Görünüm motoru oraya bakmayı anlatmaya da ihtiyacımız var.
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();
}
}
Eklentileri türü kesin belirlenmiş görünümleri ile sorunu çözmek
Sadece yukarıdaki kodu kullanarak, modelleri bin
klasörün dışında var çünkü eklentiler(modüller) türü kesin belirlenmiş görünümleri kullanma, bulamadık. Bu sorunu çözmek için izleyin aşağıdaki link.
ld: sembol dyld_stub_binding_helper bu...
&; "Uyarı: iPhone uygulamaları armv6 m...
derleme uyarı: i386 mimarisi için dosy...
(s) mimarisi: i386 için bulunan sembol...
Memcache(d) aşırı hızdan vs Vernik 3 k...