WCF CallBack
上一篇 / 下一篇 2008-04-07 20:31:20 / 个人分类:C#
Callback 机制又被称之为 "duplex call",说白了就是在原有基础上,为客户端也添加一个服务端点,让服务器能调用这个客户端 "服务",从而实现所谓的回调机制。也正因为如此,通讯 binding 就必须支持双向通讯能力(bidirectional-capable),通常我们会选择 WSDualHttpBinding、NetTcpBinding 以及 NetNamedPipeBinding。51Testing软件测试网y:^4g*{Z
nL
51Testing软件测试网F,}XWV5v0tV-Ic
接下来,我们回忆一下 Callback 的开发步骤。
"P\0_ vqE,CC!S])k0
Um'b:CU01. 创建服务契约。
M$^J d/z#s9K.V0
/zaH&[#@3Lz9dI9h R9B02. 定义回调接口。51Testing软件测试网(hd:MX.Q
51Testing软件测试网*q]E6C!}x
由于回调接口的实现类型在客户端执行,因此无需添加 ServiceContract。
Ly:n^Mf6`5LC0
3. 实现服务契约。
9i RH:E0U0
5ce B }#E Oo5m3vM0我们可以使用 "OperationContext.Current.GetCallbackChannel<T>()" 来回调客户端 "Callback"。
8}lOnu2Z/h8z A0
MmGw\Z['N)E W/Kd04. 创建 ServiceHost。51Testing软件测试网 q'z7_`%j9c8R
51Testing软件测试网 Zdk3DX$DEP1l
注意发布 Metadata。51Testing软件测试网c y0g:Yhn)M{
_&u,ZJC?,s.f05. 使用 Svcutil.exe 或 VS2005 创建客户端代理。
2xg)QG2O^e+H0
6. 创建客户端回调接口的实现类型。51Testing软件测试网U5lwkyW:^t7z
3@P \C*ka07. 为客户端自动生成的配置文件添加 clientBaseAddress。51Testing软件测试网 w/n P|Y3C @
Q&L(B]3S3X ]z)sKA0服务器通过这个地址调用客户端回调服务。在同一台机器上调试,注意使用一个不同的端口。51Testing软件测试网$q5Y`%{5G[)G.S
&E&xe_S"k08. 创建客户端调用代码。
&z{ V;g6Zab,n[ Z1K8t:S0
Gs'ku$a\g3B9A7i0运行,看看结果。你看到了什么?异常!!!51Testing软件测试网idnG,dnY,T"LO
j{tp9y@$A0死锁(deadlock)?没错,你找到了让本文继续下去的理由。51Testing软件测试网~VKu$I\Mh
1UgeI%xN2Ta8G.f(s}0在缺省情况下,服务实例是 single-threaded (ConcurrencyMode=ConcurrencyMode.Single) 的。当服务实例调用客户端回调服务时,方法被阻塞,直到客户端回调服务消息返回(reply message)。而问题是,Single模式不允许重入调用(reentrant calls),即便系统获得返回消息,也会因为无法重入调用方法解除阻塞而造成死锁。了解了这些背景,要解决这个死锁也很简单。51Testing软件测试网\_/A:YO4f"? Im&w
51Testing软件测试网e"l#Nj2^ ksp
方法1: 将回调接口方法设置为 "IsOneWay=true",这样就无需处理客户端返回消息。51Testing软件测试网,N;`oY2RZ~9u*V
8ndq9_6cTh]$Q0为回调接口方法添加 IsOneWay。
修改客户端代理文件,添加 IsOneWay,删除 ReplyAction。
*k~f8jr a0方法2: 修改服务契约的并发模式,改为 "ConcurrencyMode.Reentrant" 或 "ConcurrencyMode.Multiple"。51Testing软件测试网zs7x5`)W@X*H)q&b
#L0nQ8~u*Il r0和方法1不同,本方法无需对客户端做出修改。
pIJR+A&Eg0
无论使用哪种方法,修改后再次运行,我们得到了应有的结果。51Testing软件测试网^tXOy%i*y
i0^ vyc5o9`0回调机制可以用来实现类似事件通知等功能,但对于多数情况下,并不推荐使用。服务器要连接客户端实现回调,可能面临很多问题,诸如内部网络地址、防火墙等等,而且回调机制也让服务实例的生存期管理变得更复杂。
51Testing软件测试网F,}XWV5v0tV-Ic
接下来,我们回忆一下 Callback 的开发步骤。
"P\0_ vqE,CC!S])k0
Um'b:CU01. 创建服务契约。
M$^J d/z#s9K.V0
[ServiceContract(SessionMode=SessionMode.Required)]51Testing软件测试网l!Kks}K'z
public interface IService51Testing软件测试网Bze-o3j9wV0p
{
D.A)V#y_!h}b0 [OperationContract]51Testing软件测试网6u!Ji1a!]2fRM,Kh2X
void Test();
*y9R+V5^}r0}
public interface IService51Testing软件测试网Bze-o3j9wV0p
{
D.A)V#y_!h}b0 [OperationContract]51Testing软件测试网6u!Ji1a!]2fRM,Kh2X
void Test();
*y9R+V5^}r0}
/zaH&[#@3Lz9dI9h R9B02. 定义回调接口。51Testing软件测试网(hd:MX.Q
51Testing软件测试网*q]E6C!}x
由于回调接口的实现类型在客户端执行,因此无需添加 ServiceContract。
Ly:n^Mf6`5LC0
public interface ICallBack51Testing软件测试网{Ab3OR6Nn
{
\/A~'}/W`/[-^J4?0 [OperationContract]
bCv Ou$t X3I0 void Execute(DateTime d);51Testing软件测试网PSO,LhZPm.Q
}
51Testing软件测试网)OB ?]0oYC1w#XJ2L4jU,p{
\/A~'}/W`/[-^J4?0 [OperationContract]
bCv Ou$t X3I0 void Execute(DateTime d);51Testing软件测试网PSO,LhZPm.Q
}
3. 实现服务契约。
9i RH:E0U0
5ce B }#E Oo5m3vM0我们可以使用 "OperationContext.Current.GetCallbackChannel<T>()" 来回调客户端 "Callback"。
8}lOnu2Z/h8z A0
public class MyService : IService, IDisposable
@(~da1_xy0{51Testing软件测试网] FTkF#Xhf1x6c
public void Test()51Testing软件测试网8[1n0~:WU
{51Testing软件测试网nSJ/TLfgI7y"F
Console.WriteLine("Service Invoke CallBack...");51Testing软件测试网fQtRFQs6C
OperationContext.Current.GetCallbackChannel<ICallBack>().Execute(DateTime.Now);
icVb o~EK'm{0 }51Testing软件测试网8g1h2m z9w H&_O
51Testing软件测试网W;psA)q3g D!U k`m
public void Dispose()51Testing软件测试网5J/o$G B~Q4o
{51Testing软件测试网,]1aqj'Vy
Console.WriteLine("Dispose:{0}", DateTime.Now);
Y3sMs|4[7kY5i0 }
s0B3K*Z'N8MJ0}
@(~da1_xy0{51Testing软件测试网] FTkF#Xhf1x6c
public void Test()51Testing软件测试网8[1n0~:WU
{51Testing软件测试网nSJ/TLfgI7y"F
Console.WriteLine("Service Invoke CallBack...");51Testing软件测试网fQtRFQs6C
OperationContext.Current.GetCallbackChannel<ICallBack>().Execute(DateTime.Now);
icVb o~EK'm{0 }51Testing软件测试网8g1h2m z9w H&_O
51Testing软件测试网W;psA)q3g D!U k`m
public void Dispose()51Testing软件测试网5J/o$G B~Q4o
{51Testing软件测试网,]1aqj'Vy
Console.WriteLine("Dispose:{0}", DateTime.Now);
Y3sMs|4[7kY5i0 }
s0B3K*Z'N8MJ0}
MmGw\Z['N)E W/Kd04. 创建 ServiceHost。51Testing软件测试网 q'z7_`%j9c8R
51Testing软件测试网 Zdk3DX$DEP1l
注意发布 Metadata。51Testing软件测试网c y0g:Yhn)M{
ServiceHost host = new ServiceHost(typeof(MyService), new Uri("http://localhost:8080/myservice"));
\ E7`0Ju h!w0host.AddServiceEndpoint(typeof(IService), new WSDualHttpBinding(), "");
J2x"x V;~i"bW"bz051Testing软件测试网LQ&e,R&OvWd6}_
ServiceMetadatabehavīor metadata = new ServiceMetadatabehavīor();
T"Lf3vt |0metadata.HttpGetEnabled = true;
pYct2@0host.Descrīption.behavīors.Add(metadata);
}B$O:[.GJRV051Testing软件测试网+O`Ah{;c8pj L
host.Open();
\ E7`0Ju h!w0host.AddServiceEndpoint(typeof(IService), new WSDualHttpBinding(), "");
J2x"x V;~i"bW"bz051Testing软件测试网LQ&e,R&OvWd6}_
ServiceMetadatabehavīor metadata = new ServiceMetadatabehavīor();
T"Lf3vt |0metadata.HttpGetEnabled = true;
pYct2@0host.Descrīption.behavīors.Add(metadata);
}B$O:[.GJRV051Testing软件测试网+O`Ah{;c8pj L
host.Open();
_&u,ZJC?,s.f05. 使用 Svcutil.exe 或 VS2005 创建客户端代理。
2xg)QG2O^e+H0
//------------------------------------------------------------------------------51Testing软件测试网S}J3pG:crR
// <auto-generated>51Testing软件测试网HH&G A%~:J S8s
// 此代码由工具生成。51Testing软件测试网3YZ:?1i5w"D+vTnf5a
// 运行库版本:2.0.50727.4251Testing软件测试网'JA}%UX
//51Testing软件测试网5z&T/U/s&lC
// 对此文件的更改可能会导致不正确的行为,并且如果
p]0|Z-N&T:I2Bm~0// 重新生成代码,这些更改将会丢失。51Testing软件测试网s Y/}(a;R/TK#b
// </auto-generated>
-f&G\%Az^7bqR-x-D0//------------------------------------------------------------------------------51Testing软件测试网cs-njz
51Testing软件测试网jMDTM Bs#EO"i
namespace ConsoleApplication1.localhost51Testing软件测试网(aeb%F5|'U(o6k:M ?8L,E
{51Testing软件测试网X;U CuKIau
[GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
B"uaV3muE0 [ServiceContractAttribute(ConfigurationName = "ConsoleApplication1.localhost.IService", CallbackContract = typeof(IServiceCallback), SessionMode = SessionMode.Required)]51Testing软件测试网0V L$L i aA1a C
public interface IService51Testing软件测试网,OenVoy_hl M3c
{
7M)A6VZ y}A0 [OperationContractAttribute(Action = "http://.../IService/Test", ReplyAction = "http://.../IService/TestResponse")]51Testing软件测试网 b:{+j.@`]:qU*`
void Test();51Testing软件测试网|3Iub/ler
}
S%w@$bT f}0
`w0DhT0 [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
u9\ze X"U-u0u}8P0 public interface IServiceCallback
&PzZ9x7D p7j6`H0 {
_-d~$^1R/M0 [OperationContractAttribute(Action = "http://.../IService/Execute", ReplyAction = "http://.../IService/ExecuteResponse")]51Testing软件测试网Nw4b+d.ub9eA
void Execute(System.DateTime d);
B|;D,V|!~)P o0f}0 }51Testing软件测试网 B.h3QU!jW
51Testing软件测试网,wUk j+vQb9x
[GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]51Testing软件测试网%bB,t L/rjE$m
public interface IServiceChannel : IService, IClientChannel51Testing软件测试网"w"OR8|cJ\`!Q'I
{51Testing软件测试网#Cv;z:P.\@u
}
.b }V#pB4f\C{,U0
`WRS2{0 [DebuggerStepThroughAttribute()]51Testing软件测试网w~+R |M0R1TJ
[GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
(K e2F,w{%]G"u0 public partial class ServiceClient : DuplexClientBase<IService>, IService51Testing软件测试网Mg!ew9@
{
@+k7m4]:W-pw)ZG0 public ServiceClient(System.ServiceModel.InstanceContext callbackInstance)51Testing软件测试网,v#g,I5|A,JRn7^
: base(callbackInstance)
}+c)FKryT0 {51Testing软件测试网#]ew4us
}51Testing软件测试网3NF$v K)M kbG
*O4OXM:Y0 public void Test()51Testing软件测试网'@ Sd`^
{
3`/M^#r.wu/Sp,QV+w0 base.Channel.Test();
^F\El{ vu1Y8q0 }
{[ C_7B_%e"AI0 }
,]*W[A8e!D;Uy:S0}
51Testing软件测试网E]*o\Pt// <auto-generated>51Testing软件测试网HH&G A%~:J S8s
// 此代码由工具生成。51Testing软件测试网3YZ:?1i5w"D+vTnf5a
// 运行库版本:2.0.50727.4251Testing软件测试网'JA}%UX
//51Testing软件测试网5z&T/U/s&lC
// 对此文件的更改可能会导致不正确的行为,并且如果
p]0|Z-N&T:I2Bm~0// 重新生成代码,这些更改将会丢失。51Testing软件测试网s Y/}(a;R/TK#b
// </auto-generated>
-f&G\%Az^7bqR-x-D0//------------------------------------------------------------------------------51Testing软件测试网cs-njz
51Testing软件测试网jMDTM Bs#EO"i
namespace ConsoleApplication1.localhost51Testing软件测试网(aeb%F5|'U(o6k:M ?8L,E
{51Testing软件测试网X;U CuKIau
[GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
B"uaV3muE0 [ServiceContractAttribute(ConfigurationName = "ConsoleApplication1.localhost.IService", CallbackContract = typeof(IServiceCallback), SessionMode = SessionMode.Required)]51Testing软件测试网0V L$L i aA1a C
public interface IService51Testing软件测试网,OenVoy_hl M3c
{
7M)A6VZ y}A0 [OperationContractAttribute(Action = "http://.../IService/Test", ReplyAction = "http://.../IService/TestResponse")]51Testing软件测试网 b:{+j.@`]:qU*`
void Test();51Testing软件测试网|3Iub/ler
}
S%w@$bT f}0
`w0DhT0 [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
u9\ze X"U-u0u}8P0 public interface IServiceCallback
&PzZ9x7D p7j6`H0 {
_-d~$^1R/M0 [OperationContractAttribute(Action = "http://.../IService/Execute", ReplyAction = "http://.../IService/ExecuteResponse")]51Testing软件测试网Nw4b+d.ub9eA
void Execute(System.DateTime d);
B|;D,V|!~)P o0f}0 }51Testing软件测试网 B.h3QU!jW
51Testing软件测试网,wUk j+vQb9x
[GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]51Testing软件测试网%bB,t L/rjE$m
public interface IServiceChannel : IService, IClientChannel51Testing软件测试网"w"OR8|cJ\`!Q'I
{51Testing软件测试网#Cv;z:P.\@u
}
.b }V#pB4f\C{,U0
`WRS2{0 [DebuggerStepThroughAttribute()]51Testing软件测试网w~+R |M0R1TJ
[GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
(K e2F,w{%]G"u0 public partial class ServiceClient : DuplexClientBase<IService>, IService51Testing软件测试网Mg!ew9@
{
@+k7m4]:W-pw)ZG0 public ServiceClient(System.ServiceModel.InstanceContext callbackInstance)51Testing软件测试网,v#g,I5|A,JRn7^
: base(callbackInstance)
}+c)FKryT0 {51Testing软件测试网#]ew4us
}51Testing软件测试网3NF$v K)M kbG
*O4OXM:Y0 public void Test()51Testing软件测试网'@ Sd`^
{
3`/M^#r.wu/Sp,QV+w0 base.Channel.Test();
^F\El{ vu1Y8q0 }
{[ C_7B_%e"AI0 }
,]*W[A8e!D;Uy:S0}
6. 创建客户端回调接口的实现类型。51Testing软件测试网U5lwkyW:^t7z
class CallBack : IServiceCallback
t{2Q6Mu0{51Testing软件测试网 zK|0`l SW(D lL
public void Execute(DateTime d)
l2O X3D ?l"C]|0 {
1q\3IrHJeh&G0 Console.WriteLine("Client:{0}", d);
m6O@E Fm:D mB0 }51Testing软件测试网tW;xWM&?
}
t{2Q6Mu0{51Testing软件测试网 zK|0`l SW(D lL
public void Execute(DateTime d)
l2O X3D ?l"C]|0 {
1q\3IrHJeh&G0 Console.WriteLine("Client:{0}", d);
m6O@E Fm:D mB0 }51Testing软件测试网tW;xWM&?
}
3@P \C*ka07. 为客户端自动生成的配置文件添加 clientBaseAddress。51Testing软件测试网 w/n P|Y3C @
Q&L(B]3S3X ]z)sKA0服务器通过这个地址调用客户端回调服务。在同一台机器上调试,注意使用一个不同的端口。51Testing软件测试网$q5Y`%{5G[)G.S
<?xml version="1.0" encoding="utf-8" ?>
%\ Mc9B$U#@H:b$w0a9S2]0<configuration>51Testing软件测试网 cAn T#y;Q7V&\
<system.serviceModel>51Testing软件测试网Q+`#CT1gEsxU D
<bindings>51Testing软件测试网1[8nXCn%A
<wsDualHttpBinding>51Testing软件测试网0`~_Hh&i(` Z
<binding name="WSDualHttpBinding_IService" clientBaseAddress="http://localhost:8081/" >51Testing软件测试网MZ^`#zi5@N"Q
</binding>51Testing软件测试网P|O)q2R
</wsDualHttpBinding>
D#?z y\0 </bindings>51Testing软件测试网)WC;l5e:l%P|7Q(q
<client>51Testing软件测试网4qE`ij2b `
<endpoint address="http://localhost:8080/myservice" binding="wsDualHttpBinding"
t6Q-SJs$G_*iu0 bindingConfiguration="WSDualHttpBinding_IService" contract="ConsoleApplication1.localhost.IService"
#}@#S&p#]]0 name="WSDualHttpBinding_IService">51Testing软件测试网I(^CS._~7] n
<identity>
%y(e"OHoh}b0 <userPrincipalName value="HZH\Administrator" />
-X&Y$uf[)Z%w&jpv0 </identity>
)E&`@LmH&e0 </endpoint>
@[wXt | vXh0 </client>
nMx|)Gga,OD0 </system.serviceModel>
|6~ z+YpJ)?OX ~0</configuration>
%\ Mc9B$U#@H:b$w0a9S2]0<configuration>51Testing软件测试网 cAn T#y;Q7V&\
<system.serviceModel>51Testing软件测试网Q+`#CT1gEsxU D
<bindings>51Testing软件测试网1[8nXCn%A
<wsDualHttpBinding>51Testing软件测试网0`~_Hh&i(` Z
<binding name="WSDualHttpBinding_IService" clientBaseAddress="http://localhost:8081/" >51Testing软件测试网MZ^`#zi5@N"Q
</binding>51Testing软件测试网P|O)q2R
</wsDualHttpBinding>
D#?z y\0 </bindings>51Testing软件测试网)WC;l5e:l%P|7Q(q
<client>51Testing软件测试网4qE`ij2b `
<endpoint address="http://localhost:8080/myservice" binding="wsDualHttpBinding"
t6Q-SJs$G_*iu0 bindingConfiguration="WSDualHttpBinding_IService" contract="ConsoleApplication1.localhost.IService"
#}@#S&p#]]0 name="WSDualHttpBinding_IService">51Testing软件测试网I(^CS._~7] n
<identity>
%y(e"OHoh}b0 <userPrincipalName value="HZH\Administrator" />
-X&Y$uf[)Z%w&jpv0 </identity>
)E&`@LmH&e0 </endpoint>
@[wXt | vXh0 </client>
nMx|)Gga,OD0 </system.serviceModel>
|6~ z+YpJ)?OX ~0</configuration>
&E&xe_S"k08. 创建客户端调用代码。
&z{ V;g6Zab,n[ Z1K8t:S0
InstanceContext instance = new InstanceContext(new CallBack());51Testing软件测试网X;}zPTU
using (ServiceClient client = new ServiceClient(instance))51Testing软件测试网bcS;c P _
{
hC5o+G|0 client.Test();51Testing软件测试网SHI H#NiKNU
}
using (ServiceClient client = new ServiceClient(instance))51Testing软件测试网bcS;c P _
{
hC5o+G|0 client.Test();51Testing软件测试网SHI H#NiKNU
}
Gs'ku$a\g3B9A7i0运行,看看结果。你看到了什么?异常!!!51Testing软件测试网idnG,dnY,T"LO
用户代码未处理 System.InvalidOperationException
6I DC-Nx$M4s%]!H3l ~0 Message="This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on ServicebehavīorAttribute."
SWC4O?`0 Source="mscorlib"
+h6L'[$u v/e!~.C_0 StackTrace:
`*v5@!f.Z l0 Server stack trace: 51Testing软件测试网8w['v!h+US S\
在 System.ServiceModel.Channels.ServiceChannel.PrepareCall(ProxyOperationRuntime operation, Boolean oneway, ProxyRpc& rpc)
6I DC-Nx$M4s%]!H3l ~0 Message="This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on ServicebehavīorAttribute."
SWC4O?`0 Source="mscorlib"
+h6L'[$u v/e!~.C_0 StackTrace:
`*v5@!f.Z l0 Server stack trace: 51Testing软件测试网8w['v!h+US S\
在 System.ServiceModel.Channels.ServiceChannel.PrepareCall(ProxyOperationRuntime operation, Boolean oneway, ProxyRpc& rpc)
j{tp9y@$A0死锁(deadlock)?没错,你找到了让本文继续下去的理由。51Testing软件测试网~VKu$I\Mh
1UgeI%xN2Ta8G.f(s}0在缺省情况下,服务实例是 single-threaded (ConcurrencyMode=ConcurrencyMode.Single) 的。当服务实例调用客户端回调服务时,方法被阻塞,直到客户端回调服务消息返回(reply message)。而问题是,Single模式不允许重入调用(reentrant calls),即便系统获得返回消息,也会因为无法重入调用方法解除阻塞而造成死锁。了解了这些背景,要解决这个死锁也很简单。51Testing软件测试网\_/A:YO4f"? Im&w
51Testing软件测试网e"l#Nj2^ ksp
方法1: 将回调接口方法设置为 "IsOneWay=true",这样就无需处理客户端返回消息。51Testing软件测试网,N;`oY2RZ~9u*V
8ndq9_6cTh]$Q0为回调接口方法添加 IsOneWay。
public interface ICallBack51Testing软件测试网ya6nB#HY}$I.m%A
{51Testing软件测试网6h-|VA Hig#b
[OperationContract(IsOneWay=true)]51Testing软件测试网X7s2o ~5VR@
void Execute(DateTime d);51Testing软件测试网l Y#q Yy/?
}
51Testing软件测试网@Z,AfZc!w{51Testing软件测试网6h-|VA Hig#b
[OperationContract(IsOneWay=true)]51Testing软件测试网X7s2o ~5VR@
void Execute(DateTime d);51Testing软件测试网l Y#q Yy/?
}
修改客户端代理文件,添加 IsOneWay,删除 ReplyAction。
[GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]51Testing软件测试网V}1bFR:k QdY|}
public interface IServiceCallback51Testing软件测试网U-h0qc8h AI&|
{51Testing软件测试网@}R ZyY} t
[OperationContractAttribute(IsOneWay = true, Action = "http://.../IService/Execute")]51Testing软件测试网Py6|%P1B'aliF
void Execute(System.DateTime d);51Testing软件测试网Rp5P8fi(?
}
public interface IServiceCallback51Testing软件测试网U-h0qc8h AI&|
{51Testing软件测试网@}R ZyY} t
[OperationContractAttribute(IsOneWay = true, Action = "http://.../IService/Execute")]51Testing软件测试网Py6|%P1B'aliF
void Execute(System.DateTime d);51Testing软件测试网Rp5P8fi(?
}
*k~f8jr a0方法2: 修改服务契约的并发模式,改为 "ConcurrencyMode.Reentrant" 或 "ConcurrencyMode.Multiple"。51Testing软件测试网zs7x5`)W@X*H)q&b
#L0nQ8~u*Il r0和方法1不同,本方法无需对客户端做出修改。
pIJR+A&Eg0
[Servicebehavīor(ConcurrencyMode=ConcurrencyMode.Reentrant)]51Testing软件测试网A%qwR}"X#C0_
public class MyService : IService, IDisposable
.G u'xRWZ0{51Testing软件测试网P2_ ov r UB6_S#{ O
public void Test()
vrHP JC/]0 {
6L i1k$G9[%Q5Gg,v0 Console.WriteLine("Service Invoke CallBack...");51Testing软件测试网E9PV?U'e
OperationContext.Current.GetCallbackChannel<ICallBack>().Execute(DateTime.Now);
` S$j[?|bk4i0 }
ZS+fdq!i051Testing软件测试网ir9tmv2D%j
public void Dispose()51Testing软件测试网.PAZ;S U
{51Testing软件测试网{3R%jzg2C;zu3C
Console.WriteLine("Dispose:{0}", DateTime.Now);51Testing软件测试网0~GRQ"Y0i:`P
}
9RJL?aY(i9A0}
51Testing软件测试网/c!oBt{/Fpublic class MyService : IService, IDisposable
.G u'xRWZ0{51Testing软件测试网P2_ ov r UB6_S#{ O
public void Test()
vrHP JC/]0 {
6L i1k$G9[%Q5Gg,v0 Console.WriteLine("Service Invoke CallBack...");51Testing软件测试网E9PV?U'e
OperationContext.Current.GetCallbackChannel<ICallBack>().Execute(DateTime.Now);
` S$j[?|bk4i0 }
ZS+fdq!i051Testing软件测试网ir9tmv2D%j
public void Dispose()51Testing软件测试网.PAZ;S U
{51Testing软件测试网{3R%jzg2C;zu3C
Console.WriteLine("Dispose:{0}", DateTime.Now);51Testing软件测试网0~GRQ"Y0i:`P
}
9RJL?aY(i9A0}
无论使用哪种方法,修改后再次运行,我们得到了应有的结果。51Testing软件测试网^tXOy%i*y
i0^ vyc5o9`0回调机制可以用来实现类似事件通知等功能,但对于多数情况下,并不推荐使用。服务器要连接客户端实现回调,可能面临很多问题,诸如内部网络地址、防火墙等等,而且回调机制也让服务实例的生存期管理变得更复杂。
TAG:
标题搜索
日历
|
|||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
1 | 2 | 3 | 4 | 5 | 6 | ||||
7 | 8 | 9 | 10 | 11 | 12 | 13 | |||
14 | 15 | 16 | 17 | 18 | 19 | 20 | |||
21 | 22 | 23 | 24 | 25 | 26 | 27 | |||
28 | 29 | 30 |
我的存档
数据统计
- 访问量: 42204
- 日志数: 40
- 文件数: 1
- 建立时间: 2007-08-06
- 更新时间: 2014-06-10