설명하신 것과 유사한 플러그 형 아키텍처가있는 프로젝트에서 작업했으며 동일한 기술인 ASP.NET MVC 및 MEF를 사용했습니다. 인증, 권한 부여 및 모든 요청을 처리하는 호스트 ASP.NET MVC 응용 프로그램이 있습니다. 플러그인 (모듈)은 하위 폴더에 복사되었습니다. 플러그인은 자체 모델, 컨트롤러, 뷰, css 및 js 파일이있는 ASP.NET MVC 응용 프로그램이기도합니다. 다음은 작동하도록하기 위해 수행 한 단계입니다.
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
{
public ActionResult Index()
{
return View();
}
}
Export
특성 생성자 의 첫 번째 매개 변수 는 계약 이름을 지정하고 각 컨트롤러를 고유하게 식별하므로 고유해야합니다. 는 PartCreationPolicy
컨트롤러가 여러 요청에 재사용 할 수 없기 때문에 공유 안로 설정해야합니다.
플러그인에서보기를 찾는 것을 알고있는보기 엔진 만들기
관례 상보기 엔진은 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
폴더 외부에 존재하기 때문에 플러그인 (모듈)에서 강력한 형식의 뷰를 사용할 수 없었습니다 . 이 문제를 해결하려면 다음 링크를 따르십시오 .