Подтвердить что ты не робот

Где хранить данные для текущего вызова WCF? Безопасен ли ThreadStatic?

Пока моя служба выполняется, многим классам необходимо будет получить доступ к User.Current(это мой собственный класс User). Могу ли я безопасно хранить _currentUser в переменной [ThreadStatic]? Использует ли WCF свои потоки? Если это так, когда он очистит данные ThreadStatic? Если использование ThreadStatic небезопасно, где я должен помещать эти данные? Есть ли место внутри OperationContext.Current, где я могу хранить такие данные?

Редактировать 12/14/2009: Я могу утверждать, что использование переменной ThreadStatic небезопасно. Потоки WCF находятся в пуле потоков, и переменная ThreadStatic никогда не повторно инициализируется.

4b9b3361

Ответ 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.