То, что вы хотите, не возможно, и вы не должны пытаться достичь этого.Ваш вопрос вызван кодом, который жестко зависит от HttpContext.Current
.Это нарушение принципа инверсии зависимости.Поскольку ваш код выполняется в фоновом потоке, он не выполняется в контексте HTTP-запроса и поэтому не должен использовать информацию запроса.
Решение состоит в том, чтобы определить абстракции для конкретного приложения, которые абстрагируют HttpContext
.Например, если для этого кода требуется информация о текущем пользователе, определите абстракцию IUserContext
:
public interface IUserContext
{
Guid UserId { get; }
}
. Это позволит вам внедрить другую реализацию IUserContext
при работе в фоновом потоке.
Реализация IUserContext
для ваших веб-запросов может выглядеть следующим образом:
public sealed class AspNetUserContext : IUserContext
{
public Guid UserId => (Guid)HttpContext.Current.Session["UserId"];
}
Пользовательский контекст, который вы используете в фоновом потоке, с другой стороны, может быть реализован следующим образом:
public sealed class ThreadStaticUserContext : IUserContext
{
[ThreadStatic]
public static Guid UserIdField;
public Guid UserId => this.UserIdField;
}
Этот ThreadStaticUserContext
позволяет установить UserId
.Если вы хотите выделить фоновый поток, который запускается с тем же идентификатором пользователя, что и исходный запрос, вам придется передать идентификатор пользователя в фоновый поток и установить значение FixedUserContext.UserId
перед выполнением полной операции.Это может выглядеть так:
public AsynchronousWelcomeMessageSenderDecorator : IWelcomeMessageSender
{
private readonly IUserContext userContext;
private readonly Func<IWelcomeMessageSender> senderFactory;
public AsynchronousWelcomeMessageSenderDecorator(
IUserContext userContext,
Func<IWelcomeMessageSender> senderFactory) { ... }
public void SendWelcomeMessage(WelcomeMessage message)
{
// Read the user ID while running on the request thread
Guid userId = this.userContext.UserId;
ThreadPool.QueueUserWorkItem(_ =>
{
// Set the user ID as the first thing to do on the background thread.
ThreadStaticUserContext.UserIdField = userId;
// Resolve the 'real' sender within the thread.
IWelcomeMessageSender realSender = this.senderFactory();
// Forward the call to the real sender.
realSender.SendWelcomeMessage(message);
});
}
}
Чтобы дать вам представление, без DI-контейнера эту часть графа объектов можно построить следующим образом:
IWelcomeMessageSender sender =
new AsynchronousWelcomeMessageSenderDecorator(
new AspNetUserContext(),
() => new EmailMessageSender(new ThreadSpecificUserContext()));
Другими словамилюбой компонент, который зависит от IWelcomeMessageSender
, будет введен AsynchronousWelcomeMessageSenderDecorator
.Когда вызывается его SendWelcomeMessage
, он раскручивает фоновый поток, который запросит IWelcomeMessageSender
через senderFactory
.senderFactory
создаст новый EmailMessageSender
, который будет отправлять фактическую почту.Это EmailMessageSender
снова зависит от IUserContext
, но в этом случае оно вводится с ThreadSpecificUserContext
.