У меня есть метод, который запускается в основном потоке приложения, но создает новый Task
для долговременной работы и await
s это результат.Как получить доступ к контексту приложения из потока, который был создан с помощью Task.Factory.StartNew
public async Task<CalculatorOutputModel> CalculateXml(CalculatorInputModel input)
{
// 1
return await Task.Factory.StartNew(
new Func<CalculatorOutputModel> (() =>
{
// 2
using (var ms = Serializer.Serialize(input))
{
ms.Position = 0;
using (var rawResult = Channel.RawGetFrbXmlOutputs(ms)) // 3
{
var result = Parser.Parse(rawResult);
return result;
}
}
}),
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
Моя проблема заключается в том, что в точках контекста приложения (1) и (2) являются "немного" отличается. В пункте 1 есть обычный контекст приложения в свойстве Current
, который имеет все необходимые мне данные. В пункте 2, как вы понимаете, есть ссылка null
в AppContext.Current
, поэтому я не могу получить доступ к каким-либо данным. Проблема с доступом к контексту в точке 2 кажется легкой, просто «поймать» текущий контекст в локальной переменной или передать его в качестве параметра. Проблема для меня сложнее, потому что мне нужно получить доступ к контексту где-то в глубине строки, помеченной как «3».
Сам класс получен из , и место, где мне нужно получить доступ к контексту, является классом, который реализует IClientMessageInspector
.
class CalculatorMessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if (AppContext.Current != null)
{
// never goes here
}
}
}
Просто чтобы прояснить, вот стек вызовов (я не могу передать свой контекст внутри необходимый метод):
Итак:
- Я не могу передать контекст
Channel
, потому что это не имеет никакого смысла; - Я не могу сохранить требуемые параметры из контекста в
Channel
, потому что это прокси-класс; - Я не могу сохранить необходимые параметры в
CalculatorMessageInspector
, потому что он создан в том месте, где текущий контекст уже равен нулю.
Может ли кто-нибудь посоветовать любой метод, как я могу оставаться в том же контексте в другом потоке? Или, по крайней мере, как я могу передать параметр из места, помеченного «2» внутри иерархии методов? Может быть, я смогу использовать SynchronizationContext
как-то для его достижения? Большое спасибо за любые предложения.
Update
AppContext.Current
считают такой же, как HttpContext.Current != null ? HttpContext.Current.Items[AppContextKey] : null
Update 2 Так что, кажется, что в данном случае нет никакого общего решения сохраняется контекст. Следовательно, единственное применимое решение в этой конкретной ситуации (это довольно специфично) заключается в том, чтобы захватить требуемые параметры с помощью закрытия и сохранить тогда в объекте, который будет доступен в требуемом методе (для меня работали добавление свойств к разработчику IEndpointBehavior
, но это решение немного нечетное). Таким образом, наиболее приемлемым решением является выброс асинхронной упаковки по вызову синхронизации, поэтому AppContext
никогда не «уходит». Ответ Марка Стивена как раз тогда.
Вы не можете передавать контекст, но можете ли вы изменить подпись метода? Если вы можете, то вы можете передать делегат в BeforeSendRequest(), а затем выполнить некоторый код в этом делетете из блока кода, который имеет доступ к текущему AppContext. –
Что такое 'AppContext'? –
Просто комментарий, вы должны использовать 'Task.Run' с' async-await', как объясняет Стивен здесь: http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx –