在 中动态程序集加载后,异常"未注册类型'TestPlugins.Plugin1.Service1'的服务"。NET7



我有一个基于插件的解决方案,在。net 7上使用c#,使用动态程序集加载.

实际上,IoC容器说服务还没有注册,但实际上它已经注册了!

异常'No service for type 'TestPlugins.Plugin1。Service1"注册。

解决方案架构如下:

  • TestPlugins。PluginInterface
    1. IPlugin.cs
  • TestPlugins。Plugin1
    1. Plugin1.cs
    2. Service1.cs
  • TestPlugins。Plugin2
    1. Plugin2.cs
    2. Service2.cs
  • TestPlugins。应用程序
    1. Program.cs
    2. Plugins/TestPlugins.Plugin1.deps.json
    3. Plugins/TestPlugins.Plugin1.dll
    4. Plugins/TestPlugins.Plugin2.deps.json
    5. Plugins/TestPlugins.Plugin2.dll

接口:

using Microsoft.Extensions.DependencyInjection;
namespace TestPlugins.PluginInterface
{
public interface IPlugin
{
void Init(IServiceCollection services);
void Run(IServiceProvider serviceProvider);
}
}

插件:

using Microsoft.Extensions.DependencyInjection;
using TestPlugins.PluginInterface;
namespace TestPlugins.Plugin1
{
public class Plugin1 : IPlugin
{
public void Init(IServiceCollection services)
{
Console.WriteLine("Plugin1 Initing.");
services.AddTransient<IService1, Service1>();
Console.WriteLine("Plugin1 Inited.");
}
public void Run(IServiceProvider serviceProvider)
{
var service1 = serviceProvider.GetRequiredService<Service1>();
}
}
}

服务:

namespace TestPlugins.Plugin1
{
public interface IService1
{ }
public class Service1 : IService1
{
public Service1()
{
Console.WriteLine("Service1 Ctor.");
}
}
}

程序:

using Microsoft.Extensions.Hosting;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using TestPlugins.PluginInterface;
namespace TestPlugins.App
{
internal class Program
{
private static async Task Main(string[] args)
{
Console.WriteLine("TestPlugins.App Starting.");
using (IHost host = CreateHostBuilder(args).Build())
{
foreach (var plugin in _plugins)
{
plugin.Run(host.Services);
}
await host.RunAsync().ConfigureAwait(false);
}
Console.WriteLine("TestPlugins.App Ending.");
}
private static readonly HashSet<IPlugin> _plugins = new();
private static IHostBuilder CreateHostBuilder(string[] args)
{
var assemblies = GetPlugins();
return Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
foreach (var assembly in assemblies)
{
var obj = Activator.CreateInstance(assembly.Value) as IPlugin;
if (obj != null)
{
obj.Init(services);
_plugins.Add(obj);
}
}
});
}
private static Dictionary<Assembly, Type> GetPlugins()
{
var ipluginType = typeof(IPlugin);
var pluginDir = Path.Combine(Environment.CurrentDirectory, "Plugins");
var pluginsDlls = Directory.GetFiles(pluginDir, "*.dll", SearchOption.AllDirectories).ToList();
return pluginsDlls.Select(dll =>
{
return ReflectionsExcCatch(() =>
{
var alc = new AssemblyLoadContext(dll);
var asm = alc.LoadFromAssemblyPath(dll);
var types = asm.GetTypes();
var ipluginTypes = types.Where(t => ipluginType.IsAssignableFrom(t) && t != ipluginType);
return new KeyValuePair<Assembly, Type?>(
asm,
ipluginTypes.FirstOrDefault());
});
})
.Where(x => x.Value != null)
.ToDictionary(x => x.Key, y => y.Value)!;
}
private static KeyValuePair<Assembly, Type?> ReflectionsExcCatch(Func<KeyValuePair<Assembly, Type?>> action)
{
try
{
return action();
}
catch (ReflectionTypeLoadException ex)
{
var sb = new StringBuilder();
foreach (Exception exSub in ex.LoaderExceptions)
{
sb.AppendLine(exSub.Message);
FileNotFoundException exFileNotFound = exSub as FileNotFoundException;
if (exFileNotFound != null)
{
if (!string.IsNullOrEmpty(exFileNotFound.FusionLog))
{
sb.AppendLine("Fusion Log:");
sb.AppendLine(exFileNotFound.FusionLog);
}
}
sb.AppendLine();
}
string errorMessage = sb.ToString();
Debug.WriteLine(errorMessage);
throw;
}
}
}
}

此处出现异常:

using (IHost host = CreateHostBuilder(args).Build())
{
foreach (var plugin in _plugins)
{
plugin.Run(host.Services); // Exception  'No service for type 'TestPlugins.Plugin1.Service1' has been registered.'
}
await host.RunAsync().ConfigureAwait(false);
}

这是解决方案的回购,你可以检查它。
有什么解决问题的办法吗?

问好

这与动态加载程序集的事实没有什么关系。这个问题仅仅是由Plugin1的编程错误引起的。

您正在注册:

services.AddTransient<IService1, Service1>();

但是你正在解析:

serviceProvider.GetRequiredService<Service1>();

换句话说,您正在注册IService1抽象,但正在解析Service1实现。您应该将解析更改为:

serviceProvider.GetRequiredService<IService1>();

最新更新