Это не имеет ничего общего с кэшированием и контекстными экземплярами. Это проблема, связанная с деревьями выражений - смотрите мое обновление.
даю мультитенантное приложение и сталкиваюсь с трудностями, связанными с кэшированием идентификатора клиента в запросах. Единственная вещь, которая, кажется, помогает - постоянно перестраивать приложение, когда я вхожу и покидаю арендаторов.
Я думал, что это может иметь какое-то отношение кIHttpContextAccessor
экземпляр является одиночным, но он не может быть ограничен областью действия, и когда я вхожу и выхожу без перестройки, я вижу изменение имени арендатора в верхней части страницы, так что это не проблема.
Единственное, о чем я могу думать, это то, что EF Core выполняет какое-то кэширование запросов. Я не уверен, почему он будет считать, что это экземпляр с заданной областью, и он должен перестраиваться при каждом запросе, если я не ошибаюсь, что, вероятно, и есть. Я надеялся, что он будет вести себя как экземпляр с заданной областью, поэтому я мог бы просто ввести идентификатор клиента во время построения модели для каждого экземпляра.
Я был бы очень признателен, если бы кто-то указал мне правильное направление. Вот мой текущий код:
TenantProvider.cs
public sealed class TenantProvider :
ITenantProvider {
private readonly IHttpContextAccessor _accessor;
public TenantProvider(
IHttpContextAccessor accessor) {
_accessor = accessor;
}
public int GetId() {
return _accessor.HttpContext.User.GetTenantId();
}
}
... который вводится вTenantEntityConfigurationBase.cs где я использую его для настройки глобального фильтра запросов.
internal abstract class TenantEntityConfigurationBase<TEntity, TKey> :
EntityConfigurationBase<TEntity, TKey>
where TEntity : TenantEntityBase<TKey>
where TKey : IEquatable<TKey> {
protected readonly ITenantProvider TenantProvider;
protected TenantEntityConfigurationBase(
string table,
string schema,
ITenantProvider tenantProvider) :
base(table, schema) {
TenantProvider = tenantProvider;
}
protected override void ConfigureFilters(
EntityTypeBuilder<TEntity> builder) {
base.ConfigureFilters(builder);
builder.HasQueryFilter(
e => e.TenantId == TenantProvider.GetId());
}
protected override void ConfigureRelationships(
EntityTypeBuilder<TEntity> builder) {
base.ConfigureRelationships(builder);
builder.HasOne(
t => t.Tenant).WithMany().HasForeignKey(
k => k.TenantId);
}
}
... который затем наследуется всеми другими конфигурациями объекта-арендатора. К сожалению, это не работает так, как я планировал.
Я проверил, что идентификатор арендатора, возвращаемый принципалом пользователя, изменяется в зависимости от того, какой пользователь арендатора вошел в систему, поэтому проблема не в этом. Заранее благодарю за любую помощь!
Обновить
Для решения при использовании EF Core 2.0.1+ посмотрите на непринятый от меня ответ.
Обновление 2
Также посмотрите на обновление Ивана для 2.0.1+, оно прокси в выражении фильтра из DbContext, которое восстанавливает возможность определить его один раз в базовом классе конфигурации. Оба решения имеют свои плюсы и минусы. Я снова выбрал Ивана, потому что я просто хочу максимально использовать свои базовые конфигурации.