MVC 4 또는 5를 사용하는 MEF-플러그 형 아키텍처 (2014)
Orchard CMS와 같은 플러그 형 아키텍처로 MVC4 / MVC5 애플리케이션을 빌드하려고합니다. 그래서 시작 프로젝트가 될 MVC 응용 프로그램이 있고 인증, 탐색 등을 처리합니다. 그런 다음 asp.net 클래스 라이브러리로 별도로 빌드되거나 mvc 프로젝트를 제거하고 컨트롤러, 뷰, 데이터 저장소 등을 포함하는 여러 모듈이 있습니다.
나는 하루 종일 웹에서 튜토리얼을 진행하고 샘플을 다운로드하는 데 보냈고 Kenny가 http://kennytordeur.blogspot.in/2012/08/mef-in-aspnet-mvc-4-and -webapi.html
해당 DLL에 대한 참조를 추가하면 모듈 (별도의 DLL)에서 컨트롤러를 가져올 수 있습니다. 그러나 MEF를 사용하는 이유는 런타임에 모듈을 추가 할 수 있기 때문입니다. 보기와 함께 DLL을 시작 프로젝트의 ~ / Modules // 디렉터리에 복사하고 싶습니다 (이 작업을 수행했습니다). MEF가이를 선택합니다. MEF가 이러한 라이브러리를로드하도록 고군분투합니다.
이 답변 ASP.NET MVC 4.0 컨트롤러 및 MEF 에서 설명한대로 MefContrib도 있습니다. 이 두 가지를 함께 가져 오는 방법은 무엇입니까? 다음으로 시도 할 것입니다. 그러나 MEF가 MVC에서 기본적으로 작동하지 않는다는 것이 놀랍습니다.
MefContrib의 유무에 관계없이 유사한 아키텍처가 작동하는 사람이 있습니까? 처음에는 Orchard CMS를 제거하고 프레임 워크로 사용할 생각도했지만 너무 복잡합니다. WebAPI2를 활용하기 위해 MVC5에서 앱을 개발하는 것도 좋을 것입니다.
설명하신 것과 유사한 플러그 형 아키텍처를 가진 프로젝트에서 작업했으며 동일한 기술 ASP.NET MVC
과 MEF
. 인증, 권한 부여 및 모든 요청을 처리하는 호스트 ASP.NET MVC 응용 프로그램이 있습니다. 플러그인 (모듈)은 하위 폴더에 복사되었습니다. 플러그인은 ASP.NET MVC
자체 모델, 컨트롤러, 뷰, css 및 js 파일 이있는 애플리케이션 이기도 합니다. 다음은 작동하도록하기 위해 수행 한 단계입니다.
MEF 설정
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_Start
의 방법 Global.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
방법 에서는 커스텀 컨트롤러 팩토리와 아래에서 정의 할 커스텀 뷰 엔진도 초기화됩니다.
MEF에서 읽는 컨트롤러 팩토리 만들기
다음은 요청을 처리해야하는 컨트롤러를 검색 할 사용자 지정 컨트롤러 팩토리를 정의하는 코드입니다.
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();
}
}
The first parameter of the Export
attribute constructor must be unique because it specifies the contract name and uniquely identifies each controller. The PartCreationPolicy
must be set to NonShared because controllers cannot be reused for multiple requests.
Creating View Engine that knows to find the views from the plugins
Creation of custom view engine is needed because the view engine by convention looks for views only in the Views
folder of the host application. Since the plugins are located in separate Modules
folder, we need to tell to the view engine to look there also.
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();
}
}
Solve the problem with strongly typed views in the plugins
By using only the above code, we couldn't use strongly typed views in our plugins(modules), because models existed outside of the bin
folder. To solve this problem follow the following link.
Just be aware that MEF's container has a "nice feature" that keeps references to any IDisposable object it creates, and will lead to huge memory leak. Allegedly the memory leak can be addressed with this nuget - http://nuget.org/packages/NCode.Composition.DisposableParts.Signed
There are projects out there that implement a plugin architecture. You might want to use one of these or to have a look at their source code to see how they accomplish these things:
- ASP.NET MVC Plugin Framework (using MVC 4)
- .NET 4.0 ASP.NET MVC 3 plug-in architecture with embedded views (obviously using MVC 3 but fundamental principles might still apply)
Also, 404 on Controllers in External Assemblies is taking an interesting approach. I learned a lot by just reading the question.
참고URL : https://stackoverflow.com/questions/21017036/mef-with-mvc-4-or-5-pluggable-architecture-2014
'your programing' 카테고리의 다른 글
WPF 치트 시트를 사용할 수 있습니까? (0) | 2020.10.10 |
---|---|
C에서 setjmp 및 longjmp의 실제 사용 (0) | 2020.10.10 |
64 비트 운영 체제에서 32 비트 프로세스가 액세스 할 수있는 메모리는 얼마나됩니까? (0) | 2020.10.10 |
생성자를 사용할 때와 getInstance () 메서드 (정적 팩토리 메서드)를 사용할 때 (0) | 2020.10.10 |
SVN에서 버전이 지정되지 않은 모든 파일 목록을 얻으려면 어떻게해야합니까? (0) | 2020.10.09 |