aspnetcore插件开发dll热加载
该项目比较简单,只是单纯的把业务的dll模块和controller的dll做了一个动态的添加删除处理,目的就是插件开发。由于该项目过于简单,请勿吐槽。复杂的后续可以通过泛型的实体、dto等做业务和接口的动态区分。
项目结构如下:

上面的两个模块是独立通过dll加载道项目中的

repository动态的核心思想在此项目中是反射
public interface IRepositoryProvider
{
IRepository GetRepository(string serviceeName);
}
public class RepositoryProvider : IRepositoryProvider
{
public IRepository GetRepository(string x)
{
var path = $"{Directory.GetCurrentDirectory()}\\lib\\{x}.Repository.dll";
var _AssemblyLoadContext = new AssemblyLoadContext(Guid.NewGuid().ToString("N"), true);
Assembly assembly = null;
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
assembly = _AssemblyLoadContext.LoadFromStream(fs);
} //var assembly = Assembly.LoadFrom(path);
var types = assembly.GetTypes()
.Where(t => typeof(IRepository).IsAssignableFrom(t) && !t.IsInterface);
return (IRepository)Activator.CreateInstance(types.First());
}
}
通过一个provider注入来获取示例,这个repository的示例既然是动态热拔插,能想到暂时只能是反射来做这一块了。
using Autofac;
using IOrder.Repository;
using Order.Repository; namespace AutofacRegister
{
public class RepositoryModule:Module
{
protected override void Load(ContainerBuilder builder)
{
//builder.RegisterType<Repository>().As<IRepository>().SingleInstance();
builder.RegisterType<RepositoryProvider>().As<IRepositoryProvider>().InstancePerLifetimeScope();
}
}
}
controller插件这一块大同小异,这个控制器是通过程序集注入来实现的
public class MyControllerFilter : IStartupFilter
{ private readonly PluginManager pluginManager;
List<string> controllers = new List<string> { "First","Second" };
public MyControllerFilter(PluginManager pluginManager)
{
this.pluginManager = pluginManager;
controllers.ForEach(x => pluginManager.LoadPlugins($"{Directory.GetCurrentDirectory()}\\lib\\", $"{x}.Impl.dll"));
}
Action<IApplicationBuilder> IStartupFilter.Configure(Action<IApplicationBuilder> next)
{
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly;
return app =>
{ app.UseRouting();
app.UseEndpoints(endpoints =>
{
foreach (IPlugin item in pluginManager.GetPlugins())
{
foreach (MethodInfo mi in item.GetType().GetMethods(bindingFlags))
{
endpoints.MapPost($"/{item.GetType().Name.Replace("Service", "")}/{mi.Name}", async (string parameters, HttpContext cotext) =>
{ var task = (Task)mi.Invoke(item, new object[] { parameters });
if (task is Task apiTask)
{
await apiTask; // 如果任务有返回结果
if (apiTask is Task<object> resultTask)
{
var res = await resultTask;
return Results.Ok(JsonConvert.SerializeObject(res));
}
} // 如果方法没有返回 Task<ApiResult>,返回 NotFound
return Results.NotFound("Method execution did not return a result.");
});
}
}
});
next(app);
};
}
}
但是有一个问题,它的变化势必需要重新渲染整个controller,我只能重启他的服务了。
using Microsoft.Extensions.Hosting;
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks; namespace StartupDiagnostics
{
public class FileWatcherService : IHostedService
{
private readonly string _watchedFolder;
private FileSystemWatcher _fileSystemWatcher;
private readonly IHostApplicationLifetime _appLifetime;
public FileWatcherService(IHostApplicationLifetime appLifetime)
{
_watchedFolder =Path.Combine(Directory.GetCurrentDirectory(),"lib"); //细化指定类型的dll
_appLifetime = appLifetime;
} public Task StartAsync(CancellationToken cancellationToken)
{
_fileSystemWatcher = new FileSystemWatcher(_watchedFolder);
_fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
_fileSystemWatcher.Changed += OnFileChanged;
_fileSystemWatcher.Created += OnFileChanged;
_fileSystemWatcher.Deleted += OnFileChanged;
_fileSystemWatcher.Renamed += OnFileChanged;
_fileSystemWatcher.EnableRaisingEvents = true; return Task.CompletedTask;
} public Task StopAsync(CancellationToken cancellationToken)
{
_fileSystemWatcher.Dispose();
return Task.CompletedTask;
} private void OnFileChanged(object sender, FileSystemEventArgs e)
{
// 文件夹内容发生变化时重新启动应用程序
var processStartInfo = new ProcessStartInfo
{
FileName = "dotnet",
Arguments = $"exec \"{System.Reflection.Assembly.GetEntryAssembly().Location}\"",
UseShellExecute = false
}; _appLifetime.ApplicationStopped.Register(() =>
{
Process.Start(processStartInfo);
});
_appLifetime.StopApplication(); }
}
}
repository这一块页面效果没法展示,
controllerr可以通过swagger来看看,first和second这可以通过删除dll和添加dll来增加和删除controller给第三方。


这是控制台展示的重启效果

源代码如下:
liuzhixin405/AspNetCoreSimpleAop (github.com)
aspnetcore插件开发dll热加载的更多相关文章
- Aspnetcore下面服务器热更新与配置热加载
原文:Aspnetcore下面服务器热更新与配置热加载 Asp.net的热更新方案Appdomain在aspnetcore中不被支持了 新的方案如下: 配置文件更新选项 reloadOnChange ...
- Windows7 安装vs2015 之后 调试Web项目IIS启动不了 aspnetcore.dll未能加载
安装windows企业版,整整折腾了两天了,一个本身家里网络环境不好,时不时掉线,终于披荆斩棘,克服了所有困难,结果VS2015 EnterPrise 版本在调试Web环境的时候,始终在任务栏里找不到 ...
- 模块 DLL C:\WINDOWS\system32\inetsrv\aspnetcore.dll 未能加载。返回的数据为错误信息。
更新了win10的版本后,就启动原来的iis发布的程序 程序池就自动关闭.后来 启动网站 iis程序池自动关闭. 在为应用程序池“.NET v4.5”提供服务的工作进程“21908”中,协议“http ...
- 使用 .NET Core 3.0 的 AssemblyLoadContext 实现插件热加载
一般情况下,一个 .NET 程序集加载到程序中以后,它的类型信息以及原生代码等数据会一直保留在内存中,.NET 运行时无法回收它们,如果我们要实现插件热加载 (例如 Razor 或 Aspx 模版的热 ...
- IE报错:模块"scrrun.dll"已加载,但对DllRegisterServer的调用失败,错误代码为0x80004005
在我的win10系统上打开某内部网页登录的时候弹出'模块"scrrun.dll"已加载,但对DllRegisterServer的调用失败,错误代码为0x80004005'报错信息, ...
- webpack 教程 那些事儿03-webpack两大精华插件,热加载
本节主要讲述 webpack的两大经典开发调试插件,热插拔内存缓存机制 文章目录 1. html-webpack-plugin插件的使用 2. webpack-dev-middleware 插件登场 ...
- [Eclipse] - 集成JBoss7热加载和自动发布
使用Eclipse + JBoss开发时,总是要重启项目或JBoss,烦人.下面方法可以很简单的实现Eclipse + JBoss热加载和自动发布. 我的环境是JBoss 7.1.1 Final 1) ...
- [Eclipse] - 集成Tomcat热加载插件
使用Eclipse + Tomcat,要使用热加载,总是会重启tomcat webapp. 可以使用这个插件:jrebel 如果是Tomcat 7.0+版本,需要使用jrebel5.5.1+的版本,不 ...
- Eclipse tomcat插件禁用热加载
Eclipse中的tomcat插件默认是开户了热加载,只要是修改了java文件一保存,tomcat自动编译.加载.发布,很吃内存. 关闭方法: 打开eclipse,找到server项: 双击打开,修改 ...
- mybatis热加载的实现
最近在使用mybatis,由于是刚刚开始用,用的并不顺手,目前是感觉有2个地方非常的不好用: 1.mybatis调试不方便 由于dao层只有接口,实现只是一个map的xml文件,想加断点都没有地方加, ...
随机推荐
- drools中使用全局变量
一.背景 在我们编写drools的规则文件的时候,有些时候需要用到全局变量,那么这个该怎么实现呢?有哪些注意事项呢? 二.前置知识 1.语法结构 2.全局变量的特点 使用global来定义全局变量,它 ...
- [MAUI]模仿哔哩哔哩的一键三连
@ 目录 创建弧形进度条 绘制弧 准备物料 创建气泡 创建手势 创建交互与动效 项目地址 哔哩哔哩(Bilibili)中用户可以通过长按点赞键同时完成点赞.投币.收藏对UP主表示支持,后UP主多用&q ...
- LOTO任意波形发生器SIG82模拟输出继电器吸合断开的信号波形用于算法调试
LOTO任意波形发生器SIG82模拟输出继电器吸合断开的信号波形用于算法调试 继电器吸合的电流变化过程是如图这样的波形,0到2的时间大约为17毫秒,2到3的时间大约38毫秒. 批量继电器产品吸合是否满 ...
- KingbaseES集群运维案例之---主备库failover后auto-recovery机制
KingbaseES集群运维案例之---主备库failover后auto-recovery机制 案例说明: KingbaseES集群,在备库数据库服务down后,可以实现节点数据库服务的自动恢复:在集 ...
- 我们正在被 DDoS 攻击,但是我们啥也不干,随便攻击...
最近,一场激烈的攻防大战在网络世界悄然上演. 主角不是什么国家安全局或者黑客组织,而是一家名不见经传的创业公司--TablePlus. DDoS 攻击者们摩拳擦掌,跃跃欲试.他们从四面八方蜂拥而至,誓 ...
- 批量拉取/git pull 指定文件夹下面所有 Git 项目的最新代码
背景 因为工作需要,当前所负责的项目较多:但是人力紧缺,其中绝大部分项目平时也不会去跟进迭代.所以经常需要批量拉取最新的代码查看最新的改动. 解决方案 一键批量拉取指定文件夹下所有 Git 项目的最新 ...
- 设置 BCompare 打开文件时的默认字符编码
每次比对 .h .cpp 文件,BCompare总是默认以西欧字符编码打开文件,导致中文都变成乱码了,还需要手动的修改文件字符编码,这样才能正常的显示.非常的不方便 然后我们就需要设置默认的字符编码, ...
- vue-cli4,vue3打包后页面无内容
这个问题百度了一下,各种各样的的回答都有,试了好多种方法,终于解决这个问题 解决方法: 1.在项目根目录下,新建 vue.config.js, 在文件中输入: module.exports = { ...
- 《深入理解Java虚拟机》读书笔记:运行时栈帧结构
代码编译的结果从本地机器码转变为字节码,是存储格式发展的一小步,却是编程语言发展的一大步. 一.概述 在Java虚拟机规范中制定了虚拟机字节码执行引擎的概念模型,这个概念模型成为各种虚拟机执行引擎的统 ...
- Batch Normalization 和 DropOut
Batch-Normalization https://www.cnblogs.com/guoyaohua/p/8724433.html 有几点需要注意: \(x^{(k)}\)指的是t层的输入. 也 ...