Почему InstanceContextMode.PerSession ведет себя как PerCall при использовании wsHttpBinding?

У меня есть служба WCF, используемая клиентом AJAX с использованием SOAP 1.2.

Web.config:

<endpoint address="" binding="wsHttpBinding" 
contract="WcfService1.IService1" bindingConfiguration="wsHttpBin">

<wsHttpBinding>
  <binding name="wsHttpBin">
    <security mode="None"/>          
  </binding>
</wsHttpBinding>

Из того, что я прочитал, я необходимо использовать <security mode="None"/>, поскольку служба, представленная с привязкой «wsHttpBinding», реализует WS-Security спецификаций веб-служб семейства WS- *. Поскольку привязка использует безопасность, запрос будет отклонен, поскольку AJAX не поддерживает контекст безопасности.

Поведение моей службы WCF определяется с помощью InstanceContextMode.PerSession:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, 
                 InstanceContextMode = InstanceContextMode.PerSession)]

но когда я его использую, служба ведет себя как PerCall, и каждый вызов запускает новый экземпляр WCF вместо использования текущего экземпляра.

Почему InstanceContextMode.PerSession ведет себя как PerCall при использовании wsHttpBinding?

Что я могу сделать?


person Dor Cohen    schedule 06.12.2012    source источник
comment
возможный дубликат: stackoverflow.com/questions/4767102/   -  person ErnieL    schedule 06.12.2012
comment
@ErnieL Спасибо, но использование ‹secureSession enabled = true /› для меня не вариант, так как он не будет работать с моим клиентом AJAX.   -  person Dor Cohen    schedule 07.12.2012
comment
Сама по себе wsHttpBinding не поддерживает сеансы.   -  person ErnieL    schedule 07.12.2012
comment
@ErnieL, так что я могу сделать, чтобы использовать Wcf из Ajax и использовать сеансы?   -  person Dor Cohen    schedule 07.12.2012


Ответы (2)


Сеансы при использовании через HTTP поддерживаются WCF только при использовании сеансов безопасности или надежных сеансов. Если вы не можете использовать ни то, ни другое, вам придется реализовать механизм сеанса самостоятельно. Если вы управляете как клиентской, так и серверной стороной, это будет довольно легко сделать. Вот как:

Создайте класс, содержащий все данные сеанса, которые вам нужно сохранить (назовем его SessionData), плюс дополнительный DateTime, указывающий, когда сеанс использовался в последний раз. Затем добавьте к своему классу обслуживания (или любому другому классу) static ConcurrentDictionary<string, SessionData>.

Когда клиент обращается к вашей службе, потребуйте от него передачи уникальной строки, идентифицирующей сеанс (она может быть случайным образом сгенерирована на стороне клиента). Всякий раз, когда клиент обращается к вам в службу, найдите строку сеанса в словаре и получите данные сеанса (и обновите их содержимое по мере необходимости). Если его нет, создайте новую запись в словаре. Кроме того, каждый раз, когда вы обращаетесь к объекту SessionData, обновляйте «последний использованный» DateTime до текущего времени. Фоновая задача должна периодически очищать старые сеансы, которые долгое время не использовались.

Вот и все - вы реализовали сеансы самостоятельно. Теперь вы можете использоватьInstanceContextMode.Single и не беспокоиться о том, что WCF правильно создает экземпляры вашего класса обслуживания за сеанс.

РЕДАКТИРОВАТЬ. Если вы пишете службу WCF с помощью .NET 4.5 и ваше веб-приложение предназначено только для современных браузеров, вы можете использовать NetHttpBinding на стороне сервера и WebSocket на стороне клиента. NetHttpBinding поддерживает сеанс (при указании SessionMode.Required).

person Allon Guralnek    schedule 09.12.2012
comment
+1: Не говорю, что ваше предложение изначально ошибочно, но для реализации механизма сеанса, готового к производству, есть целый ряд проблем, которые необходимо рассмотреть или решить: например, захват сеанса (случайный или преднамеренный), фактические тайм-ауты сеанса, которые делают смысл вашего приложения, устойчивость / устойчивость сеанса (данных) в случае перезапуска сервера (запланированный или незапланированный / сбой), одновременное изменение сеанса (данных) несколькими одновременными запросами и т. д. - person Christian.K; 09.12.2012
comment
@ Christian.K: Совершенно верно. Однако я не верю, что последние две вещи предоставляются WCF. Безопасность действительно является проблемой, которую следует учитывать, и что касается безопасности потоков, я предполагал, что каждый клиент будет генерировать уникальный сеансовый ключ и выполнять не более одного вызова службы в любой момент времени, но если это не так, безопасность потоков и о правильности также нужно позаботиться. - person Allon Guralnek; 09.12.2012
comment
@AllonGuralnek не использует InstanceContextMode. Single будет иметь большое влияние на мою производительность? - person Dor Cohen; 10.12.2012
comment
@Dor: Нет, если вы используете ConcurrencyMode.Multiple. В любом случае ваша служба должна использовать только данные из объекта SessionData, поскольку (если вы не используете Single) любые поля экземпляра являются для каждого вызова (поэтому они также могут быть локальными переменными / параметрами). Вот почему Single имеет смысл в вашем случае - все либо локально, либо SessionData, экземпляры вашего класса обслуживания бессмысленны. - person Allon Guralnek; 10.12.2012
comment
Так почему бы не использовать InstanceContextMode.PerCall? таким образом я могу использовать статические переменные, и он будет иметь лучшую производительность, как вы думаете? - person Dor Cohen; 10.12.2012
comment
Опять же, в вашем случае экземпляры не имеют значения. У вас не может быть никаких полей или свойств экземпляра. Так что у этого класса будут только методы, а создание экземпляров такого класса - пустая трата времени. В вашем случае на самом деле будет медленнее иметь что-либо, кроме Single. Также InstanceContextMode не имеет ничего общего с доступом к statics. - person Allon Guralnek; 10.12.2012

Эта ссылка дает вам почти все Об этом нужно знать (в общем, конечно).

Но если быть точным. Msdn говорит о сеансе WCF:

Они явно инициируются и завершаются вызывающим приложением.

Я должен сказать, что я не знаю ни о каком JS-коде / фреймворке, который позволил бы Вам хранить явно открытый канал связи WCF, чтобы поддерживать Ваш «сеанс» в живых. (Вы не предоставили свой клиентский код, поэтому я должен сделать некоторые предположения). Сеанс WCF не основан на файлах cookie. Он не работает "из коробки" из вашего браузера, как это было бы с веб-приложением ASP.NET.

Установка InstanceContextMode.PerSession делает вашу службу WCF «готовой к сеансу», но этого недостаточно для «принудительного» сеанса.

person Grzegorz W    schedule 09.12.2012
comment
Что вы имеете в виду, говоря о файлах cookie для ASP.NET? если я добавлю ‹serviceHostingEnvironment aspNetCompatibilityEnabled = true /›, могу ли я его использовать? можно ли готовое решение. - person Dor Cohen; 10.12.2012