(8) in the WCF WCF Session, management Detailed examples

I. Introduction

   From the front of several Bowen We know that, WCF is Microsoft-based SOA to establish a set of relatively independent application framework for exchanges (Communication) in a distributed environment, which implements the latest-based WS- * specifications. In accordance with the principles of SOA, relative alone business logic is encapsulated in the form of Service, the caller by calling a service message (Messaging) manner. For bearer service functions to achieve a business should have a context (Context) independence, meaning that operating configuration services (Operation) should not be bound to a specific calling context for any call, what kind of input would have What is the corresponding output. Because SOA's goal is to achieve a maximum reuse as much as possible, only with a Context-independent services in order to maximize reuse. That was understood from the perspective of software architecture, a module only as independent as possible, that is nothing to do with context, in order to be to maximize reuse. Software systems have been emphasizing low coupling is the truth.

  However, in some scenarios, but we want the system to create a Session for us to hold interactive and Client Service, such as the Session Asp.net mechanisms, like, WCF also provides support for the Session. Here's a look at WCF in particular to achieve the Session.

 

Two, WCF in Session Details

 2.1 Asp.net and WCF in the Session Session

  In WCF, Session Service Contract fall within the scope of, and achieved by SessionModel Service Contract parameter definition. WCF in the session has the following important features:

  • Client Session are displayed by the start end and termination.

  Come and services in WCF Client through a proxy object created interactive, with the support of the default Session, Session is specific proxy object and bind together when the Client through a proxy object method call to access the service, Session is initialized until the closing agent, Session were terminated. We can close in two ways Proxy: First call ICommunicationObject.Close method, the second is to call ClientBase <TChannel> .Close method. We can also be initialized by a method of operation of the service, or termination of Session, may be specified Session Initialization and Operation terminated by OperationContractAttribute of IsInitiating and IsTerminating parameters.

  • WCF during the session, the messaging is received it sends the order.

  • WCF does not state the relevant data to support the preservation of the Session.

  Mentioned Session, who did Asp.net development, Asp.net naturally think of the Session. They just called, are very different on the implementation mechanism. The Session Asp.net has the following characteristics:

  • Asp.net The Session is always initiated by the server, that is initialized on the server.

  • The Asp.net Session is no need, no guarantee that the request processing are ordered.

  • Asp.net is achieved through support for Session State data stored on the server in some way, for example, stored in the Web Server-side memory.

2.2 WCF service instance in management

  For the Client, it can not actually interact directly Service, it can only be created by the client Proxy Service and indirectly interact, but the real calling, but carried out by the service instance. We have to create the ultimate example of the process by calling the Client service is called activation, included in .NET Remoting Singleton pattern, SingleCall mode and client activation, WCF also has a similar service activation: monotonous Service (PerCall), Session service (PerSession) and singleton service (singleton).

  • Monotone Service (PerCall) : assign each client request a new service instance. .NET Remoting similar pattern in SingleCall

  • Session Service (PerSession) : during a session, sharing a service instance for each client request, similar to the .NET Remoting clients in active mode.

  • Singleton service (Singleton) : all client requests share the same service instance, similar to the .NET Remoting Singleton pattern. But its activation point to note: When the Host is carried out for the type of service, the corresponding service instance is created out, after all service calls handled by this service instance.

  WCF services in the default mode is activated PerSession, but not all Bingding support the Session, such as BasicHttpBinding not support Session. You can also make ServiceContract by the following method does not support Session.

[ServiceContract(SessionMode = SessionMode.NotAllowed)]

  The following describes the realization of these three ways of activation.

 

Third, to achieve the WCF instance management

   In WCF service is activated by default PerSession the way, here's a look at PerSession implementation. We still follow the previous several blog posts ways to achieve using PerSession way WCF service program.

  The first step: Nature is to achieve our WCF service contracts and contract implementation. Specific implementation code is shown below: 

// definition of a service contract
2 [the ServiceContract]
. 3 the ICalculator public interface
. 4 {
. 5 [the OperationContract (= the IsOneWay to true)]
. 6 void Increase ();
. 7
. 8 [the OperationContract]
. 9 GetResult int ();
10}
. 11
12 is // Contract implementation
13 is the CalculatorService public class: the ICalculator, the IDisposable
14 {
15 int _nCount Private = 0;
16
. 17 the CalculatorService public ()
18 is {
. 19 Console.WriteLine ( "Object has been CalulatorService Created");
20 is}
21 is
22 is to be seen // release profile service instance
23 is public void the Dispose ()
24 {
25 Console.WriteLine ( "Object has been CalulatorService the Disposed");
26 is}
27
28 #region ICalulator Members
29 public void Increase()
30 {
31 // 输出Session ID
32 Console.WriteLine("The Add method is invoked and the current session ID is: {0}", OperationContext.Current.SessionId);
33 this._nCount++;
34 }
35
36 public int GetResult()
37 {
38 Console.WriteLine("The GetResult method is invoked and the current session ID is: {0}", OperationContext.Current.SessionId);
39 return this._nCount;
40 }
41 #endregion
42 }

  In order to have an intuitive understanding of the services we create and release objects, I deliberately to implement the service class constructor and IDisposable interface, while the output current Session ID in each operation.

  The second step: implement the service host program. Is employed herein as a service host console program procedures, specific implementation code as follows:

1 // 服务宿主程序
2 class Program
3 {
4 static void Main(string[] args)
5 {
6 using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
7 {
8 host.Opened += delegate
9 {
10 Console.WriteLine("The Calculator Service has been started, begun to listen request...");
11 };
12
13 host.Open();
14 Console.ReadLine();
15 }
16 }
17 }

  Corresponding to the profile:

<!--服务宿主的配置文件-->
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name ="CalculatorBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="WCFContractAndService.CalculatorService" behaviorConfiguration="CalculatorBehavior">
<endpoint address="" binding="basicHttpBinding" contract="WCFContractAndService.ICalculator"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:9003/CalculatorPerSession"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

  The third step: to achieve over the service host program, then of course implement the client program to access the service operations. Here client console program is specific implementation code as follows:

1 // 客户端程序实现
2 class Program
3 {
4 static void Main(string[] args)
5 {
6 // Use ChannelFactory<ICalculator> to create WCF Service proxy
7 ChannelFactory<ICalculator> calculatorChannelFactory = new ChannelFactory<ICalculator>("HttpEndPoint");
8 Console.WriteLine("Create a calculator proxy :proxy1");
9 ICalculator proxy1 = calculatorChannelFactory.CreateChannel();
10 Console.WriteLine("Invoke proxy1.Increate() method");
11 proxy1.Increase();
12 Console.WriteLine("Invoke proxy1.Increate() method again");
13 proxy1.Increase();
14 Console.WriteLine("The result return via proxy1.GetResult() is: {0}", proxy1.GetResult());
15
16 Console.WriteLine("Create another calculator proxy: proxy2");
17 ICalculator proxy2 = calculatorChannelFactory.CreateChannel();
18 Console.WriteLine("Invoke proxy2.Increate() method");
19 proxy2.Increase();
20 Console.WriteLine("Invoke proxy2.Increate() method again");
21 proxy2.Increase();
22 Console.WriteLine("The result return via proxy2.GetResult() is: {0}", proxy2.GetResult());
23
24 Console.ReadLine();
25 }
26 }

  Corresponding to the client configuration files shown as follows:

<!--客户端配置文件-->
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:9003/CalculatorPerSession"
binding="basicHttpBinding"
contract="WCFContractAndService.ICalculator" name="HttpEndPoint"/>
</client>
</system.serviceModel>
</configuration>

  After the above three steps, we completed the WCF program PerSession way, here look at the results of the program.

  First, run the service with administrator privileges boarding after running the program is successful, you will see the screen shown below:

  Next, run the client to invoke the service operation, after running successfully, you will see the output situation of the service host and client output as shown below:

  As can be seen from the client's operating results, although we called twice Increase way to increase the value of _nCount, but the final result is still running 0. This result seems to run by default and we said before WCF Session Support contradiction, because if the default WCF PerSession way, then the service instance is bound and Proxy, Proxy when a call any time Session start operating from this Session Proxy and will have the same life cycle. According to the results of this description, the client runtime should be 2 instead of 0. Here, I can only say that operating results are not wrong, because there are pictures and the truth Well, that in the end is what causes the client to obtain _nCount value is 0 then? In fact, as already mentioned before, not all bindings are supported to achieve basicHttpBinding we use Session of the above procedures, but does not support Session basicHttpBinding way, it will create a WCF Service Instance uses PerCall way, so is created for each Proxy has three objects in the server, two is a call to Increase method will lead to the activation of a service instance, and the other is a call to GetResult method leads to activation of the service instance. Because it is PerCall way, so after each completed call, will be released on the service instance, so there are three rows corresponding service object release output. And the use of the Session does not support binding, the output is also Session ID is null. Therefore, the above procedure is actually realized PerCall WCF way.

  Now, run the above results is due to the use of unsupported Session basicHttpBinding due, take a look at using a Session of Binding support: wsHttpBinding how to look at the results, modification here is very simple, just need to host and client side configuration file to modify the binding type wsHttpBinding it.

<!--客户端配置文件-->
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:9003/CalculatorPerSession"
binding="wsHttpBinding"
contract="WCFContractAndService.ICalculator" name="HttpEndPoint"/>
</client>
</system.serviceModel>
</configuration>
<!--服务宿主的配置文件-->
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name ="CalculatorBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="WCFContractAndService.CalculatorService" behaviorConfiguration="CalculatorBehavior">
<endpoint address="" binding="wsHttpBinding" contract="WCFContractAndService.ICalculator"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:9003/CalculatorPerSession"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

  Now we run the above procedure to look at the results of this case, specific operational results as shown below:

  从上面的运行结果可以看出,此时两个Proxy的运行结果都是2,可以看出此时服务激活方式采用的是PerSession方式。此时对于服务端就只有两个服务实例被创建了,并且对于每个服务实例具有相同的Session ID。 另外由于Client的Proxy还依然存在,服务实例也不会被回收掉,从上面服务端运行的结果也可以证实这点,因为运行结果中没有对象呗Disposable的输出。你可以在客户端显式调用ICommunicationObject.Close方法来显式关闭掉Proxy,在客户端添加对Proxy的显示关闭代码,此时客户端的代码修改为如下所示:

1 // 客户端程序实现
2 class Program
3 {
4 static void Main(string[] args)
5 {
6 // Use ChannelFactory<ICalculator> to create WCF Service proxy
7 ChannelFactory<ICalculator> calculatorChannelFactory = new ChannelFactory<ICalculator>("HttpEndPoint");
8 Console.WriteLine("Create a calculator proxy :proxy1");
9 ICalculator proxy1 = calculatorChannelFactory.CreateChannel();
10 Console.WriteLine("Invoke proxy1.Increate() method");
11 proxy1.Increase();
12 Console.WriteLine("Invoke proxy1.Increate() method again");
13 proxy1.Increase();
14 Console.WriteLine("The result return via proxy1.GetResult() is: {0}", proxy1.GetResult());
15 (proxy1 as ICommunicationObject).Close(); // 显示关闭Proxy
16
17 Console.WriteLine("Create another calculator proxy: proxy2");
18 ICalculator proxy2 = calculatorChannelFactory.CreateChannel();
19 Console.WriteLine("Invoke proxy2.Increate() method");
20 proxy2.Increase();
21 Console.WriteLine("Invoke proxy2.Increate() method again");
22 proxy2.Increase();
23 Console.WriteLine("The result return via proxy2.GetResult() is: {0}", proxy2.GetResult());
24 (proxy2 as ICommunicationObject).Close();
25
26 Console.ReadLine();
27 }
28 }

  此时,服务对象的Dispose()方法将会调用,此时服务端的运行结果如下图所示:

  上面演示了默认支持Session的情况,下面我们修改服务契约使之不支持Session,此时只需要知道ServiceContract的SessionMode为NotAllowed即可。

[ServiceContract(SessionMode= SessionMode.NotAllowed)] // 是服务契约不支持Session
public interface ICalculator
{
[OperationContract(IsOneWay = true)]
void Increase();

[OperationContract]
int GetResult();
}

  此时,由于服务契约不支持Session,此时服务激活方式采用的仍然是PerCall。运行结果与前面采用不支持Session的绑定的运行结果一样,这里就不一一贴图了。

  除了通过显式修改ServiceContract的SessionMode来使服务契约支持或不支持Session外,还可以定制操作对Session的支持。定制操作对Session的支持可以通过OperationContract的IsInitiating和InTerminating属性设置。

1 // 服务契约的定义
2 [ServiceContract(SessionMode= SessionMode.Required)] // 显式使服务契约支持Session
3 public interface ICalculator
4 {
5 // IsInitiating:该值指示方法是否实现可在服务器上启动会话(如果存在会话)的操作,默认值是true
6 // IsTerminating:获取或设置一个值,该值指示服务操作在发送答复消息(如果存在)后,是否会导致服务器关闭会话,默认值是false
7 [OperationContract(IsOneWay = true, IsInitiating =true, IsTerminating=false )]
8 void Increase();
9
10 [OperationContract(IsInitiating = true, IsTerminating = true)]
11 int GetResult();
12 }

  在上面代码中,对两个操作都设置InInitiating的属性为true,意味着调用这两个操作都会启动会话,而把GetResult操作的IsTerminating设置为true,意味着调用完这个操作后,会导致服务关闭掉会话,因为在Session方式下,Proxy与Session有一致的生命周期,所以关闭Session也就是关闭proxy对象,所以如果后面再对proxy对象的任何一个方法进行调用将会导致异常,下面代码即演示了这种情况。

1 // 客户端程序实现
2 class Program
3 {
4 static void Main(string[] args)
5 {
6 // Use ChannelFactory<ICalculator> to create WCF Service proxy
7 ChannelFactory<ICalculator> calculatorChannelFactory = new ChannelFactory<ICalculator>("HttpEndPoint");
8 Console.WriteLine("Create a calculator proxy :proxy1");
9 ICalculator proxy1 = calculatorChannelFactory.CreateChannel();
10 Console.WriteLine("Invoke proxy1.Increate() method");
11 proxy1.Increase();
12 Console.WriteLine("Invoke proxy1.Increate() method again");
13 proxy1.Increase();
14 Console.WriteLine("The result return via proxy1.GetResult() is: {0}", proxy1.GetResult());
15 try
16 {
17 proxy1.Increase(); // session关闭后对proxy1.Increase方法调用将会导致异常
18 }
19 catch (Exception ex) // 异常捕获
20 {
21 Console.WriteLine("在Session关闭后调用Increase方法失败,错误信息为:{0}", ex.Message);
22 }

23
24 Console.WriteLine("Create another calculator proxy: proxy2");
25 ICalculator proxy2 = calculatorChannelFactory.CreateChannel();
26 Console.WriteLine("Invoke proxy2.Increate() method");
27 proxy2.Increase();
28 Console.WriteLine("Invoke proxy2.Increate() method again");
29 proxy2.Increase();
30 Console.WriteLine("The result return via proxy2.GetResult() is: {0}", proxy2.GetResult());
31
32 Console.ReadLine();
33 }
34 }

  此时运行结果也验证我们上面的分析,客户端和服务端的运行结果如下图所示:

  上面演示了PerSession和PerCall的两种服务对象激活方式,下面看看Single的激活方式运行的结果。首先通过ServiceBehavior的InstanceContextMode属性显式指定激活方式为Single,由于ServiceBehaviorAttribute特性只能应用于类上,所以把该特性应用于CalculatorService类上,此时服务实现的代码如下所示:

// 契约的实现
// ServiceBehavior属性只能应用在类上
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] // 显示指定PerSingle方式
public class CalculatorService : ICalculator, IDisposable
{
private int _nCount = 0;

public CalculatorService()
{
Console.WriteLine("CalulatorService object has been created");
}

// 为了看出服务实例的释放情况
public void Dispose()
{
Console.WriteLine("CalulatorService object has been Disposed");
}

#region ICalulator Members
public void Increase()
{
// 输出Session ID
Console.WriteLine("The Add method is invoked and the current session ID is: {0}", OperationContext.Current.SessionId);
this._nCount++;
}

public int GetResult()
{
Console.WriteLine("The GetResult method is invoked and the current session ID is: {0}", OperationContext.Current.SessionId);
return this._nCount;
}
#endregion
}

  此时运行服务宿主的输出结果如下图所示:

  从运行结果可以看出,对于Single方式,服务实例在服务类型被寄宿的时候就已经创建了,对于PerCall和PerSession方式而是在通过Proxy调用相应的服务操作之后,服务实例才开始创建的。下面运行客户端程序,你将看到如下图所示的运行结果:

  此时,第二个Proxy返回的结果是4而不是2,这是因为采用Single方式只存在一个服务实例,所有的调用状态都将保留,所以_nCount的值在原来的基础上继续累加。

 

四、总结

  到这里,本文的分享就结束了,本文主要分享了WCF中实例管理的实现。从WCF的实例实现可以看出,WCF实例实现是借鉴了.NET Remoting中实例实现,然后分别分享了服务实例三种激活方式在WCF中的实现,并通过对运行结果进行对比来让大家理解它们之间的区别。

 

转自:https://www.cnblogs.com/zhili/p/MSMQ.html,作者:Learning hard。

如有侵权,请联系我删除!

Guess you like

Origin blog.csdn.net/IT_0802/article/details/91502252