Где хранить данные для текущего вызова WCF? Безопасен ли ThreadStatic?
Пока моя служба выполняется, многим классам необходимо будет получить доступ к User.Current(это мой собственный класс User). Могу ли я безопасно хранить _currentUser в переменной [ThreadStatic]
? Использует ли WCF свои потоки? Если это так, когда он очистит данные ThreadStatic? Если использование ThreadStatic небезопасно, где я должен помещать эти данные? Есть ли место внутри OperationContext.Current, где я могу хранить такие данные?
Редактировать 12/14/2009: Я могу утверждать, что использование переменной ThreadStatic небезопасно. Потоки WCF находятся в пуле потоков, и переменная ThreadStatic никогда не повторно инициализируется.
Ответы
Ответ 1
Там есть блог post, который предполагает реализацию IExtension<T>
. Вы также можете взглянуть на этот обсуждение.
Здесь предлагается реализация:
public class WcfOperationContext : IExtension<OperationContext>
{
private readonly IDictionary<string, object> items;
private WcfOperationContext()
{
items = new Dictionary<string, object>();
}
public IDictionary<string, object> Items
{
get { return items; }
}
public static WcfOperationContext Current
{
get
{
WcfOperationContext context = OperationContext.Current.Extensions.Find<WcfOperationContext>();
if (context == null)
{
context = new WcfOperationContext();
OperationContext.Current.Extensions.Add(context);
}
return context;
}
}
public void Attach(OperationContext owner) { }
public void Detach(OperationContext owner) { }
}
Что вы можете использовать так:
WcfOperationContext.Current.Items["user"] = _currentUser;
var user = WcfOperationContext.Current.Items["user"] as MyUser;
Ответ 2
РЕДАКТИРОВАТЬ: Не используйте это решение. Вместо этого используйте подход Дарин. Как сказал @np-hard, это решение не будет работать, если есть асинхронные операции (происходит переключение потоков).
Я нашел другое решение. Вы можете использовать событие OperationCompleted класса OperationContext, чтобы очистить переменные ThreadStatic.
public class SomeClass
{
[ThreadStatic]
private static _currentUser = null;
public static void GetUser()
{
if ( _currentUser == null )
{
_currentUser = LoadUser();
// Reinitialize _currentUser at the end of the request
OperationContext.Current.OperationCompleted +=
(sender, args) => _currentUser = null;
}
return _currentUser;
}
}
Забастовкa >
Ответ 3
Альтернативное решение без добавления дополнительного Drived класса.
OperationContext operationContext = OperationContext.Current;
operationContext.IncomingMessageProperties.Add("SessionKey", "ABCDEFG");
Чтобы получить значение
var ccc = aaa.IncomingMessageProperties["SessionKey"];
Это
Ответ 4
Я обнаружил, что мы пропускаем данные или текущий контекст, когда делаем асинхронный вызов с несколькими переключениями потоков. Чтобы справиться с таким сценарием, вы можете попробовать использовать CallContext. Он должен использоваться в удалении .NET, но он также должен работать в таком сценарии.
Задайте данные в CallContext:
DataObject data = new DataObject() { RequestId = "1234" };
CallContext.SetData("DataSet", data);
Получение общих данных из CallContext:
var data = CallContext.GetData("DataSet") as DataObject;
// Shared data object has to implement ILogicalThreadAffinative
public class DataObject : ILogicalThreadAffinative
{
public string Message { get; set; }
public string Status { get; set; }
}
Почему ILogicalThreadAffinative?
Когда удаленный вызов метода выполняется для объекта в другом AppDomain, текущий класс CallContext генерирует LogicalCallContext, который перемещается вместе с вызовом удаленного места.
Только объекты, которые открывают интерфейс ILogicalThreadAffinative и хранятся в CallContext, распространяются вне AppDomain.