Сеансы, экземпляры и параллелизм
Под сеансом понимается скоррелированный набор всех сообщений, переданных между двумя конечными точками. Создание экземпляров означает управление временем жизни определенных пользователем объектов службы и связанных с ними объектов InstanceContext . Терминпараллелизм означает управление количеством потоков, одновременно выполняющихся в некотором контексте InstanceContext .
В этом разделе описаны эти параметры, способы их использования и различные взаимодействия между ними.
Сеансы
Если в контракте службы для свойства ServiceContractAttribute.SessionMode задано значение SessionMode.Required, такой контракт означает, что все вызовы (т. е. обмен сообщениями, на котором основана поддержка вызовов) должны быть частью одного диалога. Если в контракте указано, что сеансы для него разрешены, но не требуются, клиенты могут подключаться, создавая сеанс или не создавая его. Если сеанс завершен, но по этому же основанному на сеансе каналу отправляется сообщение, выдается исключение.
Сеансы WCF имеют следующие основные концептуальные функции:
Они явным образом инициируются и завершаются вызвавшим приложением.
Сообщения, доставленные в ходе сеанса, обрабатываются в порядке их получения.
Сеанс коррелирует группу сообщений в диалог. Такая корреляция является абстракцией. Например, один основанный на сеансах канал может коррелировать сообщения, основываясь на общем сетевом подключении, а другой - основываясь на общем теге в тексте сообщения. Функции, получаемые в результате сеанса, зависят от характера корреляции.
Общее хранилище данных не связано с сеансом WCF.
Если вы знакомы с классом System.Web.SessionState.HttpSessionState в ASP.NET приложениях и функциональных возможностях, которые он предоставляет, вы можете заметить следующие различия между этим типом сеансов и сеансов WCF:
ASP.NET сеансы всегда инициируются сервером.
ASP.NET сеансы неявно неупорядочены.
ASP.NET сеансы предоставляют общий механизм хранения данных в запросах.
Клиентские приложения и приложения служб взаимодействуют с сеансами разными способами. Клиентское приложение инициирует сеансы, а затем получает и обрабатывает сообщения, передаваемые в рамках этого сеанса. Приложения служб могут использовать сеансы как точки расширяемости для добавления дополнительного поведения. Это можно сделать, работая непосредственно с контекстом InstanceContext , или реализовав пользовательский поставщик контекста экземпляров.
Создание экземпляров
Поведение при создании экземпляров (задаваемое с помощью свойства ServiceBehaviorAttribute.InstanceContextMode ) управляет способом создания контекста InstanceContext в ответ на входящие сообщения. По умолчанию каждый контекст InstanceContext связан с одним определенным пользователем объектом службы, поэтому (по умолчанию) задание свойства InstanceContextMode также определяет создание экземпляров определенных пользователем объектов службы. Перечисление InstanceContextMode определяет режимы создания экземпляров.
Доступны следующие режимы создания экземпляров:
PerCall: для каждого запроса клиента создается новый контекст InstanceContext (и, следовательно, новый объект службы).
PerSession: новый контекст InstanceContext (и, следовательно, новый объект службы) создается для каждого нового сеанса клиента и существует в течение времени существования этого сеанса (для этого требуется привязка, поддерживающая сеансы).
Single: все запросы клиентов за время существования приложения обрабатываются одним контекстом InstanceContext (и, следовательно, одним объектом службы).
В следующем примере кода показано явное задание для режима InstanceContextMode значения PerSession в классе службы.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class CalculatorService : ICalculatorInstance
{
...
}
Свойство ServiceBehaviorAttribute.InstanceContextMode управляет частотой освобождения контекста InstanceContext , а свойства OperationBehaviorAttribute.ReleaseInstanceMode и ServiceBehaviorAttribute.ReleaseServiceInstanceOnTransactionComplete управляют частотой освобождения объекта службы.
Широко известные одноэлементные службы
Иногда бывает полезен один из вариантов объектов службы с одним экземпляром: можно самому создать объект службы, а затем создать основное приложение службы, используя этот объект. Для этого необходимо задать для свойства ServiceBehaviorAttribute.InstanceContextMode значение Single - в противном случае при открытии основного приложения службы возникает исключение.
Для создания такой службы используйте конструктор ServiceHost(Object, Uri[]) . Он обеспечивает альтернативу реализации пользовательского System.ServiceModel.Dispatcher.IInstanceContextInitializer , если требуется предоставить определенный экземпляр объекта для использования одноэлементной службой. Эту перегрузку можно использовать, если тип реализации службы сложно создать (например, если он не реализует общедоступный конструктор без параметров).
Обратите внимание, что при предоставлении объекта этому конструктору некоторые функции, связанные с поведением windows Communication Foundation (WCF), работают по-другому. Например, вызов InstanceContext.ReleaseServiceInstance не выполняет никаких действий, если предоставлен экземпляр одноэлементного объекта. Аналогичным образом пропускаются все другие механизмы освобождения экземпляров. Приложение ServiceHost всегда ведет себя таким образом, как если бы для свойства OperationBehaviorAttribute.ReleaseInstanceMode было задано значение ReleaseInstanceMode.None для всех операций.
Совместное использование объектов InstanceContext
Также для каждого сеансового канала или вызова можно задать объект InstanceContext , с которым он будет ассоциирован, самостоятельно назначив ассоциацию.
Параллелизм
Параллелизм означает управление количеством потоков, одновременно активных в некотором контексте InstanceContext . Управление осуществляется с помощью ServiceBehaviorAttribute.ConcurrencyMode с перечислением ConcurrencyMode .
Доступны следующие три режима параллелизма:
Single: в каждом контексте экземпляра одновременно допускается максимум один поток, обрабатывающий сообщения в контексте экземпляра. Другие потоки, которым требуется использовать этот же контекст экземпляра, должны оставаться блокированными, пока исходный поток не выйдет из контекста экземпляра.
Multiple: каждый экземпляр службы может иметь несколько потоков, параллельно обрабатывающих сообщения. Чтобы использовать этот режим параллелизма, реализация службы должна быть потокобезопасной.
Reentrant: каждый экземпляр службы одновременно обрабатывает одно сообщение, но принимает вызовы операций с повторным входом. Служба принимает эти вызовы только при вызове через клиентский объект WCF.
Примечание.
Проектирование и разработка кода, который может безопасно использовать несколько потоков, может оказаться непростым делом. Перед использованием значения Multiple или Reentrant убедитесь, что служба должным образом разработана для поддержки этих режимов. Дополнительные сведения см. в разделе ConcurrencyMode.
Использование параллелизма связано с режимом создания экземпляров. При PerCall инстантинге параллелизм не имеет значения, так как каждое сообщение обрабатывается новым InstanceContext и, следовательно, никогда не активен в одном потоке InstanceContext.
В приведенном ниже коде представлен пример задания для свойства ConcurrencyMode значения Multiple.
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
public class CalculatorService : ICalculatorConcurrency
{
...
}
Сеансы взаимодействуют с параметрами InstanceContext
Взаимодействие сеансов и контекстов InstanceContext зависит от значений перечисления SessionMode в контракте и свойства ServiceBehaviorAttribute.InstanceContextMode в реализации службы; сочетание этих значений определяет сопоставление каналов и конкретных объектов службы.
В приведенной ниже таблице показано, к какому результату приводит поддержка или отсутствие поддержки сеансов входящим каналом при заданном сочетании значений свойств ServiceContractAttribute.SessionMode и ServiceBehaviorAttribute.InstanceContextMode в службе.
Значение InstanceContextMode | Required | Allowed | NotAllowed |
---|---|---|---|
PerCall | — Поведение с сеансным каналом: сеанс и InstanceContext для каждого вызова. — поведение с бессерверным каналом: создается исключение. |
— Поведение с сеансным каналом: сеанс и InstanceContext для каждого вызова. — Поведение с каналом без сеансов: для InstanceContext каждого вызова. |
— Поведение с сеансовым каналом: создается исключение. — Поведение с каналом без сеансов: для InstanceContext каждого вызова. |
PerSession | — Поведение с сеансным каналом: сеанс и InstanceContext для каждого канала. — поведение с бессерверным каналом: создается исключение. |
— Поведение с сеансным каналом: сеанс и InstanceContext для каждого канала. — Поведение с каналом без сеансов: для InstanceContext каждого вызова. |
— Поведение с сеансовым каналом: создается исключение. — Поведение с каналом без сеансов: для InstanceContext каждого вызова. |
Одна | — Поведение с сеансным каналом: сеанс и один InstanceContext для всех вызовов. — поведение с бессерверным каналом: создается исключение. |
— Поведение с сеансовым каналом: сеанс и InstanceContext для созданного или пользовательского одноэлемента. — поведение с бессерверным каналом: InstanceContext для созданного или пользовательского одноэлемента. |
— Поведение с сеансовым каналом: создается исключение. — поведение с бессерверным каналом: InstanceContext для каждого созданного одноэлементного или для указанного пользователем одноэлемента. |