代码之家  ›  专栏  ›  技术社区  ›  Coder

DI未向控制器注入服务

  •  -1
  • Coder  · 技术社区  · 7 年前

    我有一个奇怪的情况。我在startup类中注册我的服务,如下所示

    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddSingleton<ISearchService, SearchService>();
        services.AddSingleton<IBrandSearchService, BrandSearchService>();
        services.AddSingleton<INearbySearchService, NearbySearchService>();
        services.AddSingleton<ILocationService, LocationService>();
        ...
    }
    

    但是,当我尝试在控制器的构造函数中访问它们时,即使我将其添加到构造函数参数中,或者尝试从ServiceCollection获取,它们也是空的

    public class SuggestController
    {
        readonly ILocationService locationService;
    
        public SuggestController(IOptions<SiteSettings> settings, IOptions<DBAccessBuilder> access, IStringLocalizer<SharedResources> localizer, IMemoryCache memoryCache, IHostingEnvironment environment)
        {
            this.locationService = (ILocationService)new ServiceCollection().BuildServiceProvider().GetService(typeof(ILocationService));
        }
    }
    

    实现ILocationService接口的My Location类

    public class LocationService : ILocationService
    {
        readonly ISolrOperations<LocationResult> search;
    
        ...
    
        public LocationService(ISolrOperations<LocationResult> search)
        {
            this.search = search;
        }
    
        ...
    }
    

    我错过了什么?

    1 回复  |  直到 7 年前
        1
  •  0
  •   Chris Pratt    7 年前

    你没有注入你的服务。相反,您试图使用服务定位器反模式来获取它,但实际上并没有使用真正的服务集合。您正在创建一个新的服务集合,但没有注册所需的服务,并试图将您的服务从中拉出,这当然会失败。

    尽管这无论如何都不是正确的方法,但要真正正确使用服务定位器反模式,您需要注入 IServiceProvider :

    public SuggestController(IServiceProvider provider, ...)
    {
        this.locationService = provider.GetRequiredService<ILocationService>();
    }
    

    那么,这只会起作用,因为在这种情况下,您的特定服务是单例的。如果已确定范围,则必须首先创建范围:

    using (var scope = provider.CreateScope())
    {
        var locationService = scope.ServiceProvider.GetRequiredService<ILocationService>();
    }
    

    但是,在某个范围内检索到的任何内容都只能在该范围内使用。因此,对于作用域服务,您必须像这样将每个操作包装在using中(即,您不能将服务持久化到ivar)。

    综上所述,在这里,您正在注入控制器,因此,您可以直接注入依赖项,而不必依赖于服务定位器反模式(这是一种有原因的反模式)。所以所有的你 真正地 需要做的就是注射 ILocationService :

    public SuggestController(ILocationService locationService, ...)
    {
        this.locationService = locationService;
    }