概述


本文已经同步到《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. 转:Block原理及引用循环问题

    2010年WWDC发布iOS4时Apple对Objective-C进行了一次重要的升级:支持Block.说到底这东西就是闭包,其他高级语音例如Java和C++已有支持,第一次使用Block感觉满简单好 ...

  2. python---基础知识回顾(十)进程和线程(进程)

    前戏:进程和线程的概念 若是学过linux下的进程,线程,信号...会有更加深刻的了解.所以推荐去学习下,包括网络编程都可以去了解,尤其是对select,poll,epoll都会有更多的认识. 进程就 ...

  3. 你知道吗?10个精妙的 Java 编码最佳实践

    这是一个比Josh Bloch的Effective Java规则更精妙的10条Java编码实践的列表.和Josh Bloch的列表容易学习并且关注日常情况相比,这个列表将包含涉及API/SPI设计中不 ...

  4. C# 中printDocument打印、预览、打印机设置和打印属性的方法

    private void Form1_Load(object sender, System.EventArgs e) { //获取或设置一个值,该值指示是否发送到文件或端口 printDocument ...

  5. 【leetcode 简单】 第六十一题 存在重复元素

    给定一个整数数组,判断是否存在重复元素. 如果任何值在数组中出现至少两次,函数返回 true.如果数组中每个元素都不相同,则返回 false. 示例 1: 输入: [1,2,3,1] 输出: true ...

  6. Python概念-迭代器的__iter__和__next__

    大家都知道__iter__是可迭代对象和迭代器的独有方法,也知道__next__是迭代器的 既然已经学了面向对象了,那么如何自己写一个: 代码示例: # 编辑者:闫龙 class Range: def ...

  7. D - Balanced Ternary String (贪心)

    题目链接:http://codeforces.com/contest/1102/problem/D 题目大意:给你一个字符串,这个字符串是由0,1,2构成的,然后让你替换字符,使得在替换的次数最少的前 ...

  8. CSS 实现单边阴影

    box-shadow: 0px -15px 10px -15px #111; 五个值分别为:x y blur spread color 将 spread 设置成 blur 的负值即可 这种只适用于 o ...

  9. python 面试题3

    注:本面试题来源于网络. 1.python下多线程的限制以及多进程中传递参数的方式 python多线程有个全局解释器锁(global interpreter lock),这个锁的意思是任一时间只能有一 ...

  10. python装饰器三种装饰模式的简单理解

    学设计模式中有个装饰模式,用java实现起来不是很难,但是远远没有python简单,难怪越来越火了! 这里就简单讨论下python的几种装饰模式: 一 无参装饰器: # 装饰器 import time ...