【问题标题】:IServiceCollection cannot resolve type when loaded from an outside assembly从外部程序集加载时,IServiceCollection 无法解析类型
【发布时间】: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


    【解决方案1】:

    这个问题是你使用Assembly.LoadFile引起的。 LoadFile 方法会导致同一个程序集被加载两次,这样框架就会将其视为完全不同的程序集,具有不同的类型。

    解决方案是改用Asssembly.Load

    var assembly = Assembly.Load(AssemblyName.GetAssemblyName("c:\..."));
    

    请参阅related topic(对于简单注射器,但问题相同)了解更多信息。

    【讨论】:

    • 不错!你完全正确,这解决了它!昨晚让我发疯了 2 个小时..
    • 是时候开始使用更好的 DI Conrainer 了;一个实际上会报告问题所在的人;-)
    • 我认为您可以将 Autofac 与 ASP.NET Core 一起使用,但不确定 Azure Functions 是否允许您换出 DI 的东西。同意,调试几乎是不可能的(我什至花了一些时间研究服务收集源代码无济于事)。我怀疑我自己是否能够缩小确切的问题范围,我正在考虑重新设计整个事情..
    • 确实,Azure Functions 非常有限,并且没有像 ASP.NET Core 那样公开相同类型的扩展点。不过,您可以使用任何您喜欢的 DI 容器,但您可能需要采用不同的方法,例如 Simple Injector 论坛上的 here 解释。
    猜你喜欢
    • 1970-01-01
    • 2016-01-02
    • 1970-01-01
    • 2022-01-06
    • 2012-05-05
    • 2010-09-19
    • 2017-11-26
    • 2020-11-26
    • 1970-01-01
    相关资源
    最近更新 更多