• Asp.net Vnext 模块化实现


    概述


     本文已经同步到《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引用

    运行程序

     http://pan.baidu.com/s/1eQdakoy 下载地址

  • 相关阅读:
    IPC——信号量
    IPC——命名管道
    IPC——匿名管道
    IPC——信号
    管道和命名管道
    Oracle业务用户密码过期问题的解决
    Oracle获取数据库中的对象创建语句
    RAC禁用DRM特性
    配置Server Side TAF
    同一环境下新建Standby RAC库
  • 原文地址:https://www.cnblogs.com/liek/p/4619206.html
Copyright © 2020-2023  润新知