WCF之消息模式分为:
1、请求/答复模式
2、单向模式
3、双工模式
其中,请求/答复模式,在博文:
WCF 入门教程一(动手新建第一个WCF程序并部署)
WCF 入门教程二
中进行了详细介绍,此处将主要介绍:单向模式与双工模式。
1、首先,先创建一个WCF应用程序:
创建完成后,目录如下:
2、删除IService1.cs和Serivce1.svc,或者修改名称为:CalculateService.svc与ICalculateService.cs后,显示如下:
3、ICalculateService.cs文件内容如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Runtime.Serialization;
- using System.ServiceModel;
- using System.ServiceModel.Web;
- using System.Text;
-
- namespace WcfDuplexTest
- {
-
- [ServiceContract(Namespace = "http://blog.csdn.net/jiankunking",
- SessionMode = SessionMode.Required, CallbackContract = typeof(ICalculatorDuplexCallback))]
- public interface ICalculateService
- {
- [OperationContract(IsOneWay = true)]
- void GetData(string value);
-
- [OperationContract]
- CompositeType Clear();
-
-
- }
-
-
- public interface ICalculatorDuplexCallback
- {
- [OperationContract(IsOneWay = true)]
- void ComplexCalculate(string result);
- [OperationContract]
- string GetComplexCalculateResult(string value);
-
- }
-
-
- [DataContract]
- public class CompositeType
- {
- bool boolValue = true;
- string stringValue = "Hello ";
-
- [DataMember]
- public bool BoolValue
- {
- get { return boolValue; }
- set { boolValue = value; }
- }
-
- [DataMember]
- public string StringValue
- {
- get { return stringValue; }
- set { stringValue = value; }
- }
- }
- }
4、CalculateService.svc文件中的内容:
- <pre name="code" class="csharp">using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Runtime.Serialization;
- using System.ServiceModel;
- using System.ServiceModel.Web;
- using System.Text;
-
- namespace WcfDuplexTest
- {
-
-
- [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
- public class CalculateService : ICalculateService
- {
-
- ICalculatorDuplexCallback callback = null;
-
- public CalculateService()
- {
-
- callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
- }
-
- public void GetData(string value)
- {
-
- callback.ComplexCalculate(value);
- }
-
- public CompositeType Clear()
- {
- CompositeType composite = new CompositeType();
- composite.BoolValue = false;
-
- composite.StringValue = "测试回调客户端带有返回值的方法\r\n " + callback.GetComplexCalculateResult("客户端方法:GetComplexCalculateResult");
- return composite;
- }
-
- }
- }</pre>
5、修改Web.config的配置文件
- <?xml version="1.0" encoding="utf-8"?>
- <configuration>
-
- <system.web>
- <compilation debug="true" targetFramework="4.0" />
- </system.web>
- <system.serviceModel>
-
- <services>
- <service name="WcfDuplexTest.CalculateService">
- <endpoint address="" binding="wsDualHttpBinding" contract="WcfDuplexTest.ICalculateService">
- <identity>
- <dns value="localhost" />
- </identity>
- </endpoint>
- <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
- <host>
- <baseAddresses>
- <add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfDuplexTest/CalculateService/" />
- </baseAddresses>
- </host>
- </service>
- </services>
- <behaviors>
- <serviceBehaviors>
- <behavior>
-
- <serviceMetadata httpGetEnabled="true"/>
-
- <serviceDebug includeExceptionDetailInFaults="true"/>
- </behavior>
- </serviceBehaviors>
- </behaviors>
- <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
- </system.serviceModel>
- <system.webServer>
- <modules runAllManagedModulesForAllRequests="true"/>
- </system.webServer>
-
- </configuration>
6、新建winform客户端进行测试
7、添加服务端引用:
小注:
今天在vs2015中新建WCF类库,又能找到服务了
8、客户端代码如下:
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Linq;
- using System.Text;
- using System.Windows.Forms;
- using System.ServiceModel;
- using FormTest.CalculateService;
-
- namespace FormTest
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
- private void button1_Click(object sender, EventArgs e)
- {
-
- InstanceContext instanceContext = new InstanceContext(new CallbackHandler());
-
- CalculateService.CalculateServiceClient client = new CalculateService.CalculateServiceClient(instanceContext);
-
- client.GetData("客户端 传入 参数 测试 GetData");
- MessageBox.Show("GetData 调用完成!");
-
-
- CompositeType composite = client.Clear();
- MessageBox.Show("Clear 调用成功 \r\n" + composite.StringValue);
- }
- }
-
-
-
-
-
-
-
-
-
- [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
- public class CallbackHandler : CalculateService.ICalculateServiceCallback
- {
- public void ComplexCalculate(string result)
- {
- MessageBox.Show(result.ToString());
- }
-
- public string GetComplexCalculateResult(string result)
- {
- return result;
- }
- }
- }
小注:
在WCF回调中需要注意死锁问题
1、如果WCF中暴露出来的操作,没有返回值,则可以通过就是设置回调操作
IsOneWay=true,这样回调以后立即释放服务实例,不需要等待客户端响应消息,也可以避免死锁。
2、如果WCF中暴露出来的操作,有返回值,则需要通过,修改服务的ServiceBehavior的ConcurrencyMode为Reentrant或Multiple即可。
此时,服务端的死锁问题搞定了。
下面就需要考虑客户端的死锁问题了
客户端的死锁问题,通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为
死锁具体分析可以参考:点击打开链接
demo代码:点击打开链接
服务端死锁时的提示信息:
- 未处理 System.ServiceModel.FaultException`1
- HResult=-2146233087
- Message=此操作将死锁,因为在当前邮件完成处理以前无法收到答复。如果要允许无序的邮件处理,则在 ServiceBehaviorAttribute 上指定可重输入的或多个 ConcurrencyMode。
- Source=mscorlib
- Action=http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher/fault
- StackTrace:
- Server stack trace:
- 在 System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
- 在 System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
- 在 System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
- 在 System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
- 在 System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
- Exception rethrown at [0]:
- 在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
- 在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
- 在 FormTest.CalculateService.ICalculateService.GetData(Int32 value)
- 在 FormTest.CalculateService.CalculateServiceClient.GetData(Int32 value) 位置 E:\WorkSpace\WorkSpaceTest\WcfDuplexTest\FormTest\Service References\CalculateService\Reference.cs:行号 124
- 在 FormTest.Form1.button1_Click(Object sender, EventArgs e) 位置 E:\WorkSpace\WorkSpaceTest\WcfDuplexTest\FormTest\Form1.cs:行号 27
- 在 System.Windows.Forms.Control.OnClick(EventArgs e)
- 在 System.Windows.Forms.Button.OnClick(EventArgs e)
- 在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
- 在 System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
- 在 System.Windows.Forms.Control.WndProc(Message& m)
- 在 System.Windows.Forms.ButtonBase.WndProc(Message& m)
- 在 System.Windows.Forms.Button.WndProc(Message& m)
- 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
- 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
- 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
- 在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
- 在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
- 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
- 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
- 在 System.Windows.Forms.Application.Run(Form mainForm)
- 在 FormTest.Program.Main() 位置 E:\WorkSpace\WorkSpaceTest\WcfDuplexTest\FormTest\Program.cs:行号 18
- 在 System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
- 在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
- 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
- 在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
- 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
- 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
- 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
- 在 System.Threading.ThreadHelper.ThreadStart()
- InnerException:
小注:
WCF 双工模式
原文:http://www.cnblogs.com/Alex80/p/5133218.html