WCF - 服务实例管理模式
2009-01-17 15:30
387 查看
WCF 提供了三种实例上下文模式:PreCall、PreSession 以及 Single。开发人员通过
ServiceBehavior.InstanceContextMode 就可以很容易地控制服务对象的实例管理模式。而当 WCF
释放服务对象时,会检查该对象是否实现了 IDisposable 接口,并调用其 Dispose
方法,以便及时释放相关资源,同时也便于我们观察对象释放行为。
1. PreCall
在 PreCall 模式下,即便使用同一个代理对象,也会为每次调用创建一个服务实例。调用结束后,服务实例被立即释放(非垃圾回收)。对于不支持 Session 的 Binding,如 BasicHttpBinding,其缺省行为就是 PreCall。
[ServiceContract]
public interface IMyService
{
[OperationContract]
void Test();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyServie : IMyService, IDisposable
{
public MyServie()
{
Console.WriteLine("Constructor:{0}", this.GetHashCode());
}
[OperationBehavior]
public void Test()
{
Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
host.Open();
});
//-----------------------
IMyService channel = ChannelFactory<IMyService>.CreateChannel(new WSHttpBinding(),
new EndpointAddress("http://localhost:8080/MyService"));
using (channel as IDisposable)
{
channel.Test();
channel.Test();
}
}
}
输出:
Constructor:30136159
Test:urn:uuid:df549447-52ba-4c54-9432-31a7a533d9b4
Dispose
Constructor:41153804
Test:urn:uuid:df549447-52ba-4c54-9432-31a7a533d9b4
Dispose
2. PreSession
PreSession
模式需要绑定到支持 Session 的 Binding 对象。在客户端代理触发终止操作前,WCF 为每个客户端维持同一个服务对象,因此
PreSession 模式可用来保持调用状态。也正因为如此,PreSession
在大并发服务上使用时要非常小心,避免造成服务器过度负担。虽然支持 Session 的 Binding 对象缺省就会启用 PreSession
模式,但依然建议你强制指定 SessionMode.Required 和 InstanceContextMode.PerSession。
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IMyService
{
[OperationContract]
void Test();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyServie : IMyService, IDisposable
{
public MyServie()
{
Console.WriteLine("Constructor:{0}", this.GetHashCode());
}
[OperationBehavior]
public void Test()
{
Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
host.Open();
});
//-----------------------
IMyService channel = ChannelFactory<IMyService>.CreateChannel(new WSHttpBinding(),
new EndpointAddress("http://localhost:8080/MyService"));
using (channel as IDisposable)
{
channel.Test();
channel.Test();
}
}
}
输出:
Constructor:30136159
Test:urn:uuid:2f01b61d-40c6-4f1b-a4d6-4f4bc3e8847a
Test:urn:uuid:2f01b61d-40c6-4f1b-a4d6-4f4bc3e8847a
Dispose
3. Single
一如其名,服务器会在启动时,创建一个唯一(Singleton)的服务对象。这个对象为所有的客户端服务,并不会随客户端终止而释放。
[ServiceContract]
public interface IMyService
{
[OperationContract]
void Test();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyServie : IMyService, IDisposable
{
public MyServie()
{
Console.WriteLine("Constructor:{0}; {1}", DateTime.Now, this.GetHashCode());
}
[OperationBehavior]
public void Test()
{
Console.WriteLine("Test:{0}; {1}", DateTime.Now, OperationContext.Current.SessionId);
}
public void Dispose()
{
Console.WriteLine("Dispose:{0}", DateTime.Now);
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.Open();
});
//-----------------------
for (int i = 0; i < 2; i++)
{
IMyService channel = ChannelFactory<IMyService>.CreateChannel(new BasicHttpBinding(),
new EndpointAddress("http://localhost:8080/MyService"));
using (channel as IDisposable)
{
channel.Test();
channel.Test();
}
}
}
}
输出:
Constructor:2007-4-17 17:31:01; 63238509
Test:2007-4-17 17:31:03;
Test:2007-4-17 17:31:03;
Test:2007-4-17 17:31:03;
Test:2007-4-17 17:31:03;
还有另外一种方式来启动 Single ServiceHost。
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
MyServie service = new MyServie();
ServiceHost host = new ServiceHost(service, new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.Open();
});
此方式最大的好处是允许我们使用非默认构造,除此之外,和上面的例子并没有什么区别。
需要特别注意的是,缺省情况下,Single 会对服务方法进行并发控制。也就是说,多个客户端需要排队等待,直到排在前面的其他客户端调用完成后才能继续。看下面的例子。
[ServiceContract]
public interface IMyService
{
[OperationContract]
void Test();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyServie : IMyService, IDisposable
{
public MyServie()
{
Console.WriteLine("Constructor:{0}", this.GetHashCode());
}
[OperationBehavior]
public void Test()
{
Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
Thread.Sleep(2000);
Console.WriteLine("Test End:{0}", OperationContext.Current.SessionId);
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
host.Open();
});
//-----------------------
for (int i = 0; i < 2; i++)
{
new Thread(delegate()
{
IMyService channel = ChannelFactory<IMyService>.CreateChannel(new WSHttpBinding(),
new EndpointAddress("http://localhost:8080/MyService"));
using (channel as IDisposable)
{
while (true)
{
channel.Test();
}
}
}).Start();
}
}
}
输出:
Constructor:63238509
Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
...
我们可以通过修改并发模式(ConcurrencyMode)来改变这种行为,但需要自己维护多线程安全。
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
public class MyServie : IMyService, IDisposable
{
//...
}
输出:
Constructor:10261382
Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
...
ServiceBehavior.InstanceContextMode 就可以很容易地控制服务对象的实例管理模式。而当 WCF
释放服务对象时,会检查该对象是否实现了 IDisposable 接口,并调用其 Dispose
方法,以便及时释放相关资源,同时也便于我们观察对象释放行为。
1. PreCall
在 PreCall 模式下,即便使用同一个代理对象,也会为每次调用创建一个服务实例。调用结束后,服务实例被立即释放(非垃圾回收)。对于不支持 Session 的 Binding,如 BasicHttpBinding,其缺省行为就是 PreCall。
[ServiceContract]
public interface IMyService
{
[OperationContract]
void Test();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyServie : IMyService, IDisposable
{
public MyServie()
{
Console.WriteLine("Constructor:{0}", this.GetHashCode());
}
[OperationBehavior]
public void Test()
{
Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
host.Open();
});
//-----------------------
IMyService channel = ChannelFactory<IMyService>.CreateChannel(new WSHttpBinding(),
new EndpointAddress("http://localhost:8080/MyService"));
using (channel as IDisposable)
{
channel.Test();
channel.Test();
}
}
}
输出:
Constructor:30136159
Test:urn:uuid:df549447-52ba-4c54-9432-31a7a533d9b4
Dispose
Constructor:41153804
Test:urn:uuid:df549447-52ba-4c54-9432-31a7a533d9b4
Dispose
2. PreSession
PreSession
模式需要绑定到支持 Session 的 Binding 对象。在客户端代理触发终止操作前,WCF 为每个客户端维持同一个服务对象,因此
PreSession 模式可用来保持调用状态。也正因为如此,PreSession
在大并发服务上使用时要非常小心,避免造成服务器过度负担。虽然支持 Session 的 Binding 对象缺省就会启用 PreSession
模式,但依然建议你强制指定 SessionMode.Required 和 InstanceContextMode.PerSession。
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IMyService
{
[OperationContract]
void Test();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyServie : IMyService, IDisposable
{
public MyServie()
{
Console.WriteLine("Constructor:{0}", this.GetHashCode());
}
[OperationBehavior]
public void Test()
{
Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
host.Open();
});
//-----------------------
IMyService channel = ChannelFactory<IMyService>.CreateChannel(new WSHttpBinding(),
new EndpointAddress("http://localhost:8080/MyService"));
using (channel as IDisposable)
{
channel.Test();
channel.Test();
}
}
}
输出:
Constructor:30136159
Test:urn:uuid:2f01b61d-40c6-4f1b-a4d6-4f4bc3e8847a
Test:urn:uuid:2f01b61d-40c6-4f1b-a4d6-4f4bc3e8847a
Dispose
3. Single
一如其名,服务器会在启动时,创建一个唯一(Singleton)的服务对象。这个对象为所有的客户端服务,并不会随客户端终止而释放。
[ServiceContract]
public interface IMyService
{
[OperationContract]
void Test();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyServie : IMyService, IDisposable
{
public MyServie()
{
Console.WriteLine("Constructor:{0}; {1}", DateTime.Now, this.GetHashCode());
}
[OperationBehavior]
public void Test()
{
Console.WriteLine("Test:{0}; {1}", DateTime.Now, OperationContext.Current.SessionId);
}
public void Dispose()
{
Console.WriteLine("Dispose:{0}", DateTime.Now);
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.Open();
});
//-----------------------
for (int i = 0; i < 2; i++)
{
IMyService channel = ChannelFactory<IMyService>.CreateChannel(new BasicHttpBinding(),
new EndpointAddress("http://localhost:8080/MyService"));
using (channel as IDisposable)
{
channel.Test();
channel.Test();
}
}
}
}
输出:
Constructor:2007-4-17 17:31:01; 63238509
Test:2007-4-17 17:31:03;
Test:2007-4-17 17:31:03;
Test:2007-4-17 17:31:03;
Test:2007-4-17 17:31:03;
还有另外一种方式来启动 Single ServiceHost。
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
MyServie service = new MyServie();
ServiceHost host = new ServiceHost(service, new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
host.Open();
});
此方式最大的好处是允许我们使用非默认构造,除此之外,和上面的例子并没有什么区别。
需要特别注意的是,缺省情况下,Single 会对服务方法进行并发控制。也就是说,多个客户端需要排队等待,直到排在前面的其他客户端调用完成后才能继续。看下面的例子。
[ServiceContract]
public interface IMyService
{
[OperationContract]
void Test();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyServie : IMyService, IDisposable
{
public MyServie()
{
Console.WriteLine("Constructor:{0}", this.GetHashCode());
}
[OperationBehavior]
public void Test()
{
Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
Thread.Sleep(2000);
Console.WriteLine("Test End:{0}", OperationContext.Current.SessionId);
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
host.Open();
});
//-----------------------
for (int i = 0; i < 2; i++)
{
new Thread(delegate()
{
IMyService channel = ChannelFactory<IMyService>.CreateChannel(new WSHttpBinding(),
new EndpointAddress("http://localhost:8080/MyService"));
using (channel as IDisposable)
{
while (true)
{
channel.Test();
}
}
}).Start();
}
}
}
输出:
Constructor:63238509
Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
Test End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
...
我们可以通过修改并发模式(ConcurrencyMode)来改变这种行为,但需要自己维护多线程安全。
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
public class MyServie : IMyService, IDisposable
{
//...
}
输出:
Constructor:10261382
Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
Test End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
...
相关文章推荐
- WCF - 服务实例管理模式
- WCF - 服务实例管理模式
- WCF - 服务实例管理模式
- WCF学习--WCF服务实例模式
- WCF之服务实例管理
- 并发与实例上下文模式: WCF服务在不同实例上下文模式下具有怎样的并发表现
- WCF服务实例模式与并发、限流
- 跟我一起学WCF(8)——WCF中Session、实例管理详解
- WCF并发(Concurrency)的本质:同一个服务实例上下文(InstanceContext)同时处理多个服务调用请求
- 微软WCF应用高级进阶(分布式+异步调用+安全+通信模式)配销售管理平台项目实战
- WCF中实例模式(InstanceContextMode)与会话模式(SessionMode)
- WCF服务编程设计规范(3):服务契约、数据契约和实例管理设计规范
- WCF服务实例激活类型编程与开发(转)
- WCF技术剖析之五:利用ASP.NET兼容模式创建支持会话(Session)的WCF服务
- WCF服务操作的消息模式
- Zookeeper使用实例——服务节点管理
- 实现一个服务的基础结构和管理本地服务和WCF服务的管理器
- WCF 第五章 并发和实例(服务行为)
- WCF并发(Concurrency)的本质:同一个服务实例上下文(InstanceContext)同时处理多个服务调用请求(转)
- WCFRest实例:打造轻巧灵活的服务和Url