Разрешение мультитенантной информации из HttpContext и асинхронных вызовов
Я занимаюсь разработкой многопользовательского приложения ASP.NET MVC. В мультитенантном приложении первый аспект мультитенантности - это идентификация арендаторов на основе информации, доступной в текущем запросе.
Это приложение использует OpenID Connect для аутентификации. Идея состоит в том, чтобы после успешной аутентификации пользователя найти соответствующего арендатора (т.е. TenantID) и сохранить TenantID
в качестве претензии на HttpContext. Для любого последующего запроса я могу разрешить клиента из HttpContext и использовать его TenantID
фильтровать EF-запросы. Что-то вроде этого
public class ClientService:IClientService
{
public async Task<Client> GetClientInfo()
{
//NOTE: The framework will implicitly resolve the TenantID from HttpContext and make it available to the Service.
return await _dbContext.Clients.Where(x=>x.TenantID = this.TenantID)
.SingleOrDefaultAsync()
.ConfigureAwait(false)
}
}
а затем в контроллере
public class ClientController
{
private readonly IClientService _service;
public ClientController(IClientService service)
{
_service = service;
}
public async Task<ActionResult> Index()
{
var entity = await _service.GetClientInfo().ConfigureAwait(false);
var model = MapEntityToModel(entity);
return View(model);
}
}
Обратите внимание на использование ConfigureAwait(false)
, (Есть несколько статей и ТАК обсуждений, почему мы должны использовать ConfigureAwait(false)
чтобы избежать тупиков и лучшей производительности. Как этот MSDN)
Проблема из-за ConfigureAwait(false)
HttpContext будет нулевым в ClientService
Одним из способов решения этой проблемы является получение TenantID
в контроллере и передать его в качестве параметра
public async Task<ActionResult> Index()
{
// get the tenantid that is stored in claims on HttpContext
var tenantID = GetTenantIDFromHttpContext();
var entity = await _service.GetClientInfo(tenantID).ConfigureAwait(false);
var model = MapEntityToModel(entity);
return View(model);
}
Однако приложение будет иметь несколько сотен методов обслуживания, и каждый будет использовать TenantID для фильтрации запросов EF. Разрешить его в контроллере не представляется возможным.
Есть ли другие способы решения TenantID
без необходимости идти на компромисс ConfigureAwait(false)