NetCore插件化开发

  • A+
所属分类:.NET技术
摘要

使用NetCore3.1完成框架基本开发后实际应用于项目,需要保证框架的独立性与项目的个性化, 就需要类似于下图的插件化形式将项目放入框架这个容器中启动,下面开始详细介绍实现步骤

使用NetCore3.1完成框架基本开发后实际应用于项目,需要保证框架的独立性与项目的个性化, 就需要类似于下图的插件化形式将项目放入框架这个容器中启动,下面开始详细介绍实现步骤

NetCore插件化开发NetCore插件化开发

项目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();  }