I have multi-tenant Web API application built using ASP.NET Core 6. We are using HangFire for Report Scheduling. It uses Onion based Architecture where Interface lies in the application and implementation outside the layer
Project has application Layer and Integration Layer , so IDbContext will be present in app layer and implementation class DbContext lies in Integration Layer, so I can not create dbContext instance directly from app layer as it is not accessible.
As it is web API , we use jwt token and this token is passed as part of "Http Request Header" for every other request for user to authorize.
As background jobs run , this HttpContext will be null which ends up giving error for all services as most of the DI services use this to get the values like connection String for DbContext, logged in user, URL to third party services as all are stored as part of that HttpHeader.
public jmasdbContext(DbContextOptions<jmasdbContext> options, ITenantProviderService tnt, IJwtAuthenticationManager jwt, IWebHostEnvironment env)
: base(options)
{
//Check if is developement is added for migration purpose.- THIS IF CONDITION CAN BE REMOVED WHILE DEPLOYING TO PRODUCTION
if (!env.EnvironmentName.Equals("Development"))
{
//This if part will be executed only during Login creation as Claims will not be set at this time,
//we need to fetch ConnectionString from Tenant...
if (tnt != null && tnt.HasTenantSet())
{
ConnectionString = tnt.Tenant.ConnectionString;
}
else if (jwt != null && !string.IsNullOrEmpty(jwt.GetAccessToken()))
{
ConnectionString = jwt.GetTenantConnectionString();
}
}
}
Here is how the connectionString is Set. First part gets executed during setting the tenant (login) and else part for every subsequent request
The code jwt.GetAccessToken() is dependent on httpContext and jwt.GetTenantConnectionString() is dependent on the jwt.GetAccessToken as it is stored as part of token claims.
/// <summary>
/// Gets the token passed in Header
/// </summary>
/// <returns>Access Token</returns>
public string GetAccessToken()
{
if (_httpContextAccessor != null && _httpContextAccessor.HttpContext != null)
{
return _httpContextAccessor.HttpContext.Request.Headers["Authorization"];
}
if (!string.IsNullOrEmpty(AccessToken))
{
return AccessToken;
}
return string.Empty;
}
To get the connectionString for the Tenant
/// <summary>
/// Get Tenant's connection string
/// </summary>
/// <returns></returns>
public string GetTenantConnectionString()
{
var customerDomain_Name = GetCustomerDomain();
var keyName = customerDomain_Name + ":DataContext";
var connectionString = _configuration.GetValue<string>(keyName);
return connectionString;
}
I tried faking using "https://stackoverflow.com/questions/47404479/add-httpcontext-into-hangfire" and other Unit test ways but nothing seem to work and defining HttpContext in .NET Core has been changed and I can not create HttpContext manually and need to be injected via IHttpContextAccessor.
Do you see any ways this can be achieved?