简体   繁体   中英

DI not injecting service to Controller

I have a strange situation. I register my services in the startup class, like so

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

but when I try to access them in the constructor of the controller, they are null, even if I add it to the constructor parameters, or try to get from the 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));
    }
}

My Location class which implements the ILocationService interface

public class LocationService : ILocationService
{
    readonly ISolrOperations<LocationResult> search;

    ...

    public LocationService(ISolrOperations<LocationResult> search)
    {
        this.search = search;
    }

    ...
}

What am I missing?

You're not injecting your service. Instead, you're attempting to use the service-locator antipattern to get it, but you're not actually using your real service collection. You're creating a new service collection, without a registration for the service you want, and attempting to pull your service out of that, which of course fails.

Although this is not the correct method anyways, to actually use the service locator antipattern correctly, you'd need to inject IServiceProvider :

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

Then, that would only work because in this case, your particular service is a singleton. If it were scoped, you'd have to create a scope first:

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

However, anything retrieved within a scope is only available within that scope. So you have to wrap every operation in a using like this for scoped services (ie you cannot persist the service to an ivar).

All that said, here, you're injecting into a controller, and as such, you can inject your dependencies directly without having to rely on a the service-locator antipattern (it's an antipattern for a reason). So all you really need to do is just inject ILocationService :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM