【发布时间】:2021-05-08 11:02:18
【问题描述】:
我在使用依赖注入时遇到了一个奇怪的问题,为来自外部程序集的类型添加了单例。这是使用 Azure Function 框架,但我不确定这是否与它有关,或者这是否也会与 ASP.NET Core 一起重现。我实际的“现实世界”实现非常复杂,无法在此处概述,但我设法提出了一个最小的重现。
BugRepro.dll(这是一个 Azure Function 项目)
这有两个文件。
Test.cs:
public class Test
{
private readonly AppConfig config;
public Test(AppConfig config)
{
this.config = config;
}
[FunctionName("Test")]
public async Task<IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req)
{
return new OkObjectResult(config.SampleSetting);
}
}
Startup.cs:
namespace BugRepro
{
public class AppConfig
{
public string SampleSetting { get; set; } = "Test";
}
public static class Startup
{
public static void Configure(IServiceCollection services)
{
services.AddSingleton(new AppConfig());
}
}
}
此程序集引用了TestDll.dll。
TestDll.dll(这是一个普通的 .NET Core 库)
Startup.cs:
[assembly: FunctionsStartup(typeof(TestDll.Startup))]
namespace TestDll
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var asm = Assembly.LoadFile(Path.Combine(builder.GetContext().ApplicationRootPath, @"bin\BugRepro.dll"));
var type = asm.GetType("BugRepro.Startup");
var method = type.GetMethod("Configure");
method.Invoke(null, new object[] {builder.Services});
}
}
}
当 Azure Function 运行时,框架会自动调用 TestDll.Startup.Configure 方法。此方法使用反射加载另一个程序集BugRepro.dll,并调用BugRepro.Startup.Configure 静态方法,传递IServiceCollection。
BugRepro.Startup.Configure 静态方法将AppConfig 的单个实例添加到服务集合中。我可以验证该实例是否已成功添加到服务集合中,并一路进入代码,正确的 ServiceDescriptor 和所有内容都已创建。一切看起来都很完美。
但是,当我调用 /Test 端点时,我得到了错误:
[2021-02-04T06:39:10.502Z] Executed 'Test' (Failed, Id=22cfb587-3ba9-401f-b0a5-8688aed7bc9d, Duration=386ms)
[2021-02-04T06:39:10.506Z] Microsoft.Extensions.DependencyInjection.Abstractions: Unable to resolve service for type 'BugRepro.AppConfig' while attempting to activate 'BugRepro.Test'.
基本上,它就像从未注册过的单例一样,它无法解析该类型。
修复方法:
因此,如果我将 AppConfig 类从 BugRepro.dll 移动到 TestDll.dll(基本上 AppConfig 类型与我的 FunctionsStartup 类在同一个 DLL 中),代码将按预期工作。
修复它的另一种方法是使用接口,它在 TestDll 中定义:
public interface IConfig
{
}
然后让AppConfig实现那个接口,然后使用它的接口注册Singleton:
services.AddSingleton<IConfig>(new AppConfig());
但是,我必须将IConfig 注入Test 构造函数,而不是我不想这样做的AppConfig。
我的问题
有没有办法为存在于外部程序集中的类型注册单例?对我来说,这似乎是 .NET Core DI 框架中的一个错误。谢谢!
【问题讨论】:
标签: c# .net .net-core dependency-injection azure-functions