I noticed something strange when injecting ITokenAcquisition.
You can find my code to reproduce the issue here: Github Repo
I use the NuGet Microsoft.Identity.Web 2.18.0 to enable MSAL authentication in my ASP.NET Api (.NET 7)
My Program.cs looks like this:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration)
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddHostedService<QueuedHostedService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
You can see that together with my API, a background service is also running:
public class QueuedHostedService : BackgroundService
{
ITokenAcquisition _tokenAcquisition;
public QueuedHostedService(ITokenAcquisition tokenAcquisition)
{
_tokenAcquisition = tokenAcquisition;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await BackgroundProcessing(stoppingToken);
}
private async Task BackgroundProcessing(CancellationToken stoppingToken)
{
var token = await _tokenAcquisition.GetAccessTokenForAppAsync("api://0f5ff0f2-5a7f-430e-8ea1-6e133055990e/.default");
while (!stoppingToken.IsCancellationRequested)
{
Console.WriteLine("Executing...");
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
// "Queued Hosted Service is stopping.");
await base.StopAsync(stoppingToken);
}
}
This service uses ITokenAcquisition to get an access token for another API (could be the graph or so)
My controller action looks almost standard, but has the Authorize-Attribute
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
ITokenAcquisition _tokenAcquisition;
public WeatherForecastController(ITokenAcquisition tokenAcquisition)
{
_tokenAcquisition = tokenAcquisition;
}
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> GetAsync()
{
var token = await _tokenAcquisition.GetAccessTokenForAppAsync("api://0f5ff0f2-5a7f-430e-8ea1-6e133055990e/.default");
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
My code works and the background service receives the access token, but only when the ASPNETCORE_ENVIRONMENT variable is set to “Test” or “Production”.
In Development my service fails with the following error message:
Cannot consume scoped service
‘Microsoft.Identity.Web.ITokenAcquisition’ from singleton
‘Microsoft.Extensions.Hosting.IHostedService’.)’
Anybody knows:
- Is it allowed to inject ITokenAcquisition in a background service?
- How can it be that it works in Test or Production modes, but never in Development mode?