使用会话Using Sessions

在 Windows Communication Foundation (WCF)应用程序中,会话将一组消息关联到会话中。In Windows Communication Foundation (WCF) applications, a session correlates a group of messages into a conversation. WCF 会话不同于 ASP.NET 应用程序中提供的会话对象,支持不同的行为,并且以不同的方式进行控制。WCF sessions are different than the session object available in ASP.NET applications, support different behaviors, and are controlled in different ways. 本主题介绍了在 WCF 应用程序中启用会话的功能以及如何使用这些功能。This topic describes the features that sessions enable in WCF applications and how to use them.

Windows Communication Foundation 应用程序中的会话Sessions in Windows Communication Foundation Applications

当某个服务协定指定它需要会话时,该协定会指定所有调用(即,支持调用的基础消息交换)必须是同一对话的一部分。When a service contract specifies that it requires a session, that contract is specifying that all calls (that is, the underlying message exchanges that support the calls) must be part of the same conversation. 如果某个协定指定它允许使用会话但不要求使用会话,则客户端可以进行连接,并选择建立会话或不建立会话。If a contract specifies that it allows sessions but does not require one, clients can connect and either establish a session or not establish a session. 如果会话结束,然后在同一个通道上发送消息,将会引发异常。If the session ends and a message is sent through the same channel an exception is thrown.

WCF 会话具有以下主要概念功能:WCF sessions have the following main conceptual features:

  • 它们由调用应用程序(WCF 客户端)显式启动和终止。They are explicitly initiated and terminated by the calling application (the WCF client).

  • 会话期间传递的消息按照接收消息的顺序进行处理。Messages delivered during a session are processed in the order in which they are received.

  • 会话将一组消息相互关联,从而形成对话。Sessions correlate a group of messages into a conversation. 可以有不同类型的关联。Different types of correlation are possible. 例如,一个基于会话的通道可能会根据共享网络连接来关联消息,而另一个基于会话的通道可能会根据消息正文中的共享标记来关联消息。For instance, one session-based channel may correlate messages based on a shared network connection while another session-based channel may correlate messages based on a shared tag in the message body. 可以从会话派生的功能取决于关联的性质。The features that can be derived from the session depend on the nature of the correlation.

  • 没有与 WCF 会话相关联的常规数据存储区。There is no general data store associated with a WCF session.

如果你熟悉 ASP.NET 应用程序中的 System.Web.SessionState.HttpSessionState 类以及它提供的功能,你可能会注意到该类型的会话和 WCF 会话之间存在以下差异:If you are familiar with the System.Web.SessionState.HttpSessionState class in ASP.NET applications and the functionality it provides, you might notice the following differences between that kind of session and WCF sessions:

  • ASP.NET 会话始终由服务器启动。ASP.NET sessions are always server-initiated.

  • ASP.NET 会话是隐式无序的。ASP.NET sessions are implicitly unordered.

  • ASP.NET 会话提供跨请求的常规数据存储机制。ASP.NET sessions provide a general data storage mechanism across requests.

本主题描述:This topic describes:

  • 在服务模型层中使用基于会话的绑定时的默认执行行为。The default execution behavior when using session-based bindings in the service model layer.

  • 基于 WCF 会话的、系统提供的绑定所提供的功能的类型。The types of features that the WCF session-based, system-provided bindings provide.

  • 如何创建声明会话要求的协定。How to create a contract that declares a session requirement.

  • 如何了解和控制会话的创建和终止以及会话与服务实例的关系。How to understand and control the creation and termination of the session and the relationship of the session to the service instance.

使用会话的默认执行行为Default Execution Behavior Using Sessions

尝试启动会话的绑定称为基于会话的 绑定。A binding that attempts to initiate a session is called a session-based binding. 通过将服务协定接口(或类)上的 ServiceContractAttribute.SessionMode 属性设置为 System.ServiceModel.SessionMode 枚举值之一,服务协定指定它们要求、允许或拒绝基于会话的绑定。Service contracts specify that they require, permit, or refuse session-based bindings by setting the ServiceContractAttribute.SessionMode property on the service contract interface (or class) to one of the System.ServiceModel.SessionMode enumeration values. 默认情况下,此属性的值为 Allowed,这意味着,如果客户端将基于会话的绑定与 WCF 服务实现一起使用,则该服务将建立并使用提供的会话。By default, the value of this property is Allowed, which means that if a client uses a session-based binding with a WCF service implementation, the service establishes and uses the session provided.

当 WCF 服务接受客户端会话时,默认情况下会启用以下功能:When a WCF service accepts a client session, the following features are enabled by default:

  1. WCF 客户端对象之间的所有调用都由同一个服务实例处理。All calls between a WCF client object are handled by the same service instance.

  2. 不同的基于会话的绑定还会提供其他功能。Different session-based bindings provide additional features.

系统提供的会话类型System-Provided Session Types

基于会话的绑定支持服务实例与特定会话的默认关联。A session-based binding supports the default association of a service instance with a particular session. 但是,除了启用前面介绍的基于会话的实例化控制之外,不同的基于会话的绑定还支持不同的功能。However, different session-based bindings support different features in addition to enabling the session-based instancing control previously described.

WCF 提供了以下类型的基于会话的应用程序行为:WCF provides the following types of session-based application behavior:

设置 SessionMode 属性并不指定协定需要的会话类型,而只是指定协定需要一个会话。Setting the SessionMode property does not specify the type of session the contract requires, only that it requires one.

创建一个需要会话的协定Creating a Contract That Requires a Session

创建需要会话的协定的原则是,必须在同一会话内执行服务协定声明的所有操作组,并且必须按顺序传递消息。Creating a contract that requires a session states that the group of operations that the service contract declares must all be executed within the same session and that messages must be delivered in order. 若要断言服务协定需要的会话支持级别,请将服务协定接口或类上的 ServiceContractAttribute.SessionMode 属性设置为 System.ServiceModel.SessionMode 枚举的值以指定协定是否:To assert the level of session support that a service contract requires, set the ServiceContractAttribute.SessionMode property on your service contract interface or class to the value of the System.ServiceModel.SessionMode enumeration to specify whether the contract:

  • 需要会话。Requires a session.

  • 允许客户端建立会话。Allows a client to establish a session.

  • 禁止会话。Prohibits a session.

但是,设置 SessionMode 属性并不指定协定需要的基于会话的行为的类型。Setting the SessionMode property does not, however, specify the type of session-based behavior the contract requires. 它指示 WCF 在运行时确认在运行时,为服务配置的绑定(为其创建信道)不会,也不会在实现服务时建立会话。It instructs WCF to confirm at runtime that the configured binding (which creates the communication channel) for the service does, does not, or can establish a session when implementing a service. 同样,绑定可以使用它选择的任何类型的基于会话的行为(安全、传输、可靠或某种组合)来满足该要求。Again, the binding can satisfy that requirement with any type of session-based behavior it chooses—security, transport, reliable, or some combination. 具体的行为取决于选择的 System.ServiceModel.SessionMode 值。The exact behavior depends on the System.ServiceModel.SessionMode value selected. 如果为服务配置的绑定不符合 SessionMode的值,则会引发异常。If the configured binding of the service does not conform to the value of SessionMode, an exception is thrown. 绑定及其创建的支持会话的通道可认为是基于会话的。Bindings and the channels they create that support sessions are said to be session-based.

下面的服务协定指定 ICalculatorSession 中的所有操作必须在会话中进行交换。The following service contract specifies that all operations in the ICalculatorSession must be exchanged within a session. 除了 Equals 方法之外,任何操作都不会向调用方返回值。None of the operations returns a value to the caller except the Equals method. 但是, Equals 方法不使用参数,因此,在已将其中的数据传递到其他操作的会话内部只可以返回非零值。However, the Equals method takes no parameters and, therefore, can only return a non-zero value inside a session in which data has already been passed to the other operations. 此协定需要会话正常工作。This contract requires a session to function properly. 如果没有与特定客户端相关联的会话,则服务实例无法知道此客户端前面已经发送了哪些数据。Without a session associated with a specific client, the service instance has no way of knowing what previous data this client has sent.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)]
public interface ICalculatorSession
{
    [OperationContract(IsOneWay=true)]
    void Clear();
    [OperationContract(IsOneWay = true)]
    void AddTo(double n);
    [OperationContract(IsOneWay = true)]
    void SubtractFrom(double n);
    [OperationContract(IsOneWay = true)]
    void MultiplyBy(double n);
    [OperationContract(IsOneWay = true)]
    void DivideBy(double n);
    [OperationContract]
    double Equals();
}
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples", SessionMode:=SessionMode.Required)> _
Public Interface ICalculatorSession

    <OperationContract(IsOneWay:=True)> _
    Sub Clear()
    <OperationContract(IsOneWay:=True)> _
    Sub AddTo(ByVal n As Double)
    <OperationContract(IsOneWay:=True)> _
    Sub SubtractFrom(ByVal n As Double)
    <OperationContract(IsOneWay:=True)> _
    Sub MultiplyBy(ByVal n As Double)
    <OperationContract(IsOneWay:=True)> _
    Sub DivideBy(ByVal n As Double)
    <OperationContract()> _
    Function Equal() As Double
End Interface

如果服务允许会话,则当客户端启动一个会话时将建立并使用该会话;否则,不建立会话。If a service allows a session, then a session is established and used if the client initiates one; otherwise, no session is established.

会话和服务实例Sessions and Service Instances

如果使用 WCF 中的默认实例化行为,则 WCF 客户端对象之间的所有调用都由同一服务实例处理。If you use the default instancing behavior in WCF, all calls between a WCF client object are handled by the same service instance. 因此,在应用程序级别上,可以将会话视为启用与本地调用行为相似的应用程序行为。Therefore, at the application level, you can think of a session as enabling application behavior similar to local call behavior. 例如,在创建本地对象时:For example, when you create a local object:

  • 调用构造函数。A constructor is called.

  • 对 WCF 客户端对象引用所做的所有后续调用都由同一个对象实例处理。All subsequent calls made to the WCF client object reference are processed by the same object instance.

  • 在销毁对象引用时调用析构函数。A destructor is called when the object reference is destroyed.

只要使用默认的服务实例行为,会话就会在客户端和服务之间启用一个相似的行为。Sessions enable a similar behavior between clients and services as long as the default service instance behavior is used. 如果服务协定需要或支持会话,则通过设置 IsInitiatingIsTerminating 属性,可以将一个或多个协定操作标记为启动或终止会话。If a service contract requires or supports sessions, one or more contract operations can be marked as initiating or terminating a session by setting the IsInitiating and IsTerminating properties.

启动操作 是必须作为新会话的第一个操作而调用的操作。Initiating operations are those that must be called as the first operation of a new session. 只有在已调用至少一个启动操作之后才可以调用非启动操作。Non-initiating operations can be called only after at least one initiating operation has been called. 因此,可以通过声明一个启动操作来为服务创建某种会话构造函数,启动操作应设计为从与服务实例的开始相对应的客户端接收输入。You can therefore create a kind of session constructor for your service by declaring initiating operations designed to take input from clients appropriate to the beginning of the service instance. (状态与会话相关联,但是,不与服务对象相关联。)(The state is associated with the session, however, and not the service object.)

相反,终止操作是必须作为现有会话中的最后消息而调用的操作。Terminating operations, conversely, are those that must be called as the last message in an existing session. 默认情况下,在关闭与服务相关联的会话之后,WCF 会回收服务对象及其上下文。In the default case, WCF recycles the service object and its context after the session with which the service was associated is closed. 因此,可以通过声明终止操作来创建某种析构函数,终止操作应设计为执行与服务实例的结束相对应的函数。You can, therefore, create a kind of destructor by declaring terminating operations designed to perform a function appropriate to the end of the service instance.

备注

尽管默认的行为与本地构造函数和析构函数有相似之处,但仅仅是相似。Although the default behavior bears a resemblance to local constructors and destructors, it is only a resemblance. 任何 WCF 服务操作都可以是启动或终止操作,也可以同时为两者。Any WCF service operation can be an initiating or terminating operation, or both at the same time. 另外,在默认情况下,可以按任意顺序调用启动操作任意次数;一旦建立会话并与实例相关联后,便不会再创建其他会话,除非显式控制服务实例的生存期(通过操作 System.ServiceModel.InstanceContext 对象)。In addition, in the default case, initiating operations can be called any number of times in any order; no additional sessions are created once the session is established and associated with an instance unless you explicitly control the lifetime of the service instance (by manipulating the System.ServiceModel.InstanceContext object). 最后,状态与会话相关联,而不是与服务对象相关联。Finally, the state is associated with the session and not the service object.

例如,在前面的示例中使用的 ICalculatorSession 协定需要 WCF 客户端对象首先调用 Clear 操作,然后再执行任何其他操作,并且与 WCF 客户端对象的会话应在调用 Equals 操作时终止。For example, the ICalculatorSession contract used in the preceding example requires that the WCF client object first call the Clear operation prior to any other operation and that the session with this WCF client object should terminate when it calls the Equals operation. 下面的代码示例演示强制执行这些要求的协定。The following code example shows a contract that enforces these requirements. 必须首先调用Clear 来启动会话,并且会话在调用 Equals 时结束。Clear must be called first to initiate a session, and that session ends when Equals is called.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)]
public interface ICalculatorSession
{
    [OperationContract(IsOneWay=true, IsInitiating=true, IsTerminating=false)]
    void Clear();
    [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
    void AddTo(double n);
    [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
    void SubtractFrom(double n);
    [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
    void MultiplyBy(double n);
    [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
    void DivideBy(double n);
    [OperationContract(IsInitiating = false, IsTerminating = true)]
    double Equals();
}
<ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples", SessionMode:=SessionMode.Required)> _
Public Interface ICalculatorSession

    <OperationContract(IsOneWay:=True, IsInitiating:=True, IsTerminating:=False)> _
    Sub Clear()
    <OperationContract(IsOneWay:=True, IsInitiating:=False, IsTerminating:=False)> _
    Sub AddTo(ByVal n As Double)
    <OperationContract(IsOneWay:=True, IsInitiating:=False, IsTerminating:=False)> _
    Sub SubtractFrom(ByVal n As Double)
    <OperationContract(IsOneWay:=True, IsInitiating:=False, IsTerminating:=False)> _
    Sub MultiplyBy(ByVal n As Double)
    <OperationContract(IsOneWay:=True, IsInitiating:=False, IsTerminating:=False)> _
    Sub DivideBy(ByVal n As Double)
    <OperationContract(IsInitiating:=False, IsTerminating:=True)> _
    Function Equal() As Double
End Interface

服务不会启动与客户端的会话。Services do not start sessions with clients. 在 WCF 客户端应用程序中,基于会话的通道的生存期和会话本身的生存期之间存在直接关系。In WCF client applications, a direct relationship exists between the lifetime of the session-based channel and the lifetime of the session itself. 因此,客户端可通过创建新的基于会话的通道来创建新会话,并通过正常关闭基于会话的通道来关闭现有的会话。As such, clients create new sessions by creating new session-based channels and tear down existing sessions by closing session-based channels gracefully. 客户端通过调用以下项目之一来启动与服务终结点的会话:A client starts a session with a service endpoint by calling one of the following:

通常,客户端通过调用以下项目之一来结束与服务终结点的会话:Typically a client ends a session with a service endpoint by calling one of the following:

有关示例,请参阅 How to: Create a Service That Requires Sessions 以及 Default Service BehaviorInstancing 示例。For examples, see How to: Create a Service That Requires Sessions as well as the Default Service Behavior and Instancing samples.

有关客户端和会话的详细信息,请参阅使用 WCF 客户端访问服务For more information about clients and sessions, see Accessing Services Using a WCF Client.

会话与 InstanceContext 设置进行交互Sessions Interact with InstanceContext Settings

协定中的 SessionMode 枚举与 ServiceBehaviorAttribute.InstanceContextMode 属性之间存在交互,该属性可控制通道和特定服务对象之间的关联。There is an interaction between the SessionMode enumeration in a contract and the ServiceBehaviorAttribute.InstanceContextMode property, which controls the association between channels and specific service objects. 有关详细信息,请参阅会话、实例化和并发For more information, see Sessions, Instancing, and Concurrency.

共享 InstanceContext 对象Sharing InstanceContext Objects

通过自己执行关联,您还可以控制将哪个基于会话的通道或调用与哪个 InstanceContext 对象相关联。You can also control which session-based channel or call is associated with which InstanceContext object by performing that association yourself.

会话和流Sessions and Streaming

当有大量数据要传输时,WCF 中的流传输模式是一种可用于在内存中缓冲和处理消息的默认行为的可行替代方法。When you have a large amount of data to transfer, the streaming transfer mode in WCF is a feasible alternative to the default behavior of buffering and processing messages in memory in their entirety. 在流与基于会话的绑定一起调用时可能会产生意外行为。You may get unexpected behavior when streaming calls with a session-based binding. 可通过单一通道(数据报通道)执行所有流调用,该通道不支持会话,即使将正在使用的绑定配置为使用会话也是如此。All streaming calls are made through a single channel (the datagram channel) that does not support sessions even if the binding being used is configured to use sessions. 如果多个客户端通过基于会话的绑定对相同的服务对象进行流调用,并且将服务对象的并发模式设置为 single,同时将其实例上下文模式设置为 PerSession,则所用的调用必须经过数据报通道,因此一次只处理一个调用。If multiple clients make streaming calls to the same service object over a session-based binding, and the service object's concurrency mode is set to single and its instance context mode is set to PerSession, all calls must go through the datagram channel and so only one call is processed at a time. 一个或多个客户端可能会超时。可以通过将服务对象的 InstanceContextMode 设置为 PerCall 或并发性到多个,来解决此问题。One or more clients may then time out. You can work around this issue by either setting the service object's InstanceContextMode to PerCall or Concurrency to multiple.

备注

MaxConcurrentSessions 在此情况下不会产生任何影响,因为只有一个“会话”可用。MaxConcurrentSessions have no effect in this case because there is only one "session" available.

请参阅See also