Где хранить данные для текущего вызова WCF? ThreadStatic безопасно?
Пока мой сервис выполняется, многим классам потребуется доступ к User.Current (это мой собственный класс User). Могу ли я безопасно хранить _currentUser в [ThreadStatic]
переменная? WCF повторно использует свои потоки? Если это так, когда он очистит данные ThreadStatic? Если использование ThreadStatic небезопасно, где я должен поместить эти данные? Есть ли место внутри OperationContext.Current, где я могу хранить такие данные?
Изменить 14/12/2009: я могу утверждать, что использование переменной ThreadStatic небезопасно. Потоки WCF находятся в пуле потоков, а переменная ThreadStatic никогда не инициализируется повторно.
3 ответа
Есть блог, который предлагает реализовать 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;
Альтернативное решение без добавления дополнительного класса.
OperationContext operationContext = OperationContext.Current;
operationContext.IncomingMessageProperties.Add("SessionKey", "ABCDEFG");
Чтобы получить значение
var ccc = aaa.IncomingMessageProperties["SessionKey"];
это оно
Я обнаружил, что мы пропускаем данные или текущий контекст, когда мы делаем асинхронный вызов с многопоточным переключением. Для обработки такого сценария вы можете попробовать использовать 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.