概述


本文已经同步到《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. GO_08:GO语言基础之interface

    接口interface 1. 接口是一个或多个方法签名的集合 2. 只要某个类型拥有该接口的所有方法签名,即算实现该接口,无需显示声明实现了哪个接口,这称为 Structural typing 3. ...

  2. servlet拦截器

    servlet拦截未登录的用户请求 java代码: package com.gavin.filter; import java.io.IOException; import javax.servlet ...

  3. 转:iOS-CoreLocation:无论你在哪里,我都要找到你!

    1.定位 使用步骤: 创建CLLocationManager示例,并且需要强引用它 设置CLLocationManager的代理,监听并获取所更新的位置 启动位置更新 1 2 3 _manager = ...

  4. codevs 3327 选择数字

    3327 选择数字  时间限制: 1 s  空间限制: 256000 KB 题目描述 Description 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续 ...

  5. 图论:LCA-欧拉序

    #include<cmath> #include<vector> #include<cstdio> #include<cstring> #include ...

  6. 2015/12/12 考了PAT,又回来玩Python了。

    上次写飞机大战的坑还没填完,然后就有好长时间没有更新博客了.可能大家在疑惑我在干什么... 其实不是有意暂停博客更新的,十一月学校里有两个考试要准备,然后有好多实验要做.平时的课余时间本来就不是很多了 ...

  7. How To Configure VMware fencing using fence_vmware_soap in RHEL High Availability Add On——RHEL Pacemaker中配置STONITH

    本文主要简单介绍一下如何在RHEL 7 Pacemaker中配置一个fence_vmware_soap类型的STONITH设备(仅供测试学习). STONITH是Shoot-The-Other-Nod ...

  8. debian下配置双核cpu

    ----------------------------文:jiqing(吉庆) http://hi.baidu.com/jiqing0925email: jiqingwu@gmail.comdate ...

  9. Druid.io启用SQL支持

    Druid.io的SQL功能虽然在试验阶段,但是也支持了大部分的功能,而且还可以通过 Avatica JDBC查看请求的json,有助于我们理解Druid.io的语法.Druid.io有个比较坑的是, ...

  10. JavaScript辅助响应式

    js响应式 rem辅助响应式布局:其实就是指在HTML页面的大小不断变化的时候,里面的宽.高.字体等等也随之变化,主要是通过获取window.innerwidth的值来进行判断,7.5rem===10 ...