WCF wsHttpBinding с IIS

#multithreading #wcf #iis

#многопоточность #wcf #iis

Вопрос:

У меня есть набор служб WCF, настроенных с использованием wsHttpBinding с IIS, и я внедрил пользовательскую безопасность (с использованием заголовков сообщений) для определения пользователя, который делает запрос. Я всегда понимал, основываясь на нескольких годах опыта NetTcpBinding (используя службу Windows для размещения, а не IIS), что каждый запрос, полученный конечной точкой WCF, попадает в новый поток. Используя это предположение, мой пользовательский класс безопасности (который реализует IDispatchMessageInspector) устанавливает идентификатор потока на основе нахождения «токена» (идентификатора Guid) в заголовке сообщения следующим образом:

 public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel, InstanceContext instanceContext)
{
     string token = string.Empty;
     if (request.Headers.FindHeader("SecurityToken", Primitives.SerializationNamespace) > -1)
         token = request.Headers.GetHeader<string>("SecurityToken", Primitives.SerializationNamespace);

     if (!string.IsNullOrEmpty(token))
        Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(token, "AppName"), new string[] { "testrole" });
    else
        Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("guest", "AppName"), new string[] { });
     }

     return null;
 }
 

Однако при тестировании этого, и несмотря на то, что моя внутренняя переменная (которая содержит объект user) помечена как ThreadStatic, новые запросы, похоже, сохраняют идентификатор предыдущего вызывающего абонента.

Вот пример:

 [ThreadStatic]
private static User _CurrentUser = null;

internal static User CurrentUser
    {
        get
        {
            //this holds the value of the previous caller's identity still, even though the
            //thread's Identity.Name is now equal to the new caller's Guid
            if (_CurrentUser == null)
                    _CurrentUser = UserData.GetByToken(Thread.CurrentPrincipal.Identity.Name);


            return _CurrentUser;
        }
    }
 

Я также попытался пометить все реализации моей службы (непосредственно за файлом .svc) следующим атрибутом, но это ничего не изменило:

 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
 

Любые идеи о том, как я могу гарантировать, что каждый запрос находится в новом потоке? Или есть лучший способ сохранить / определить, кто пользователь, отправляющий запрос, без какого-либо возможного перекрытия?

Комментарии:

1. С какой стати ты играешь ThreadStatic ? Чего вы пытаетесь достичь?

Ответ №1:

Использование ThreadStatic переменной в среде, где у вас нет потоков под вашим контролем, — это путь к катастрофе. Как WCF (IIS и автономный), так и ASP.NET внутренне использовать пул потоков = каждый запрос обслуживается отдельным потоком, но эти потоки повторно используются для последующих запросов, и избежать этого невозможно.

Используйте пользовательское OperationContext расширение для хранения вашего пользователя вместо ThreadStatic переменной.

Комментарии:

1. Я думаю, что это именно то, что мне было нужно. Я протестирую немного больше, но, похоже, он работает отлично. Спасибо!