0

I am trying to find a way to inject a dependency in Startup.cs, for a aspnet5 application. I am aware of the following previous question, but hopefully I can expand on my particular requirements:

Aspnet core 5.0 inject dependency in startup.cs constructor

I initially needed a way to fire a custom method after OnSignIn with MS Identity Platform (IP) within my app. After posting the following questions, I was quickly pointed in the right direction:

How to fire a custom method after OnSignIn with MS Identity Platform

In short, during ConfigureServices in StartUp.cs, I needed to configure the IP middleware service, to add my own methods to some of its available events. Works a treat!

So I initially tried:

services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
   options.Events = new OpenIdConnectEvents
   {
      OnTicketReceived = async ctex =>
               {
                   // Blah
               },
   });

As I say, this works great. However, to do anything serious, I need access to my existing code and the DI magic that goes with it. This is where I a hitting this problem. I need my custom logic that requires DI, during ConfigureServices, before I have configured the services for DI.

On the same post, someone pointed out that you can wrap up the configuration, and essentially inject it back in, so you can get DI back. Great! But for some reason, I can only inject the handler, either as a Singleton, or Transient. Not Scoped. I get to some extent why it can't be scoped (if it is has a dependency of its own on a transient service), but then are why both extremes ok? Why is Singleton OK? Why is Transient? It just so happens, but my DI requirements are that I would need to inject scoped services, as that is what I need. I need some of the data to persist across instances, but I can't have a single instances shared across the whole application/user base.

So then I tried:

public class AzureAdOpendIdHandler : IConfigureNamedOptions<OpenIdConnectOptions>
    {

        public AzureAdOpendIdHandler(Authentication.AuthenticationManager authenticationManager)
        {
            AuthenticationManager = authenticationManager;
        }

        public Authentication.AuthenticationManager AuthenticationManager { get; }

        public void Configure(string name, OpenIdConnectOptions options)
        {
            options.Events = new OpenIdConnectEvents
            {
                OnTicketReceived = context =>
                {
                   //Blah

                    return Task.CompletedTask;
                },
            };
        }

    }

Then called in StartUp.cs like:

services.AddScoped<Authentication.IAuthenticationManager, Authentication.AuthenticationManager>();
services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, AzureAdOpendIdHandler>();

Again, the handler works fine, and everything fires, as long as I don't try and pass "AuthenticationManager" within the constructor. I get an error saying that I can't inject a scoped service into a singleton service.

I keep getting within spitting distance of doing what I need, but there is always another block in the way.

In summary:

  1. To override/extend MS Identity Platform, I need to make changes in ConfigureServices() in StartUp.cs
  2. These changes require my classes to be available via DI.
  3. The DI must allow me to pass them as scoped

So far, I can only meet the first two requirements, I can not find a way to satisfy all three.

My end requirement is to be able to add a call to my AuthenticationManager class from within the following OnTicketReceived Event:

 services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
       options.Events = new OpenIdConnectEvents
       {
          OnTicketReceived = async ctex =>
                   {
                       //use my AuthenticationManager class!!
                   },
       });

I have tried the direct method, wrapping things up in a handler and injecting, but DI seems to be getting in the way now.

Any help, would be gratefully received.

user3280560
  • 137
  • 1
  • 13
  • 2
    I don't understand. What is the need? What is the problem? What have you tried? – vernou Sep 09 '21 at 11:04
  • Apologies if not clear. I need to be able to call my own classes in ConfigureServices() in Startup.cs. As everything requires DI, and DI is not ready at that point, I am facing the issue I can't call my own classes, at that particular point. I have tried wrapping everything in a handler, and injecting this back in (example shown above), and although this works, if my DI requirement requires Scoped for my own classes within this handler, then it is not compatible (it would work if my classes could be injected as singleton, but they can't). I don't know what to try now. – user3280560 Sep 09 '21 at 11:24
  • What is the full name (namespace + class) of `AuthenticationManager`? – vernou Sep 09 '21 at 12:36
  • Authentication.AuthenticationManager. If a namespace is missing, it it is just because a using statement is not shown, while trying to demonstrate where I am at. I will edit. – user3280560 Sep 09 '21 at 14:32
  • Maybe you can manually create `AuthenticationManager` and `AzureAdOpendIdHandler`? So you can pass the AuthenticationManager in the AzureAdOpendIdHandler's constructor. – vernou Sep 10 '21 at 07:03
  • Thanks. AzureAdOpendIdHandler was initially manual anyway. I would have considered making AuthenticationManager manually, but there is a reason why I can't. There is nothing i can do about that reason, but it doesn't belong in this question, and I don't want to take it off topic. For that reason, the original question still stands; if I have to use DI to call my class, how do I use it from this area of Startup.cs. – user3280560 Sep 10 '21 at 08:11

0 Answers0