其他
.NET Core 插件化开发
(给DotNet加星标,提升.Net技能)
转自:code2roc cnblogs.com/yanpeng19940119/p/14493690.html
前言
使用.NET Core 3.1 完成框架基本开发后实际应用于项目,需要保证框架的独立性与项目的个性化, 就需要类似于下图的插件化形式将项目放入框架这个容器中启动,下面开始详细介绍实现步骤
项目dll扫描
在框架根目录创建Plugin文件夹,项目在生成后事件使用copy命令拷贝至Plugin文件夹,框架启动时会扫描该文件夹并进行ShadowCopy到PluginTemplate文件夹中
private static void ScanPlugin()
{
if (!PluginFolder.Exists)
{
PluginFolder.Create();
}
if (!TempPluginFolder.Exists)
{
TempPluginFolder.Create();
}
TempPluginFolder.Attributes = FileAttributes.Normal & FileAttributes.Directory;
PluginFolder.Attributes = FileAttributes.Normal & FileAttributes.Directory;
//清理临时文件。
foreach (var file in TempPluginFolder.GetFiles("*.dll", SearchOption.AllDirectories))
{
try
{
File.SetAttributes(file.FullName, FileAttributes.Normal);
file.Delete();
}
catch (Exception e)
{
throw new Exception("请检查IIS权限");
}
}
//复制插件进临时文件夹。
foreach (var plugin in PluginFolder.GetFiles("*.dll", SearchOption.AllDirectories))
{
try
{
string CopyFilePath = Path.Combine(TempPluginFolder.FullName, plugin.Name);
File.Copy(plugin.FullName, CopyFilePath, true);
File.SetAttributes(CopyFilePath, FileAttributes.Normal);
}
catch (Exception e)
{
throw new Exception("请检查IIS权限");
}
}
}
项目dll加载
直接使用ApplicationParts加载AssemblyPart即可
public static void LoadPlugin()
{
ScanPlugin();
IEnumerable<Assembly> AssemblyList = GetPluginAssemblies();
foreach (Assembly assembly in AssemblyList)
{
foreach (var type in assembly.GetTypes())
{
if (type.IsAssignableFrom(typeof(Controller)) && type.Name.Contains("Controller") && type.IsClass && !type.IsAbstract)
{
string Name = type.Name;
//如果有自定义的路由注解
if (type.IsDefined(typeof(Route), false))
{
var areaattribute = type.GetCustomAttributes(typeof(Route), false).FirstOrDefault();
Name = ((Route)areaattribute).Name;
Name += "Controller";
}
if (!ControllerTypeDic.ContainsKey(Name))
{
ControllerTypeDic.Add(Name, type);
}
}
}
var controllerAssemblyPart = new AssemblyPart(assembly);
CloudUtil.GetBuilder().ConfigureApplicationPartManager(apm =>
{
apm.ApplicationParts.Add(controllerAssemblyPart);
});
}
CloudUtil.GetBuilder().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
StartPluginRefreshWatch();
}
项目视图
项目的cshtml视图文件可以手动拷贝到部署的框架Views文件夹中(正式环境),也可以通过监控当前项目的Views文件夹,如果变动进行自动拷贝(开发环境)
private static void StartPluginRefreshWatch()
{
_FileSystemWatcher.Path = CloudUtil.GetContentPath() + "/Plugin";
_FileSystemWatcher.Filter = "*.dll";
_FileSystemWatcher.Changed += _FileSystemWatcher_Changed;
_FileSystemWatcher.IncludeSubdirectories = true;
_FileSystemWatcher.NotifyFilter =
NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size;
_FileSystemWatcher.EnableRaisingEvents = true;
if (AppConfigUtil.Configuration["Frame:ViewsPublishType"]=="AutoCopy"
&& !string.IsNullOrEmpty(AppConfigUtil.Configuration["Frame:ViewsVirtualPath"])
&& Directory.Exists(AppConfigUtil.Configuration["Frame:ViewsVirtualPath"]))
{
FileSystemWatcher ViewsWatcher = new FileSystemWatcher();
ViewsWatcher.Path = AppConfigUtil.Configuration["Frame:ViewsVirtualPath"];
ViewsWatcher.Changed += ViewsWatcher_Changed;
ViewsWatcher.IncludeSubdirectories = true;
ViewsWatcher.NotifyFilter =
NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size;
ViewsWatcher.EnableRaisingEvents = true;
//系统启动时整个文件夹拷贝
DirectoryInfo FrameWorkViews = new DirectoryInfo(CloudUtil.GetContentPath() + "/Views");
DirectoryInfo ProjectViews = new DirectoryInfo(AppConfigUtil.Configuration["Frame:ViewsVirtualPath"]);
foreach (DirectoryInfo FDir in FrameWorkViews.GetDirectories())
{
foreach (DirectoryInfo PDir in ProjectViews.GetDirectories())
{
if (PDir.Name== FDir.Name)
{
FileUtil.DeleteDirectoryContent(FDir.FullName);
}
}
}
FileUtil.CopyDirectory(AppConfigUtil.Configuration["Frame:ViewsVirtualPath"],CloudUtil.GetContentPath() + "/Views", true);
}
}
项目dll热更新
监控Plugin文件夹,若有变调用IApplicationLifetime的StopApplication重启系统
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfiguration configuration, Microsoft.AspNetCore.Hosting.IApplicationLifetime applicationLifetime)
{
CloudUtil.SetAPP(applicationLifetime);
}
private static void _FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
CloudUtil.Restrat();
}
public static void Restrat()
{
APP.StopApplication();
}
- EOF -
看完本文有收获?请转发分享给更多人
推荐关注「DotNet」,提升.Net技能
点赞和在看就是最大的支持❤️