I have read through all other posts on this matter and I'm certain this is not a duplicate.
I'm building a Razor page filter to be used in my Startup.cs class and I need access to the HttpContext. I would normally do this through constructor injection using ASP.NET Core's DI capabilities. I even have the usual services.AddHttpContextAccessor() statement in Startup.cs and use it elsewhere in my project.
Since I'm bulding a Razor page filter which derives from IAsyncPageFilter, and is created from the Startup.cs class, it doesn't appear as though I can inject it (since it's created by startup, and not injected).
Here is the addition of the filter to Startup.cs:
Startup.cs (snip)
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
options.Filters.Add(new RazorAsyncPageFilter(_logger, Configuration)); <---my filter
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
Here is my filter:
RazorAsyncPageFilter.cs
public class RazorAsyncPageFilter : IAsyncPageFilter
{
private readonly ILogger _logger;
private readonly IConfiguration _configuration;
public string[] Scopes { get; set; }
public string ScopeKeySection { get; set; }
public RazorAsyncPageFilter(ILogger logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}
public async Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context)
{
await Task.CompletedTask;
}
public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
{
VaultGraphServiceClient.OnMsalUiExceptionEvent += VaultGraphServiceClientOnOnMsalUiExceptionEvent;
await next.Invoke();
}
private void VaultGraphServiceClientOnOnMsalUiExceptionEvent(object sender, MsalUiRequiredException e)
{
_logger.LogInformation($"Triggered authentication exception: {e.Message}");
Scopes = new string[] { _configuration.GetValue<string>(ScopeKeySection) };
var properties = BuildAuthenticationPropertiesForIncrementalConsent(Scopes, e, **I_NEED_CONTEXT_HERE**);
new ChallengeResult(properties);
}
}
Note the context needed in the method call triggered from an event handler in another class. I'd like to pass the HttpContext to the private method in the filter class.
Here is what I've tried:
Defining a field in
Startup.csforIHttpContextAccessor _httpContextand pass it to the filter however this obviously didn't work as that context isn't established yet.Pass context from another method. This was a bit more work and is fraught with warnings about passing it to a background thread.
Inject the context from my calling
EventHandler. Unfortunately this is being called from a static class and from what I understand, there is no concept of DI in static classes. Is this correct? Additionally, I'm using anEventHandlerdelegate which I'm using to pass theMsalUiRequiredExceptionobject and can only pass one object. Maybe I could use a different handler for theeventtype but I'm not familiar enough with events to understand how this could be done.I'm considering creating a custom class to hold both the
MsalUiRequiredExceptionand theHttpContextwhere it can be injected/passed elsewhere but this also seems like overkill or could be a problem as per #2 above.
Any suggestions?
abstract class TViewPage<TModel> : System.Web.Mvc.WebViewPage<TModel>You can used the RazorPage class in Asp.Net Core instead of WebViewPageVaultGraphServiceClient.OnMsalUiExceptionEvent