Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 591
Justin Avatar asked Jan 03 '18 00:01

Justin


2 Answers

It turns out that all I was missing was:

services.AddOptions();

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

like image 157
Justin Avatar answered Nov 16 '22 19:11

Justin


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"));
like image 1
greentrees Avatar answered Nov 16 '22 18:11

greentrees