首页 > 解决方案 > 在配置方法中使用服务时超出范围?

问题描述

下面是我教科书中的伪代码,我对在配置方法中使用服务感到困惑

public class ConcreteA
{
   public static Run(IServiceProvider serviceProvider)
   {
      ConcreteB _concrete = serviceProvider.GetRequiredService<ConcreteB>();
      ... //use ConcreteB  instance
   }

}
__________________________________________________________

// startup.cs
public void ConfigureServices(IServiceCollection services) 
{
   services.AddScoped<ConcreteA>;
   services.AddScoped<ConcreteB>;  
}

public void Configure(IApplicationBuilder app) {
   app.UseStatusCodePages();
   app.UseDeveloperExceptionPage();
   app.UseMvcWithDefaultRoute();
   ConcreteA.Run(app.ApplicationServices);
}

有人告诉我,因为我使用ConcreteAinConfigure方法,所以我在范围之外运行它。我创建的任何依赖项(在这种情况下为 ConcreteB 实例)都会徘徊。

我很困惑,以下是我的问题:

Q1-我都注册了ConcreteA,所以不应该有任何捕获的依赖关系问题,因为它们在同一范围内,所以为什么仍然会徘徊。ConcreteBAddScopedConcreteB

Q2-我什至没有创建 ConcreteA 实例,因为我访问的方法是静态方法,因此不需要创建 ConcreteA 实例。所以更不可能ConcreteB闲逛。

标签: c#dependency-injection.net-coreasp.net-core-mvc

解决方案


这似乎是一个XY 问题

我相信您正在尝试实现以下目标,但首先您需要重构ConcreteA以显式依赖于ConcreteB通过构造函数注入(尽管对混凝土的依赖作为代码气味超出了当前形式的此问题的范围(请原谅双关语))

public class ConcreteA {
    private ConcreteB B;

    public ConcreteA(ConcreteB B) {
        this.B = B;
    }

    public void Run() {
        ... //use ConcreteB  instance
    }    
}

然后在启动时将它们注册为作用域,就像之前在 ConfigureServices 中一样。但是,Configure您将在范围内访问它们。

例如

启动.cs

public void ConfigureServices(IServiceCollection services) {
    services.AddScoped<ConcreteA>();
    services.AddScoped<ConcreteB>();  

    //...
}

public void Configure(IApplicationBuilder app) {
    app.UseStatusCodePages();
    app.UseDeveloperExceptionPage();
    app.UseMvcWithDefaultRoute();

    // Create a new IServiceScope that can be used to resolve scoped services.
    using(var scope = app.ApplicationServices.CreateScope()) {
        // resolve the services within this scope
        ConcreteA A = scope.ServiceProvider.GetRequiredService<ConcreteA>();

        //ConcreteA instance and injected ConcreteB are used in the same scope

        //do something
        A.Run();           
    }

    //both will be properly disposed of here when they both got out of scope.
}

上面使用的ConcreteAand 扩展ConcreteB名将在相同的范围内。


推荐阅读