#c# #asp.net-core #dependency-injection #entity-framework-core
#c# #asp.net-core #внедрение зависимостей #entity-framework-core
Вопрос:
Мне трудно понять, как это сделать. Это многопользовательское приложение ASP MVC Core 3.1, и текущий способ разрешения текущего клиента пользователя — это использование утверждений в файле cookie. У меня есть следующее в startup.cs
ConfigureServices
методе:
services.AddScoped<ITenantResolver, TenantResolver>();
services.AddScoped(p => p.GetService<IHttpContextAccessor>()?.HttpContext?.GetTenant());
и следующее промежуточное программное обеспечение, зарегистрированное в Configure
методе:
app.UseMiddleware<TenantResolutionMiddleware>();
Процесс заключается в том, что промежуточное программное обеспечение разрешает клиента (используя TenantResolver
), а затем устанавливает его в HttpContext
. Метод GetTenant()
расширения HttpContext
возвращает клиента к службам. В зависимости от выбранного клиента используются разные строки соединений, и поэтому EFCore
DbContext
он связан с другой базой данных. На самом деле единственное различие, когда выбираются разные арендаторы DbContext
, — это объект и Tenant
объект;
Все это работает, но что мне нужно, чтобы иметь возможность использовать службы вне конвейера запросов, скажем, в фоновом задании hangfire или во вспомогательном проекте. Мне нужны службы для создания отчетов о разных базах данных в приложении, у которого нет конвейера запросов.
Я хочу иметь возможность делать что-то вроде этого:
foreach(var tenant in Tenants)
{
// set the tenant
// get a service provider for that tenant and use those services
}
Я знаю, что мне нужно иметь возможность «установить арендатора» вне системы разрешения арендаторов, но мой разум застрял в стеке запросов.
Спасибо, Брайан
Комментарии:
1. Итак, логика разрешения клиента основана на утверждениях, использующих строковые значения? Какая коллекция строковых значений сопоставляется с вашей коллекцией клиентов? Все это не зависит от HttpRequest, который является просто механизмом сохранения строкового значения в заявках с помощью файлов cookie. Я предполагаю
HttpContext.User
, что используется для получения доступа к утверждениям в вашем промежуточном программном обеспечении, но это весь синтаксический сахар для получения строкового значения.2. Да, я использую
HttpContext.User
для получения утверждений, есть утверждение ‘currentTenant’ со значением идентификатора арендатора. Есть также претензии относительно того, имеют ли они доступ, который используется в разделе аутентификации, но для DI я просто забочусь о ‘currentTenant’.
Ответ №1:
Ваши службы все еще используют внедрение зависимостей? Вы можете создать ITenantResolver, который позволяет вам явно устанавливать клиента:
class TenantResolver : ITenantResolver
{
// Not sure what type 'Tenant' is, but you can change it to suit
public string Tenant { get; set; }
string GetTenant() => Tenant;
}
Затем в основном цикле выполнения вашей службы:
var factory = services.GetService<IServiceScopeFactory>();
foreach (var tenant in Tenants)
{
using (var scope = factory.CreateScope())
{
scope.Services.GetService<TenantResolver>().Tenant = tenant;
// Use scope.Services to resolve services using the current tenant
}
}
Комментарии:
1. Да, существует множество служб, которые зависят от разрешенного клиента и соответствующего DbContrext. Видя ваш ответ, я думаю, конечно, мне просто нужен другой TenantResolver и в некотором смысле новое «дерево зависимостей» (простите, если это неправильный термин). Я предполагаю, что это и есть «область видимости» в вашем примере. Думаю, мне нужно создать новую область вне конвейера запросов. Нужно ли мне перерегистрировать все службы в этой области? Я посмотрю на это, спасибо.
2. Создание областей — это отдельный процесс для регистрации служб. Вы регистрируете службы один раз при запуске, затем все созданные вами области будут использовать зарегистрированные службы