Justin
Justin

Reputation: 18236

Unable to resolve service for type IOptions[DataAccessConfiguration] in non-ASP.NET Core app

All of our business services were previously set up to use Dependency Injection with IOptions because they were being consumed by ASP.NET Core apps, like so:

NotificationDataAccess.cs:

public class NotificationDataAccess : BaseDataAccess, INotificationDac<Notification>
    {
        public NotificationDataAccess(IOptions<DataAccessConfiguration> options, IClaimsAccessor claimsAccessor) :
            base(options, claimsAccessor)
        {
        }
}

NotificationBusinessService.cs:

public class NotificationBusinessServices : INotificationServices<Notification>
    {
        private readonly INotificationDac<Notification> _notificationDataAccess;

        public NotificationBusinessServices(
            INotificationDac<Notification> notifcationDataAccess)
        {
            _notificationDataAccess = notifcationDataAccess;
        }
}

Now I'm left with the unenviable task of trying to figure out how to leverage the same pattern from a windows service, which doesn't benefit from the built-in ASP.NET Core features for handling DI. When the service starts up, I execute the following code:

// Set up configuration, services, and logging.
            IServiceCollection services = new ServiceCollection();
            var startup = new Startup();
            startup.ConfigureServices(services);
            IServiceProvider serviceProvider = services.BuildServiceProvider();

            var configuration = serviceProvider.GetService<IConfigurationRoot>();
            var notificationService = serviceProvider.GetService<INotificationServices<Notification>>();// TODO: This errors!
            processor = new Processor(configuration, notificationService);

And here is the Startup.cs code, which is supposed to configure the services:

public class Startup
    {
        IConfigurationRoot Configuration { get; }

        public Startup()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Path.Combine(AppContext.BaseDirectory))
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IConfigurationRoot>(Configuration);
            //services.AddMvc();

            // Add application services.
            Listings.Business.Configuration.Instance = new BusinessLayerConfiguration();
            services.Configure<DataAccessConfiguration>(options => Configuration.GetSection("Data").Bind(options));
            services.AddScoped(typeof(INotificationDac<Notification>), typeof(NotificationDataAccess));
            services.AddScoped(typeof(INotificationServices<Notification>), typeof(NotificationBusinessServices));
        }
    }

Unfortunately, when I run the windows service it throws an exception when trying to get the notificationService:

var notificationService = serviceProvider.GetService<INotificationServices<Notification>>();

The exception is:

System.InvalidOperationException: 'Unable to resolve service for type 'Microsoft.Extensions.Options.IOptions`1[Rpr.Listings.DataAccess.DataAccessConfiguration]' while attempting to activate 'Rpr.Listings.DataAccess.NotificationDataAccess'.'

I was hoping my "services.Configure" code would resolve this, but alas no. Clearly I need to register IOptions in my Startup.cs, however I have no idea how to do so. Is this something that usually happens out of the box with ASP.NET MVC? Does "services.AddMvc();" normally register this binding correctly? I can call that, but would need to import a ton of ASP.NET MVC packages into my windows service, which I'm reluctant to do.

Please let me know how to register the IOptions binding correctly, thanks!

Upvotes: 19

Views: 14997

Answers (2)

greentrees
greentrees

Reputation: 63

In case it helps anyone, I had this issue in a console app and it was caused by creating the service provider

IServiceProvider serviceProvider = services.BuildServiceProvider();

before I'd registered my config

services.Configure<DataAccessConfiguration>(Configuration.GetSection("Data"));

Upvotes: 3

Justin
Justin

Reputation: 18236

It turns out that all I was missing was:

services.AddOptions();

Once I added that, the IOptions binding was registered correctly!

Upvotes: 54

Related Questions