博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WCF服务通信测试
阅读量:6564 次
发布时间:2019-06-24

本文共 18289 字,大约阅读时间需要 60 分钟。

知识需要反复咀嚼,常读常新,简单的WCF通信测试:basicHttpBinding(基本通信)\netTcpBinding(双工通信)\netMsmqBinding(消息队列),简单的测试Demo。

简单说一下代码结构,后续整理一下具体的实现逻辑,为什么这么处理。
1.WCFTest.DataContracts类库代码(基础数据契约类库)
<1>.OrderItem.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using System.Runtime.Serialization;using System.Threading.Tasks;namespace WCFTest.DataContracts{    [DataContract]    public class OrderItem    {        [DataMember]        public Guid ProductID;        [DataMember]        public string ProductName;        [DataMember]        public decimal UnitPrice;        [DataMember]        public int Quantity;    }}
View Code

<2>.Order.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using System.Runtime.Serialization;using System.Threading.Tasks;namespace WCFTest.DataContracts{    [DataContract]    [KnownType(typeof(OrderItem))]    public class Order    {        [DataMember]        public Guid OrderNo;        [DataMember]        public DateTime OrderDate;        [DataMember]        public Guid SupplierID;        [DataMember]        public string SupplierName;        [DataMember]        public List
OrderItems=new List
(); //如果不这样的构建方式,使用请使用get;set;,并且Order构造函数实例化(new)这个集合 ///
/// 订单信息描述 /// ///
public override string ToString() { StringBuilder strBuilder = new StringBuilder(); strBuilder.AppendLine("General Information:\n\t"); strBuilder.AppendLine(string.Format("Order No:{0}", OrderNo)); strBuilder.AppendLine(string.Format("Order Date:{0}", OrderDate.ToShortDateString())); strBuilder.AppendLine(string.Format("SupplierID:{0}", SupplierID)); strBuilder.AppendLine(string.Format("SupplierName:{0}", SupplierName)); strBuilder.AppendLine("\nProducts:"); foreach (OrderItem order in OrderItems) { strBuilder.AppendLine(string.Format("ProductID:{0}", order.ProductID)); strBuilder.AppendLine(string.Format("ProductName:{0}", order.ProductName)); strBuilder.AppendLine(string.Format("UnitPrice:{0}", order.UnitPrice)); strBuilder.AppendLine(string.Format("Quantity:{0}", order.Quantity)); } return strBuilder.ToString(); } }}
View Code

2.WCFTest.Contracts类库代码(服务端和客户端通信契约接口)

<1>.ICalculator.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using System.Threading.Tasks;namespace WCFTest.Contracts{    [ServiceContract]    public interface ICalculator    {        [OperationContract]        double Add(double numA, double numB);        [OperationContract]        double Sub(double numA, double numB);        [OperationContract]        double Multiply(double numA, double numB);        [OperationContract]        double Divide(double numA, double numB);    }}
View Code

<2>.IDuplexCallBack.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using System.Threading.Tasks;namespace WCFTest.Contracts{    public interface IDuplexCallBack    {        [OperationContract(IsOneWay = true)]        void DisplayResult(double result);    }}
View Code

<3>.IDuplexContract.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using System.Threading.Tasks;namespace WCFTest.Contracts{    #region BaseInfoKnown    /*     * 如何理解双工通信?     * 请求过程中的回调,双工消息交换模式的表现形式,客户端调用服务的时候,附加上一个回调对象;     * 服务端在处理该请求中,通过客户端附加的回调对象(调用回调服务的代理对象)回调客户端操作(该操作在客户端执行)。     * 整个消息交换过程由两个基本的消息交换,其一客户端正常的服务请求,其二服务端对客户端的回调。两者可以采用请求-回复模式,也可以采用单向(One-way)的MEP进行消息交换。     *      * 如何模拟测试?     * 本例采用另外一种截然不同的方式调用服务并进行结果的输出:     * 通过单向(One-way)的模式调用CalculuateService(也就是客户端不可能通过回复消息得到计算结果),服务端在完成运算结果后,通过回调(Callback)的方式在客户端将计算结果打印出来。     */    #endregion    [ServiceContract(CallbackContract = typeof(IDuplexCallBack))]    public interface IDuplexContract    {        [OperationContract(IsOneWay = true)]//单向(只是客户端请求,未做响应[回复])        void Add(double numA, double numB);    }}
View Code

<4>.IMSMQContract.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using WCFTest.DataContracts;using System.Threading.Tasks;namespace WCFTest.Contracts{    #region BaseInfoKnown    /*     * 比如,在Intranet内,通过TCP进行高效的数据通信;而在Internet内,通常使用Http进行跨平台数据交换。     * 这些通信的特点都是基于Connection的,也就是说,交互双方必须有一个可用的Connection存在于他们之间。     * 而在某些时候比如用户拨号、便携式计算机的用户,不能保证需要Server时有一个可用的Connection。这时候,基于Messaging Queue尤为重要。     * MSMQ的好处:     * <1>.MSMQ是基于Disconnection。这种通信方式为离线工作成为了可能。     * <2>.MSMQ天生是One-way、异步的。对于用户的请求,Server端无需立即相应,也就是说,Server对数据的处理无需和Client的数据发送进行同步。这样可以避免峰值负载。     * <3>.MSMQ能够提供高质量的Reliable Messaging。异步通信,无法获知Message是否抵达Server端,也无法获知Server端的执行结果和出错信息。     * MSMQ提供Reliable Messaging的机制:     * a.超时机制(Timeout)     * b.确认机制(Acknowledgement)     * c.日志机制(Journaling):消息被发送或接收后,被Copy一份。     * d.死信队列(Dead letter Queue):保存发送失败的message。      *      * 在WCF中,MSMQ的数据传输功能被封装在一个Binding中,提供WCF Endpoint之间、以及Endpoint和现有的基于MSMQ的Application进行通信的实现。     * 提供两种不同的built-in binding:     * <1>.NetMsmqBinding:从提供的功能和使用方式上看,和一般的使用的binding一样,所不同的是,它提供的是基于MSMQ的Reliable Messaging。变成模式和一般的binding完全一样。     * <2>.MsmqIntergrationBinding:主要用于将我们的WCF Application和现有的基于MSMQ的Application集成的情况。     * 实现了WCF Endpoint和某个Message Queue进行数据的通信,具体来说,就是实现了单一的向某个Message Queue发送Message,和从某个Message Queue中接收Message的功能。     *      * MSMQ则有效地提供了这样的机制:Server端建立一个Message Queue来接收来个客户的订单,客户端通过向该Message Queue发送承载了订单数据的Message实现订单的递交。     * 如果客户在离线的情况,仍然可以通过客户端进行订单递交的操作,存储着订单数据的Message会被暂保在本地的Message Queue中,一旦客户联机,MSMQ将Message从中取出,发送到真正的接收方,这个动作对于用户的透明的。     */    #endregion    [ServiceContract]    [ServiceKnownType(typeof(Order))]    public interface IMSMQContract    {        [OperationContract(IsOneWay = true)]        void SubmitOrder(Order order);    }}
View Code

3.WCFTest.Services类库代码(契约接口业务功能实现)

<1>.CalculatorService.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using WCFTest.Contracts;using System.Threading.Tasks;namespace WCFTest.Services{    public class CalculatorService : ICalculator    {        public double Add(double numA, double numB)        {            return numA + numB;        }        public double Sub(double numA, double numB)        {            return numA - numB;        }        public double Multiply(double numA, double numB)        {            return numA * numB;        }        public double Divide(double numA, double numB)        {            if (numB != 0)            {                return numA / numB;            }            return 0;        }    }}
View Code

<2>.DuplexService.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using WCFTest.Contracts;using System.Threading.Tasks;namespace WCFTest.Services{    ///     /// 在Server端,通过OperationContext.Current.GetCallbackChannel
() /// 获得Client指定的CallbackContent Instance,进行Client调用Opertion ///
public class DuplexService : IDuplexContract { public void Add(double numA, double numB) { double result = numA + numB; IDuplexCallBack duplexCall = OperationContext.Current.GetCallbackChannel
(); duplexCall.DisplayResult(result); } }}
View Code

<3>.MSMQService.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using WCFTest.Contracts;using WCFTest.DataContracts;using System.Threading.Tasks;namespace WCFTest.Services{    public class MSMQService:IMSMQContract    {        //设定服务端请求行为:需求事务操作\自动完成事务        [OperationBehavior(TransactionScopeRequired=true,TransactionAutoComplete=true)]        public void SubmitOrder(WCFTest.DataContracts.Order order)        {            //将Order数据保存到数据库            SaveData.SaveOrder(order);            Console.WriteLine("Receive An Order:");            Console.WriteLine(order.ToString()); //服务端输出的信息,在Host监听器可以看到,服务是不可见的        }    }}
View Code

<4>.SaveData.cs

using System;using System.Collections.Generic;using System.Linq;using System.Text;using WCFTest.DataContracts;using System.Threading.Tasks;namespace WCFTest.Services{    public class SaveData    {        private static Dictionary
dicOrder = new Dictionary
(); public static void SaveOrder(Order order) { if (!dicOrder.Keys.Contains(order.OrderNo)) { dicOrder.Add(order.OrderNo, order); } } public static Order GetOrder(Guid orderNo) { Order order = new Order(); if (dicOrder.Keys.Contains(orderNo)) { order=dicOrder[orderNo]; } return order; } }}
View Code

4.WCFTest.Hots 控制台程序代码(多服务宿主程序)

<1>.App.config (服务端和客户端通信配置ABC)

<2>.Program.cs  (多服务宿主启用监听)

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using WCFTest.Services;using System.Configuration;using System.Threading.Tasks;using System.Xml;using System.Configuration;using System.Messaging;namespace WCFTest.Hots{    ///     /// 如何可以按需开启不同的Host    ///     class Program    {        static void Main(string[] args)        {            #region 单Host调用测试            ////计算服务Host            //CalculatorHosts();            ////双工通信服务Host            //DuplexHost();            #endregion            #region 多Host调用测试            Dictionary
dicHosts = new Dictionary
(); dicHosts.Add("CalculatorHost", new ServiceHost(typeof(Services.CalculatorService))); dicHosts.Add("DuplexHost", new ServiceHost(typeof(Services.DuplexService))); dicHosts.Add("MSMQHost", new ServiceHost(typeof(Services.MSMQService))); foreach (KeyValuePair
keyPair in dicHosts) { if (keyPair.Key.Contains("MSMQHost"))//MSMQHost的附加逻辑 { //MSMQ队列不存在,或您没有足够的权限执行该操作异常:因为是这里的路径\Host\Client的地址路径问题 string strMSMQPath = @".\Private$\Orders"; //string strMSMQPath = ConfigurationManager.AppSettings["MSMQPath"]; if (!MessageQueue.Exists(strMSMQPath)) { //创建一个MessageQueue,参数说明:MSMQ的位置,支持事务队列 MessageQueue.Create(strMSMQPath,true); } } keyPair.Value.Opened += delegate { Console.WriteLine(keyPair.Key + " Host Has Been Listening......."); }; keyPair.Value.Open(); } Console.WriteLine("\nPlease Enter Any Key To Abort All Hosts:"); Console.ReadLine(); foreach (KeyValuePair
keyPair in dicHosts) { keyPair.Value.Abort(); keyPair.Value.Close(); Console.WriteLine(keyPair.Key + " Host Has Been Stoped!"); } #endregion Console.WriteLine("\nPlease Enter Any Key Exit:"); Console.Read(); } ///
/// 计算服务Host /// private static void CalculatorHosts() { using (ServiceHost host = new ServiceHost(typeof(Services.CalculatorService))) { host.Opened += delegate { Console.WriteLine("Host Has Been Opened! Please Enter Any Key To Abort This Host:"); Console.ReadKey(); host.Abort(); host.Close(); Console.WriteLine("Host Has Been Stoped!"); }; host.Open(); } } ///
/// 双工通信服务Host /// private static void DuplexHost() { using (ServiceHost duplexHost = new ServiceHost(typeof(Services.DuplexService))) { duplexHost.Opened += delegate { Console.WriteLine("Duplex Host Has Been Listening....! Please Enter Any Key To Abort This Host:"); Console.ReadLine(); duplexHost.Abort(); duplexHost.Close(); Console.WriteLine("Duplex Host Has Been Stoped!"); }; duplexHost.Open(); } } }}

5.WCFTravelReview 控制台程序代码 (客户端调用)

<1>.App.config (客户端和服务端通信配置ABC)

<2>.DuplexCallBackClient.cs (双工通信回调接口实现)

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using WCFTest.Contracts;using System.Threading.Tasks;namespace WCFTravelReview{    //客户端的回调类,显示计算结果,实现ICallback接口    public class DuplexCallBackClient : IDuplexCallBack    {        public void DisplayResult(double result)        {            Console.WriteLine("The Result is {0}", result.ToString());        }    }}

<3>.Program.cs (测试客户端调用)

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using WCFTest.Contracts;using WCFTest.DataContracts;using System.Transactions;using System.Threading.Tasks;namespace WCFTravelReview{    class Program    {        static void Main(string[] args)        {            //计算服务Client            CalculatorClient();            //双工服务Client            DuplexClient();            //消息队列            MSMQClient();            Console.Read();        }        ///         /// 计算服务Client        ///         private static void CalculatorClient()        {            using (ChannelFactory
calculatorChannel = new ChannelFactory
("CalculatorClient")) { ICalculator proxy = calculatorChannel.CreateChannel(); using (proxy as IDisposable) { Console.WriteLine("计算通信测试:"); Console.WriteLine("请输入数字A:"); double numA = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("请输入数字B:"); double numB = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("WCF调用服务计算:"); Console.WriteLine("{0}+{1}={2}", numA, numB, proxy.Add(numA, numB)); Console.WriteLine("{0}-{1}={2}", numA, numB, proxy.Sub(numA, numB)); Console.WriteLine("{0}*{1}={2}", numA, numB, proxy.Multiply(numA, numB)); Console.WriteLine("{0}/{1}={2}", numA, numB, proxy.Divide(numA, numB)); } } } ///
/// 双工服务Client /// private static void DuplexClient() { #region TCP/IP DuplexInfo Known /* * 对于双工通信 * 对于TCP/IP簇中的传输层协议TCP,它则是一个基于Connection的协议,在正式进行数据传输之前, * 必须要在Client和Server之后建立一个Connection,Connection的建立通过经典的“3次握手”。 * TCP具有Duplex的特性,就是说Connection被创建之后,从Client到Server,从Server到Client的数据传递可以利用同一个Connection来实现。 * 对于WCF的双向通信,Client调用Service,Service Callback Client使用的都是同一个Channel。 */ #endregion InstanceContext instanceContext = new InstanceContext(new DuplexCallBackClient()); using (DuplexChannelFactory
duplexChannel = new DuplexChannelFactory
(instanceContext, "DuplexClient")) { IDuplexContract proxy = duplexChannel.CreateChannel(); using (proxy as IDisposable) { Console.WriteLine("\n双工通信测试:"); Console.WriteLine("请输入数字A:"); double numA = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("请输入数字B:"); double numB = Convert.ToDouble(Console.ReadLine()); Console.WriteLine("WCF调用双工通信计算:"); proxy.Add(numA, numB); } } } ///
/// MSMQ订单Client /// private static void MSMQClient() { //创建订单数据 Order order = new Order() { OrderNo=Guid.NewGuid(), OrderDate=DateTime.Now, SupplierID=Guid.NewGuid(), SupplierName="SupplierName" }; OrderItem orderItem = new OrderItem() { ProductID=Guid.NewGuid(), ProductName="PP", Quantity=1, UnitPrice=1 }; order.OrderItems.Add(new OrderItem() { ProductID=Guid.NewGuid(), ProductName="ProductName1", Quantity=300, UnitPrice=10 }); order.OrderItems.Add(new OrderItem() { ProductID = Guid.NewGuid(), ProductName = "ProductName2", Quantity = 10, UnitPrice = 1 }); ChannelFactory
msmqChannel = new ChannelFactory
("MSMQClient"); IMSMQContract proxy = msmqChannel.CreateChannel(); using (proxy as IDisposable) { Console.WriteLine("\n消息队列通信测试:"); Console.WriteLine("MSMQ Submit Order To Server...."); using (TransactionScope tansactionScope = new TransactionScope(TransactionScopeOption.Required)) { proxy.SubmitOrder(order); tansactionScope.Complete(); Console.WriteLine("Order Has Been Submit! Complete This Order!"); } } } }}

 6.运行效果:

 

转载于:https://www.cnblogs.com/SanMaoSpace/p/3722097.html

你可能感兴趣的文章
DHCP工作过程的六个主要步骤
查看>>
相关变量跟自己无关,
查看>>
适合0基础的web开发系列教程-img图片标签
查看>>
MVC-命名空间“System.Web.Mvc”中不存在类型或命名空间名称“Html”(是否缺少程序集引用?)...
查看>>
Kali-linux使用Maltego收集信息
查看>>
Mysql : Error Code 1064
查看>>
SWT的FormLayout
查看>>
C# DataTable常用操作总结 (转载)
查看>>
编程思考 研究源代码心得
查看>>
logn+m复杂度找两个有序数列的中位数
查看>>
MySQL5.7延迟复制半同步复制
查看>>
前端面试之html5新特性
查看>>
10个超赞的jQuery图片滑块动画
查看>>
关于“计算题”程序的分析和总结
查看>>
贝塞尔曲线--css3动画类型
查看>>
Beta阶段冲刺日志集合贴
查看>>
校门外的树(增强版)
查看>>
lumen简单使用exel组件
查看>>
javascript运行机制之执行顺序详解
查看>>
获取伪元素的属性和改变伪元素的属性
查看>>