Asp.net Vnext 模块化实现

概述



在程序中实现模块化可以加快开发效率,通过替换模块实现升级.

架构



vnext 没有 Virtualpathprovider,本文通过IFileProvider实现模块

ModularVNext.Startup 启动类

   public class Startup
    {
        private IFileProvider _modulesFileProvider;
        private readonly string ApplicationBasePath;
        private readonly IAssemblyLoadContextAccessor _assemblyLoadContextAccessor;
        private readonly IAssemblyLoaderContainer _assemblyLoaderContainer;
        public Startup(IHostingEnvironment hostingEnvironment,
            IApplicationEnvironment applicationEnvironment,
            IAssemblyLoaderContainer assemblyLoaderContainer,
            IAssemblyLoadContextAccessor assemblyLoadContextAccessor)
            {
            //程序集加载上下文访问
            _assemblyLoadContextAccessor = assemblyLoadContextAccessor;
            //程序集加载容器
            _assemblyLoaderContainer = assemblyLoaderContainer;
            //程序基本路径
            ApplicationBasePath = applicationEnvironment.ApplicationBasePath;
            Configuration = new Configuration()
                .AddJsonFile("config.json")
                .AddEnvironmentVariables();
            }

        public IConfiguration Configuration { get; set; }

        public void ConfigureServices(IServiceCollection services)
        {
            var basePaths = Configuration.Get("additionalFileProviderBasePaths")?.Split(‘;‘) ?? new string[] { };
            var modulesPath = Path.Combine(ApplicationBasePath.Substring(0,ApplicationBasePath.IndexOf("src")), Configuration.Get("moduleLoadPath"));

            var moduleAssemblies = LoadAssembliesFrom(modulesPath, _assemblyLoaderContainer, _assemblyLoadContextAccessor);

            _modulesFileProvider = GetModulesFileProvider(basePaths, moduleAssemblies);

            services.AddInstance(Configuration);

            services.AddMvc();

            services.Configure<RazorViewEngineOptions>(o =>
            {
                o.FileProvider = _modulesFileProvider;
            });

            services.AddInstance(new ModuleAssemblyLocator(moduleAssemblies));
            services.AddTransient<DefaultAssemblyProvider>();
            services.AddTransient<IAssemblyProvider, ModuleAwareAssemblyProvider>();
            }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
        {
            loggerfactory.AddConsole();

            if (string.Equals(env.EnvironmentName, "Development", StringComparison.OrdinalIgnoreCase))
                {
                app.UseBrowserLink();
                app.UseErrorPage(ErrorPageOptions.ShowAll);
                }
            else
                {
                app.UseErrorHandler("/Home/Error");
                }

            app.UseStaticFiles(new StaticFileOptions
                {
                FileProvider = _modulesFileProvider
                });

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "areaRoute",
                    template: "{area:exists}/{controller}/{action}",
                    defaults: new { controller = "Home", action = "Index" }
                    );
                routes.MapRoute(
                    name: "default",
                    template: "{controller}/{action}/{id?}",
                    defaults: new { controller = "Home", action = "Index" });
            });
            }

        private List<Assembly> LoadAssembliesFrom(string modulesDirectory,
          IAssemblyLoaderContainer assemblyLoaderContainer,
          IAssemblyLoadContextAccessor loadContextAccessor)
            {
            var assemblies = new List<Assembly>();
            var loadContext = _assemblyLoadContextAccessor.GetLoadContext(typeof(Startup).GetTypeInfo().Assembly);
            using (assemblyLoaderContainer.AddLoader(new DirectoryLoader(modulesDirectory, loadContext)))
                {

                foreach (var modulePath in Directory.EnumerateFiles(@"C:\Users\Administrator\Documents\Visual Studio 2015\Projects1\ModularVNext\artifacts\bin\Module1\Debug\dnx451", "*.dll"))
                    {
                    var name = Path.GetFileNameWithoutExtension(modulePath);
                    assemblies.Add(loadContext.Load(name));
                    }
                }
            return assemblies;
            }

        private IFileProvider GetModulesFileProvider(string[] basePaths, List<Assembly> moduleAssemblies)
            {

            var redirectedFileProviders = basePaths
                .Select(path => Path.IsPathRooted(path) ? path : Path.Combine(ApplicationBasePath, path))
                .Select(root => new PhysicalFileProvider(root)).ToList();

            var resourceFileProviders = moduleAssemblies.Select(a => new SafeEmbeddedFileProvider(a)).ToList();

         var redirectedFileProviders1=  redirectedFileProviders.Select(x => x as IFileProvider);
            var resourceFileProviders1=   resourceFileProviders.Select(x => x as IFileProvider);
          var co=  redirectedFileProviders1.Concat<IFileProvider>(resourceFileProviders1).ToList();

            IFileProvider rootProvider = new PhysicalFileProvider(ApplicationBasePath);

            co.Add(rootProvider);
            return new CompositeFileProvider(co);

            }

        }

ConfigureServices 方法主要是获取模块程序集和模块程序提供者

 var moduleAssemblies = LoadAssembliesFrom(modulesPath, _assemblyLoaderContainer, _assemblyLoadContextAccessor);

通过LoadAssembliesFrom方法获取模块程序集

参数:

modulesPath 模块的路径

也就是 Module1的程序集路径

选择该选项,然后编译就可以输出程序集了

在根目录下\artifacts\bin\Module1\Debug\会产生两个程序集分别是 dnx451 和 dnxcore50 ,这里我选择的是dnx451

集体实现

  private List<Assembly> LoadAssembliesFrom(string modulesDirectory,
          IAssemblyLoaderContainer assemblyLoaderContainer,
          IAssemblyLoadContextAccessor loadContextAccessor)
            {
            var assemblies = new List<Assembly>();

            //程序集加载上下文
            var loadContext = _assemblyLoadContextAccessor.GetLoadContext(typeof(Startup).GetTypeInfo().Assembly);

              //添加程序集加载
            using (assemblyLoaderContainer.AddLoader(new DirectoryLoader(modulesDirectory, loadContext)))
                {

                //找出文件夹下的程序集,我这里写的是硬编码
                foreach (var modulePath in Directory.EnumerateFiles(@"C:\Users\Administrator\Documents\Visual Studio 2015\Projects1\ModularVNext\artifacts\bin\Module1\Debug\dnx451", "*.dll"))
                    {
                    var name = Path.GetFileNameWithoutExtension(modulePath);
                    //加载程序集
                    assemblies.Add(loadContext.Load(name));
                    }
                }
            return assemblies;
            }

返回程序集在条用_modulesFileProvider 获取文件提供者然后把获取到的文件提供者设置到RazorViewEngineOptions

            services.Configure<RazorViewEngineOptions>(o =>
            {
                o.FileProvider = _modulesFileProvider;
            });

ModularVNext.Infrastructure.CompositeFileProvider这是实现IFileProvider的类

   public class CompositeFileProvider : IFileProvider
    {
        //提供者目录
        private List<IFileProvider> _fileProviders;
        //触发器
        private readonly Dictionary<string, TestFileTrigger> _fileTriggers =
            new Dictionary<string, TestFileTrigger>(StringComparer.Ordinal);
        public CompositeFileProvider(IEnumerable<IFileProvider> fileProviders)
        {
            _fileProviders = fileProviders.ToList();
        }

        public IDirectoryContents GetDirectoryContents(string subpath)
        {
            foreach (var fileProvider in _fileProviders)
            {
                //更具subpat获取目录
                var contents = fileProvider.GetDirectoryContents(subpath);
                if (contents != null && contents.Exists)
                {
                    return contents;
                }
            }
            return new NotFoundDirectoryContents();
        }

        public IFileInfo GetFileInfo(string subpath)
        {
            foreach (var fileProvider in _fileProviders)
                {//更具subpat获取文件信息
                var fileInfo = fileProvider.GetFileInfo(subpath);
                if (fileInfo != null && fileInfo.Exists)
                {
                    return fileInfo;
                }
            }
            return new NotFoundFileInfo(subpath);
        }

        public IExpirationTrigger Watch(string filter)
        {

            //触发器
           TestFileTrigger trigger;

            trigger = new TestFileTrigger();

            return trigger;

            }
    }

    internal class TestFileTrigger : IExpirationTrigger
        {
        public bool ActiveExpirationCallbacks
            {
            get { return false; }
            }
        private CancellationToken Token { get; set; }
        public bool IsExpired
            {
            get {

                return false; }
            }

        public IDisposable RegisterExpirationCallback(Action<object> callback, object state)
            {
            return null;
            }
        }

没有对Module1引用

运行程序

时间: 2024-08-29 01:03:16

Asp.net Vnext 模块化实现的相关文章

Asp.net Vnext &amp; MVC6 系列

vs 2015  rc  vnext  1.0.0-beta4 ,本系列还将持续继续更新 Asp.net Vnext 调试源码 Asp.net Vnext 自定义日志 Asp.net Vnext 中间件实现基本验证 Asp.net Vnext 实现IView Asp.net Vnext TagHelpers Asp.net Vnext Routing Asp.net Vnext IValueProvider Asp.net Vnext ModelBinding Asp.net Vnext 模块化

ASP.NET vNext 微笔记

关心 ASP.NET vNext 的人可能已经读过相关文章,例如:ASP.NET vNext @ 2014.那么,你可能已经知道,ASP.NET vNext 摆脱了 System.Web.DLL,把 Web API 合并至 MVC 框架,而且更全面地采用 task-based 异步程序模型.因此,我们应该可以期待,采用 vNext 应用程序将会更模块化.有更好的性能.更容易编写异步程序(搭配 C# 的 async/await 语法),而且更容易延展(scale). 此外,同样重要的是知道 ASP

[译]Introducing ASP.NET vNext and MVC 6

原文:http://www.infoq.com/news/2014/05/ASP.NET-vNext?utm_source=tuicool Part of the ASP.NET vNext initiative, ASP.NET MVC 6 represents a fundamental change to how Microsoft constructs and deploys web frameworks. The goal is to create a host agnostic fr

ASP.NET vNext总结:CLR

1.前言 1.1感慨 2015年来了,园子里多了一些<年总结>类的帖子,颇有感触.俺没啥文化,出来打工10年了,人生能有几个10年?命长的话,活个70岁古来稀就知足了.期间换三个职业,N家单位吧,如今真正选择做一名程序员,也有一年时间了.我也不想提及为何成了苦逼的程序员?反正我必须承认这些年来混得挺失败的. 不管是工作上写过年终结,职业规划,就连人生也写过感悟,生活理想.可事实上,写过又能怎样?人的成长是不断变化的,过去的想法,在下一时期,可能又不认同了.还有计划跟不上变化的,这看似是在为没有

ASP.NET vNext or .NET vNext?

ASP.NET vNext or .NET vNext? 从概念和基础开始 vNext在曝光以来绝大多数以ASP.NET vNext这样的的字眼出现,为什么这边会提及.NET vNext?原因是我认为ASP.NET只是其中的一种开发框架而已,其中真正核心重要的乃是底层的支撑层,至于底层还有些什么内容,下面会进行一次分析. .NET Framework.Mono..NET Core都是什么鬼? 相信有不少人对这一次vNext新诞生的名词抱有许多疑惑,它们到底是做什么的?负责什么内容?扮演者什么样的

一步一步学习ASP.NET vNext (一)- 基本概念和环境配置

转发:微软MVP 卢建晖 的文章,希望对大家有帮助. 编者语:时代在变,在csdn开博一年就发了那么的两篇文章,无论是什么原因都觉得有愧了.但是今年重心都会在这里发表一些文章,和大家谈谈.NET, 移动跨平台,云计算等热门话题.希望有更好的交流. 好吧言归正转,开篇和大家先聊一个系列ASP.NET vNext . 相信大家都知道了微软在2014年中开始正式对不同的技术进行了开源.而.NET开源对于微软商业上和技术上都有不同程度的影响.说句实在的,mono社区这么多年终于有了个名份了.这里特别谢谢

微软下一代云环境Web开发框架ASP.NET vNext预览

微软在2014年5月12日的TechEd大会上宣布将会发布下一代ASP.NET框架ASP.NET vNext的预览.此次发布的ASP.NET框架与以前相比发生了根本性的变化,凸显了微软"云优先"(cloud-first)的新战略思想.微软员工Scott Hanselman发布博客对ASP.NET vNext进行了简要介绍.以下为其博客的翻译. 原文:http://www.hanselman.com/blog/IntroducingASPNETVNext.aspx 译文发布地址:http

Asp.net vNext 学习之路(一)

概述 asp.net vNext 也叫 asp.net 5.0,意思是微软推出的下一个版本的asp.net.可以说是微软对asp.net的一个比较重大的重新设计, asp.net vNext是一 个比较理想的选择对于构建现代Web应用程序来说.它为部署到云端或者运行在本地的应用程序提供了一个优化的开发框架,它的模块化组件以最小的 开销让你可以灵活地构建你的解决方案. asp.net vNext 包括以下几个特性: 1,新的灵活和跨平台的运行时. 2,新的模块化HTTP请求管道. 3,云计算环境的

ASP.NET vNext:微软下一代云环境Web开发框架

作者 郭蕾 发布于 2014年5月16日 在5月12日的TechED大会上,微软首次向外界介绍了下一代ASP.NET框架--ASP.NET vNext.ASP.NET vNext专门针对云环境和服务器环境进行了优化,并带来了"无编译"( no-compile )开发体验以及依赖注入(Dependency Injection out of box)等令人兴奋的新特性.微软员工Scott Hanselman在其博客中对ASP.NET vNext做了简单介绍. 首先使用ASP.NET vNe