Dependency Injected DbContext is always null












1















I've used DI across multiple ASP.NET (Core) applications where DbContext is injected into a controller constructor, and upon the first request to the controller, the constructor is ran and the dependency injected.



I'm now working with a web API project that is hooked into an Azure Message Bus, processing and persisting data from the bus and providing an API endpoint for the data. The class processing and persisting the messages from Azure Message Bus is QueueProcessor.



I need to persist the data from project start, which means I need an instance of DbContext from when the project is ran as opposed to when I'm querying data out via an API endpoint. Due to this, the constructor of QueueProcessor is never implicitly called, and if I want to manually do so I need a pre-existing instance of MyDbContext to pass to it.



I've been researching this for a couple of days, trying out some manual patterns but I'm running into concurrency issues and the whole project feels like a hack at the moment.



The closest question I've come across is this, which despite specifying non-controllers, the accepted answer requires a controller for the dependency to be injected.



This is what I'm currently doing:



    public void ConfigureServices(IServiceCollection services)
{
services.AddHangfire(x => x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));

services.AddDbContextPool<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("default")));

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}


I'm then having to create a new instance of my QueueProcessor and use var context = new MyDbContext() inside the constructor. This is causing concurrency issues and completely negates the DI.



If I want to inject MyDbContext with DI like I have done hundreds of times, creating an instance of the class to run a process inside the QueueProcessor means I have to pass an instance of MyDbContext to the constructor myself. VS flags this up at design time.



I've ever tried botching this as much as possible by doing:



services.AddTransient(x => new QueueProcessor(x.GetService<MyDbContext>(), Configuration.GetConnectionString("MessageBus")));


I'm looking for a cleaner way of achieving:




  • Invoke a method inside QueueProcessor to handle Azure Message Bus messages from project start.

  • Before messages are processed, I should have an instantiated instance of MyDbContext that I can use to persist the messages when they get processed.

  • Not have to use a Controller to set up the DI correctly.


Is there a way to achieve this or have I completely missed the mark here?










share|improve this question



























    1















    I've used DI across multiple ASP.NET (Core) applications where DbContext is injected into a controller constructor, and upon the first request to the controller, the constructor is ran and the dependency injected.



    I'm now working with a web API project that is hooked into an Azure Message Bus, processing and persisting data from the bus and providing an API endpoint for the data. The class processing and persisting the messages from Azure Message Bus is QueueProcessor.



    I need to persist the data from project start, which means I need an instance of DbContext from when the project is ran as opposed to when I'm querying data out via an API endpoint. Due to this, the constructor of QueueProcessor is never implicitly called, and if I want to manually do so I need a pre-existing instance of MyDbContext to pass to it.



    I've been researching this for a couple of days, trying out some manual patterns but I'm running into concurrency issues and the whole project feels like a hack at the moment.



    The closest question I've come across is this, which despite specifying non-controllers, the accepted answer requires a controller for the dependency to be injected.



    This is what I'm currently doing:



        public void ConfigureServices(IServiceCollection services)
    {
    services.AddHangfire(x => x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));

    services.AddDbContextPool<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("default")));

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }


    I'm then having to create a new instance of my QueueProcessor and use var context = new MyDbContext() inside the constructor. This is causing concurrency issues and completely negates the DI.



    If I want to inject MyDbContext with DI like I have done hundreds of times, creating an instance of the class to run a process inside the QueueProcessor means I have to pass an instance of MyDbContext to the constructor myself. VS flags this up at design time.



    I've ever tried botching this as much as possible by doing:



    services.AddTransient(x => new QueueProcessor(x.GetService<MyDbContext>(), Configuration.GetConnectionString("MessageBus")));


    I'm looking for a cleaner way of achieving:




    • Invoke a method inside QueueProcessor to handle Azure Message Bus messages from project start.

    • Before messages are processed, I should have an instantiated instance of MyDbContext that I can use to persist the messages when they get processed.

    • Not have to use a Controller to set up the DI correctly.


    Is there a way to achieve this or have I completely missed the mark here?










    share|improve this question

























      1












      1








      1


      0






      I've used DI across multiple ASP.NET (Core) applications where DbContext is injected into a controller constructor, and upon the first request to the controller, the constructor is ran and the dependency injected.



      I'm now working with a web API project that is hooked into an Azure Message Bus, processing and persisting data from the bus and providing an API endpoint for the data. The class processing and persisting the messages from Azure Message Bus is QueueProcessor.



      I need to persist the data from project start, which means I need an instance of DbContext from when the project is ran as opposed to when I'm querying data out via an API endpoint. Due to this, the constructor of QueueProcessor is never implicitly called, and if I want to manually do so I need a pre-existing instance of MyDbContext to pass to it.



      I've been researching this for a couple of days, trying out some manual patterns but I'm running into concurrency issues and the whole project feels like a hack at the moment.



      The closest question I've come across is this, which despite specifying non-controllers, the accepted answer requires a controller for the dependency to be injected.



      This is what I'm currently doing:



          public void ConfigureServices(IServiceCollection services)
      {
      services.AddHangfire(x => x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));

      services.AddDbContextPool<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("default")));

      services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
      }


      I'm then having to create a new instance of my QueueProcessor and use var context = new MyDbContext() inside the constructor. This is causing concurrency issues and completely negates the DI.



      If I want to inject MyDbContext with DI like I have done hundreds of times, creating an instance of the class to run a process inside the QueueProcessor means I have to pass an instance of MyDbContext to the constructor myself. VS flags this up at design time.



      I've ever tried botching this as much as possible by doing:



      services.AddTransient(x => new QueueProcessor(x.GetService<MyDbContext>(), Configuration.GetConnectionString("MessageBus")));


      I'm looking for a cleaner way of achieving:




      • Invoke a method inside QueueProcessor to handle Azure Message Bus messages from project start.

      • Before messages are processed, I should have an instantiated instance of MyDbContext that I can use to persist the messages when they get processed.

      • Not have to use a Controller to set up the DI correctly.


      Is there a way to achieve this or have I completely missed the mark here?










      share|improve this question














      I've used DI across multiple ASP.NET (Core) applications where DbContext is injected into a controller constructor, and upon the first request to the controller, the constructor is ran and the dependency injected.



      I'm now working with a web API project that is hooked into an Azure Message Bus, processing and persisting data from the bus and providing an API endpoint for the data. The class processing and persisting the messages from Azure Message Bus is QueueProcessor.



      I need to persist the data from project start, which means I need an instance of DbContext from when the project is ran as opposed to when I'm querying data out via an API endpoint. Due to this, the constructor of QueueProcessor is never implicitly called, and if I want to manually do so I need a pre-existing instance of MyDbContext to pass to it.



      I've been researching this for a couple of days, trying out some manual patterns but I'm running into concurrency issues and the whole project feels like a hack at the moment.



      The closest question I've come across is this, which despite specifying non-controllers, the accepted answer requires a controller for the dependency to be injected.



      This is what I'm currently doing:



          public void ConfigureServices(IServiceCollection services)
      {
      services.AddHangfire(x => x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));

      services.AddDbContextPool<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("default")));

      services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
      }


      I'm then having to create a new instance of my QueueProcessor and use var context = new MyDbContext() inside the constructor. This is causing concurrency issues and completely negates the DI.



      If I want to inject MyDbContext with DI like I have done hundreds of times, creating an instance of the class to run a process inside the QueueProcessor means I have to pass an instance of MyDbContext to the constructor myself. VS flags this up at design time.



      I've ever tried botching this as much as possible by doing:



      services.AddTransient(x => new QueueProcessor(x.GetService<MyDbContext>(), Configuration.GetConnectionString("MessageBus")));


      I'm looking for a cleaner way of achieving:




      • Invoke a method inside QueueProcessor to handle Azure Message Bus messages from project start.

      • Before messages are processed, I should have an instantiated instance of MyDbContext that I can use to persist the messages when they get processed.

      • Not have to use a Controller to set up the DI correctly.


      Is there a way to achieve this or have I completely missed the mark here?







      c# entity-framework azure dependency-injection async-await






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 28 '18 at 10:30









      Jay GouldJay Gould

      1,7071124




      1,7071124
























          1 Answer
          1






          active

          oldest

          votes


















          1














          A working solution, not sure if it's the best pattern:




          1. In Startup.cs chance ConfigureServices to return IServiceProvider rather than void.

          2. Build the serviceProvider using: var serviceProvider = services.BuildServiceProvider();

          3. Get the instance of MyDbContext: var context = serviceProvider.GetRequiredService<MyDbContext>();

          4. Create an instance of QueueProcessor and pass context to the constructor and invoke method to begin processing messages.

          5. From ConfigureServices, return your new serviceProvider.


          Full code block:



              public IServiceProvider ConfigureServices(IServiceCollection services)
          {
          services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("...")));

          var serviceProvider = services.BuildServiceProvider();

          var localMyDbContext = serviceProvider.GetRequiredService<MyDbContext>();

          Processor = new QueueProcessor(localDbContext, Configuration.GetConnectionString("Other"));
          Processor.RunAsync().GetAwaiter().GetResult();

          return serviceProvider;
          }





          share|improve this answer

























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53517321%2fdependency-injected-dbcontext-is-always-null%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            1














            A working solution, not sure if it's the best pattern:




            1. In Startup.cs chance ConfigureServices to return IServiceProvider rather than void.

            2. Build the serviceProvider using: var serviceProvider = services.BuildServiceProvider();

            3. Get the instance of MyDbContext: var context = serviceProvider.GetRequiredService<MyDbContext>();

            4. Create an instance of QueueProcessor and pass context to the constructor and invoke method to begin processing messages.

            5. From ConfigureServices, return your new serviceProvider.


            Full code block:



                public IServiceProvider ConfigureServices(IServiceCollection services)
            {
            services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("...")));

            var serviceProvider = services.BuildServiceProvider();

            var localMyDbContext = serviceProvider.GetRequiredService<MyDbContext>();

            Processor = new QueueProcessor(localDbContext, Configuration.GetConnectionString("Other"));
            Processor.RunAsync().GetAwaiter().GetResult();

            return serviceProvider;
            }





            share|improve this answer






























              1














              A working solution, not sure if it's the best pattern:




              1. In Startup.cs chance ConfigureServices to return IServiceProvider rather than void.

              2. Build the serviceProvider using: var serviceProvider = services.BuildServiceProvider();

              3. Get the instance of MyDbContext: var context = serviceProvider.GetRequiredService<MyDbContext>();

              4. Create an instance of QueueProcessor and pass context to the constructor and invoke method to begin processing messages.

              5. From ConfigureServices, return your new serviceProvider.


              Full code block:



                  public IServiceProvider ConfigureServices(IServiceCollection services)
              {
              services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("...")));

              var serviceProvider = services.BuildServiceProvider();

              var localMyDbContext = serviceProvider.GetRequiredService<MyDbContext>();

              Processor = new QueueProcessor(localDbContext, Configuration.GetConnectionString("Other"));
              Processor.RunAsync().GetAwaiter().GetResult();

              return serviceProvider;
              }





              share|improve this answer




























                1












                1








                1







                A working solution, not sure if it's the best pattern:




                1. In Startup.cs chance ConfigureServices to return IServiceProvider rather than void.

                2. Build the serviceProvider using: var serviceProvider = services.BuildServiceProvider();

                3. Get the instance of MyDbContext: var context = serviceProvider.GetRequiredService<MyDbContext>();

                4. Create an instance of QueueProcessor and pass context to the constructor and invoke method to begin processing messages.

                5. From ConfigureServices, return your new serviceProvider.


                Full code block:



                    public IServiceProvider ConfigureServices(IServiceCollection services)
                {
                services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("...")));

                var serviceProvider = services.BuildServiceProvider();

                var localMyDbContext = serviceProvider.GetRequiredService<MyDbContext>();

                Processor = new QueueProcessor(localDbContext, Configuration.GetConnectionString("Other"));
                Processor.RunAsync().GetAwaiter().GetResult();

                return serviceProvider;
                }





                share|improve this answer















                A working solution, not sure if it's the best pattern:




                1. In Startup.cs chance ConfigureServices to return IServiceProvider rather than void.

                2. Build the serviceProvider using: var serviceProvider = services.BuildServiceProvider();

                3. Get the instance of MyDbContext: var context = serviceProvider.GetRequiredService<MyDbContext>();

                4. Create an instance of QueueProcessor and pass context to the constructor and invoke method to begin processing messages.

                5. From ConfigureServices, return your new serviceProvider.


                Full code block:



                    public IServiceProvider ConfigureServices(IServiceCollection services)
                {
                services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("...")));

                var serviceProvider = services.BuildServiceProvider();

                var localMyDbContext = serviceProvider.GetRequiredService<MyDbContext>();

                Processor = new QueueProcessor(localDbContext, Configuration.GetConnectionString("Other"));
                Processor.RunAsync().GetAwaiter().GetResult();

                return serviceProvider;
                }






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Dec 5 '18 at 9:15

























                answered Nov 28 '18 at 11:07









                Jay GouldJay Gould

                1,7071124




                1,7071124
































                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53517321%2fdependency-injected-dbcontext-is-always-null%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Lallio

                    Futebolista

                    Jornalista