概述


本文已经同步到《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(,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 下载地址

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

  1. [译]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 init ...

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

    微软在2014年5月12日的TechEd大会上宣布将会公布下一代ASP.NET框架ASP.NET vNext的预览.此次公布的ASP.NET框架与曾经相比发生了根本性的变化,凸显了微软"云优 ...

  3. ASP.NET vNext or .NET vNext?

    ASP.NET vNext or .NET vNext? 从概念和基础开始 vNext在曝光以来绝大多数以ASP.NET vNext这样的的字眼出现,为什么这边会提及.NET vNext?原因是我认为 ...

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

    ASP.NET vNext (一)- 基本概念和环境配置 转发:微软MVP 卢建晖 的文章,希望对大家有帮助. 编者语:时代在变,在csdn开博一年就发了那么的两篇文章,无论是什么原因都觉得有愧了.但 ...

  5. Asp.net vNext 学习1

    Asp.net vNext 学习之路(一) 概述 asp.net vNext 也叫 asp.net 5.0,意思是微软推出的下一个版本的asp.net.可以说是微软对asp.net的一个比较重大的重新 ...

  6. Introducing ASP.NET vNext and MVC 6

    [译]Introducing ASP.NET vNext and MVC 6 原文:http://www.infoq.com/news/2014/05/ASP.NET-vNext?utm_source ...

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

    作者 郭蕾 发布于 2014年5月16日   在5月12日的TechED大会上,微软首次向外界介绍了下一代ASP.NET框架——ASP.NET vNext.ASP.NET vNext专门针对云环境和服 ...

  8. Asp.net vNext 学习之路(一)

    概述 asp.net vNext 也叫 asp.net 5.0,意思是微软推出的下一个版本的asp.net.可以说是微软对asp.net的一个比较重大的重新设计, asp.net vNext是一 个比 ...

  9. ASP.NET vNext 微笔记

    关心 ASP.NET vNext 的人可能已经读过相关文章,例如:ASP.NET vNext @ 2014.那么,你可能已经知道,ASP.NET vNext 摆脱了 System.Web.DLL,把 ...

随机推荐

  1. django中的认证与登录

    认证登录 django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: 1  authenticate(**credentials)    提供了用户认证,即验证用户名以及密码是否 ...

  2. Python之paramiko模块和SQL连接API

    堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: i ...

  3. Java 9 新特性快速预览

    原文出处:wangwenjun69 Java 8 已经出来三年多的时间了,原本计划2016年七月份release Java 9,但是基于种种原因,Java 9 被推迟到了2017年的3月份,本人也在O ...

  4. java中的悲观锁和乐观锁实现

    悲观锁就是认为并发时一定会有冲突发生,采用互斥的策略.比如java中的synchronized. 而乐观锁是假设并发时不会有冲突发生,如果发生冲突,则操作失败,并不断重试.乐观锁的机制就是CAS(Co ...

  5. python---基础知识回顾(六)网络编程2(处理粘包)

    前戏: 之前在python---基础知识回顾(六)网络编程异步模块中提到过粘包现象,而且在使用twisted中提到过一种处理办法,按行接收lineReceived,当收到\r\n换行符时,才去缓冲区中 ...

  6. 6.redis的分布式锁

    https://www.cnblogs.com/linjiqin/p/8003838.html

  7. CSS3实战之多列

    CSS2中如果要设计多列布局,常用的方法有浮动和定位,但是浮动容易错位,定位无法满足模块的自适应能力,以及模块之间的文档流联动的需要.为了解决多列布局的难题,CSS3新增了多列自动布局功能. 利用多列 ...

  8. Mac下MySQL的卸载

    先停止所有mysql有关进程. 打开控制台一次复制下列所有内容: sudo rm /usr/local/mysql sudo rm -rf /usr/local/mysql* sudo rm -rf ...

  9. .Net多线程之线程安全

    ConcurrentDictionary是.net4.0推出的一套线程安全集合里的其中一个,和它一起被发行的还有ConcurrentStack,ConcurrentQueue等类型,它们的单线程版本( ...

  10. android安全技术技能清单

    大部分android apk都是在裸奔.大部分android程序员,有一些懂得代码混淆,然而,这东西也不靠谱.除去第三方提供的服务的服务的话,大部分android apk就是在裸奔.不过,使用第三方的 ...