如何用MEF实现Asp.Net MVC框架

目的是实现多个Controller类,View在不同的dll里, 供一个大框架调用。 

原理:
1.用MEF实现各个Controller类的dll的导出和导入。
2.用 [ PartCreationPolicy ( CreationPolicy . NonShared )]标记来实现每个Controller在Export时重新创建实例
3.继承DefaultControllerFactory来创建我们自定义的ControllerFactory。
4.用 ControllerBuilder . Current . SetControllerFactory 调用我们创建的ControllerFactory类
5.继承 RazorViewEngine , 实现我们自定义的ViewEngine。
6.用 ViewEngines . Engines . Clear ();
    ViewEngines.Engines.Add(我们实现的自定义ViewEngine);
7.继承VirtualPathProviderVirtualFile实现我们自定义的VirtualPath, 来查找各个子模块的资源(View)
8.用System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(我们自定义的VirtualPathProvider); 
9.子模块中的改变,1:每个View的属性设置为Embedded Resource, 每个Controller类有Export和PartCreationPolicy属性。

集成遇到的问题
1.     修改Controller类:继承IPACSModule,添加[PartCreationPolicy(CreationPolicy.NonShared)]标签
[PartCreationPolicy(CreationPolicy.NonShared)]
public class PatientController : Controller,IPACSModule

2.     修改View的属性Build Action为Embedder Resource
 

        
3.     修改XXXX.Cshtml, 添加@inherits System.Web.Mvc.WebViewPage, 如果Cshtml中有@model, 如:@model  IEnumerable<OrderViewModel>
改为

@using System.Web.WebPages;    
@using System.Web.Mvc;    
@using System.Web.Mvc.Ajax;    
@using System.Web.Mvc.Html;    
@using System.Web.Routing;  

@inherits System.Web.Mvc.WebViewPage<IEnumerable<OrderViewModel>>
@using (Ajax.BeginForm("Submit", new AjaxOptions { UpdateTargetId = "main" }))
{
}


具体代码:
1.框架层的实现:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;
using System.Web.Mvc;
using System.Web.WebPages;
using AddIn.Interface;
using System.Globalization;
using System.ComponentModel.Composition.Primitives;
 
namespace Common
{
    public class ExtensionHelper
    {
        [ImportMany(AllowRecomposition = true)]
        public IEnumerable<IPACSModule> PACSModules { get; set; }
 
        public CompositionContainer _container;
 
        public void Initialize()
        {
            AggregateCatalog catalog = new AggregateCatalog();
 
            catalog.Catalogs.Add(new AggregateCatalog(
                new DirectoryCatalog(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")),
                new AssemblyCatalog(typeof(Controller).Assembly),
                new TypeCatalog(typeof(IPACSModule))
                ));
 
            _container = new CompositionContainer(catalog);
 
            try
            {
                _container.ComposeParts(this);
            }
            catch (CompositionException ex)
            {
                throw new SystemException(ex.Message, ex);
            }
 
            //Set Custom Controller
            ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
 
            //Set Custom ViewEngine
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new CustomViewEngine());
 
            //Register a virtual path provider
            System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(new CustomVirtualPathProvider());        
        }
    }
 
    public class CustomControllerFactory : DefaultControllerFactory 
    {
        protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            //{call AddIn controller 
            var export = MvcApplication._extHelper._container.GetExports<IPACSModule>()
                .Where(e => e.Value.GetType().Equals(controllerType))
                .FirstOrDefault();
 
            if (null != export)
            {
                return export.Value as Controller;
            }
            else
            {
                return base.GetControllerInstance(requestContext, controllerType);
            }
            //end AddIn controller}
        }
 
        public override void ReleaseController(IController controller)
        {
            IDisposable disposable = controller as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            } 
 
            //base.ReleaseController(controller);
        }
    }
 
    public class CustomViewEngine : RazorViewEngine
    {
        public CustomViewEngine()
        {
            base.AreaViewLocationFormats = new string[] 
            { "~/Areas/{2}/Views/{1}/{0}.cshtml", 
                "~/Areas/{2}/Views/Shared/{0}.cshtml"};
 
            base.AreaMasterLocationFormats = new string[] 
            { "~/Areas/{2}/Views/{1}/{0}.cshtml", 
                "~/Areas/{2}/Views/Shared/{0}.cshtml" };
 
            base.AreaPartialViewLocationFormats = new string[] 
            { "~/Areas/{2}/Views/{1}/{0}.cshtml",
                "~/Areas/{2}/Views/Shared/{0}.cshtml" };
 
            base.ViewLocationFormats = new string[] 
            { "~/Views/{1}/{0}.cshtml",
                "~/Views/Shared/{0}.cshtml",
                "~/PACSModule/Views/{1}/{0}.cshtml",
                "~/PACSModule/Views/Shared/{0}.cshtml"};
 
            base.MasterLocationFormats = new string[] 
            { "~/Views/{1}/{0}.cshtml",
                "~/Views/Shared/{0}.cshtml", 
                "~/PACSModule/Views/{1}/{0}.cshtml", 
                "~/PACSModule/Views/Shared/{0}.cshtml", 
                "~/PACSModule/Views/{0}.cshtml"};
 
            base.PartialViewLocationFormats = new string[]
            { "~/Views/{1}/{0}.cshtml", 
                "~/Views/Shared/{0}.cshtml", 
                "~/PACSModule/Views/{1}/{0}.cshtml",
                "~/PACSModule/Views/Shared/{0}.cshtml",
                "~/PACSModule/Views/{0}.cshtml"};
 
            base.FileExtensions = new string[] { "cshtml"};
        }
 
        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            var dllName = controllerContext.Controller.GetType().Module.Name;
 
            return base.CreatePartialView(controllerContext, partialPath.Replace("PACSModule", dllName));
        }
 
        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            var dllName = controllerContext.Controller.GetType().Module.Name;
 
            RazorView razorView = new RazorView(controllerContext, viewPath.Replace("PACSModule", dllName), masterPath, false, base.FileExtensions, base.ViewPageActivator);
   
            return razorView;
        }
 
        protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
        {
            var dllName = controllerContext.Controller.GetType().Module.Name;
 
            try
            {
                    return base.FileExists(controllerContext, virtualPath.Replace("PACSModule", dllName));   
            }
            catch (System.Exception ex)
            {
                return false;
            }              
        }
    }
 
    public class CustomView : RazorView
    {
        public CustomView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions, IViewPageActivator viewPageActivator)
            : base(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions, viewPageActivator)
        {
        }
 
        protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }
 
            WebViewPage layoutPath = instance as WebViewPage;
            if (layoutPath == null)
            {
                throw new InvalidOperationException("WebViewPage is null.");
            }
 
            layoutPath.VirtualPath = this.ViewPath;
            layoutPath.ViewContext = viewContext;
            layoutPath.ViewData = viewContext.ViewData;
            layoutPath.InitHelpers();
 
            WebPageRenderingBase viewStartPage = null;
            if (this.RunViewStartPages)
            {
                try
                {
                    viewStartPage = StartPage.GetStartPage(layoutPath, "_ViewStart", new string[] { "cshtml" });
                }
                catch
                {
                    viewStartPage = GetStartPage(layoutPath, "~/Views/_ViewStart.cshtml");
                }
            }
 
            WebPageContext pageContext = new WebPageContext(null, null, null);
            layoutPath.ExecutePageHierarchy(pageContext, writer, viewStartPage);
        }
 
        private static StartPage GetStartPage(WebViewPage childPage, string startPagePath)
        {
            StartPage startPage = null;
 
            startPage = childPage.VirtualPathFactory.CreateInstance(startPagePath) as StartPage;
            startPage.VirtualPath = startPagePath;
            startPage.ChildPage = childPage;
            startPage.VirtualPathFactory = childPage.VirtualPathFactory;
 
            return startPage;
        }
    }
 
    public class CustomVirtualPathProvider : VirtualPathProvider
    {
        private bool IsAppResourcePath(string virtualPath)
        {
            String checkPath = VirtualPathUtility.ToAppRelative(virtualPath);
 
            return checkPath.StartsWith("~/xxx", StringComparison.InvariantCultureIgnoreCase);
        }
 
        public override bool FileExists(string virtualPath)
        {
            return (IsAppResourcePath(virtualPath) || base.FileExists(virtualPath));
        }
 
        public override VirtualFile GetFile(string virtualPath)
        {
            if (IsAppResourcePath(virtualPath))
            {
                return new CustomVirtualFile(virtualPath);
            }
            else
            {
                return base.GetFile(virtualPath);
            }
        }
 
        public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            if (IsAppResourcePath(virtualPath))
            {
                string[] parts = virtualPath.Split('/');
                string assemblyName = parts[1];
 
                Assembly asm = Assembly.Load(assemblyName.Replace(".DLL", "").Replace(".dll", ""));
                return new CacheDependency(asm.Location);
            }
            else
            {
                return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
            }
        }
    }
 
    public class CustomVirtualFile : VirtualFile
    {
        private string _virtualPath = "";
 
        public CustomVirtualFile(string virtualPath)
            : base(virtualPath)
        {
            _virtualPath = VirtualPathUtility.ToAppRelative(virtualPath);
        }
 
        public override System.IO.Stream Open()
        {
            string[] parts = _virtualPath.Split('/');
            string assemblyName = parts[1];
            string resourceName = assemblyName.Replace(".DLL", "").Replace(".dll", "") + "." 
                + parts[2] + "."
                + parts[3] + "." 
                + parts[4]; //"UIH.PACS.Workstation.AddIn.Demo."+"Views." + "Controller." + "Action.cshtml"
 
            assemblyName = Path.Combine(HttpRuntime.BinDirectory, assemblyName);
 
            System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(assemblyName);
            if (null != assembly)
            {
                Stream resourceStream = assembly.GetManifestResourceStream(resourceName);
                return resourceStream;
            }
 
            return null;
        }
    }
}
2.IPACSModule就是空接口, 用来各个子模块的controller的Export
    [InheritedExport(typeof(IPACSModule))]
    public interface IPACSModule
    {
 
    }
3.子模块的Controller使用
 [PartCreationPolicy(CreationPolicy.NonShared)]
    public class TestController : Controller, IPACSModule
    {
        //
        // GET: /Test/
 
        public ActionResult Index()
        {
            return View();
        }
 
    }
4. 子模块的View的使用
@inherits System.Web.Mvc.WebViewPage
 
@{
    ViewBag.Title = "Demo/Test/Index.cshtml";
}
 
<div class="content-wrapper">
 
 
    This is Demo's index view for Test
</div>
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值