skip to Main Content

First off, sorry for the really bad question title. I couldn’t think of a better way to word it. I’m open to suggestions for an edit!

In my ASP.NET app written to target .NET 7, I have this in my Program.cs class:

var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<AppConfiguration>(builder.Configuration.GetSection(AppConfiguration.ConfigurationSectionName));

builder.Services.AddAuthentication(options =>
{
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
}
)
.AddOpenIdConnect(options =>
{
    options.ClientId = "whatever";
    // etc...

    options.Events = new OpenIdConnectEvents()
    {
        OnRemoteFailure = AuthenticationHelper.OnAuthenticationFailed,
        OnAuthorizationCodeReceived = AuthenticationHelper.OnAuthenticationSucceeded
    };
});

Then I have my AuthenticationHelper class which, at the moment (I need to build it out) looks like this:

internal static class AuthenticationHelper
{
    internal static Task OnAuthenticationFailed(RemoteFailureContext context)
    {
        context.HandleResponse();
        context.Response.Redirect("/?errormessage=" + context.Failure?.Message ?? string.Empty);
        return Task.FromResult(0);
    }

    internal static Task OnAuthenticationSucceeded(AuthorizationCodeReceivedContext context)
    {
        var claim = new Claim(_appConfiguration.MyClaimName, "My value");
        return Task.FromResult(0);
    }
}

Note that second-to-last line, where I’m referencing a variable named _appConfiguration. That obviously doesn’t work because the variable isn’t declared anywhere. I’ve copied this line from another class where dependency injection is used to inject the app configuration.

The problem is that I obviously can’t use DI in my AuthenticationHelper class becaues it’s a static class, and, so far, I can’t work out how to change it to a standard class (i.e. not static) and still be able to reference it when assigning values to OnRemoteFailure and OnAuthorizationCodeReceived in Program.cs.

As far as I can see, my two options are to either:

  1. Find another way to get the app configuration in Authentication Helper without using DI.
  2. Find a way to reference an instance of AuthenticationHelper in Program.cs if I make it non-static.

So far, I can’t figure out how to do either! The closest I’ve come is to make the AuthenticationHelper class non-static, add it as a singleton service in Program.cs, and change the event option assignments to e.g.:

OnAuthorizationCodeReceived = builder.Services.BuildServiceProvider().GetService<IAuthenticationHelper>().OnAuthenticationSucceeded

This works, but I’m aware that using BuildServiceProvider() is a bad idea, as it creates a new instance of the singleon class every time.

What’s the best approach to this?

2

Answers


  1. Register AppConfiguration as DI service and access it using the context object like this:

    internal static Task OnAuthenticationSucceeded(AuthorizationCodeReceivedContext context)
    {
        var appConfiguration = context.HttpContext.RequestServices.GetRequiredService<AppConfiguration>();
    
        var claim = new Claim(appConfiguration.MyClaimName, "My value");
        return Task.FromResult(0);
    }
    
    Login or Signup to reply.
  2. If AuthenticationHelper needs to be static, Method Injection is the generally the answer.

    This means that, in your case, you add AppConfiguration as parameter to the OnAuthenticationSucceeded method, as shown here:

    internal static class AuthenticationHelper
    {
        ...
    
        internal static Task OnAuthenticationSucceeded(
            AuthorizationCodeReceivedContext context,
            AppConfiguration appConfiguration) // <-- Apply Method Injection here
        {
            var claim = new Claim(appConfiguration.MyClaimName, "My value");
            return Task.FromResult(0);
        }
    }
    

    Inside your Composition Root you then supply AppConfiguration to the OnAuthenticationSucceeded method, as demonstrated next:

    var appSection = builder.Configuration
        .GetSection(AppConfiguration.ConfigurationSectionName);
    var appConfig = appSection.Get<AppConfiguration>();
    builder.Services.Configure<AppConfiguration>(appSection);
    
    ...
    
    .AddOpenIdConnect(options =>
    {
        options.ClientId = "whatever";
        // etc...
    
        options.Events = new OpenIdConnectEvents()
        {
            OnRemoteFailure = AuthenticationHelper.OnAuthenticationFailed,
            OnAuthorizationCodeReceived =
                context => AuthenticationHelper.OnAuthenticationSucceeded(
                    context,
                    appConfig) // <-- Method Injection here
        };
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search