设为首页 加入收藏

TOP

使用 .NET Core 3.0 的 AssemblyLoadContext 实现插件热加载(二)
2019-10-09 19:59:07 】 浏览:180
Tags:使用 .NET Core 3.0 AssemblyLoadContext 实现 插件 加载
Options = new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Debug); var references = _defaultAssemblies .Select(assembly => assembly.Location) .Where(path => !string.IsNullOrEmpty(path) && File.Exists(path)) .Select(path => MetadataReference.CreateFromFile(path)) .ToList(); var syntaxTrees = sourceFiles .Select(p => CSharpSyntaxTree.ParseText(File.ReadAllText(p))) .ToList(); var compilation = CSharpCompilation.Create(_pluginName) .WithOptions(compilationOptions) .AddReferences(references) .AddSyntaxTrees(syntaxTrees); var emitResult = compilation.Emit(dllPath); if (!emitResult.Success) { throw new InvalidOperationException(string.Join("\r\n", emitResult.Diagnostics.Where(d => d.WarningLevel == 0))); } //return _context.LoadFromAssemblyPath(Path.GetFullPath(dllPath)); using (var stream = File.OpenRead(dllPath)) { var assembly = _context.LoadFromStream(stream); return assembly; } } private IPlugin GetInstance() { var instance = _instance; if (instance != null && !_changed) return instance; lock (_reloadLock) { instance = _instance; if (instance != null && !_changed) return instance; UnloadPlugin(); _context = new AssemblyLoadContext( name: $"Plugin-{_pluginName}", isCollectible: true); var assembly = CompilePlugin(); var pluginType = assembly.GetTypes() .First(t => typeof(IPlugin).IsAssignableFrom(t)); instance = (IPlugin)Activator.CreateInstance(pluginType); _instance = instance; _changed = false; } return instance; } public string GetMessage() { return GetInstance().GetMessage(); } public void Dispose() { UnloadPlugin(); _watcher?.Dispose(); _watcher = null; } } internal class Program { static void Main(string[] args) { using (var controller = new PluginController("MyPlugin", "../guest")) { bool keepRunning = true; Console.CancelKeyPress += (sender, e) => { e.Cancel = true; keepRunning = false; }; while (keepRunning) { try { Console.WriteLine(controller.GetMessage()); } catch (Exception ex) { Console.WriteLine($"{ex.GetType()}: {ex.Message}"); } Thread.Sleep(1000); } } } } }

host.csproj 的内容:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.3.1" />
  </ItemGroup>

</Project>

Plugin.cs 的内容:

using System;
using Common;

namespace Guest
{
    public class MyPlugin : IPlugin
    {
        public MyPlugin()
        {
            Console.WriteLine("MyPlugin loaded");
        }

        public string GetMessage()
        {
            return "Hello 1";
        }

        public void Dispose()
        {
            Console.WriteLine("MyPlugin unloaded");
        }
    }
}

运行示例程序

进入 pluginexample/host 下运行 dotnet run 即可启动宿主程序,这时宿主程序会自动编译与加载插件,检测插件文件的变化并在变化时重新编译加载。你可以在运行后修改 pluginexample/guest/Plugin.cs 中的 Hello 1Hello 2,之后可以看到类似以下的输出:

MyPlugin loaded
Hello 1
Hello 1
Hello 1
MyPlugin unloaded
MyPlugin loaded
Hello 2
Hello 2

我们可以看到程序自动更新并执行修改以后的代码,如果你有兴趣还可以测试插件代码语法错误时会出现什么。

源代

首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇.NET开发者必须学习.NET Core 下一篇.netcore+vue+elementUI 前后端分..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目