最近在封装WCF,有一些很好的实践就记录下来,大家可以放心使用,所有代码都已经调试过。如果有高手可以大家探讨一下。
在WCF中有两种不同的方法可以用于创建客户端服务对象,他们分别为:
1. 代理构造法
2. 通道工厂法
本文会从实际应用的角度上,阐述两种方法的一些细节和优劣对比,希望通过学习本文,能掌握什么情况下使用什么样的方式来创建客户端服务代理对象,怎样创建客户端代理对象。本文重点在术,非道。
构造代理法
从名字中可以看出,使用本方法创建客户端服务代理对象,是调用了服务代理类的构造方法。这种方法非常符合创建对象的常规方法:通过new的方式产生类型实例。可在WCF中要使用此方法,却是需要一个前提:要首先具备代理类。所以产生代理类便是此种方法首先要解决的问题了,下面就来看下WCF中创建代理类的几种常见办法。
在WCF中,创建代理类,可以分为下面的几种情况:
第一种:知道服务元数据地址,通过在项目中添加服务引用。
第二种:知道服务元数据地址,通过svcutil.exe生成代理类和配置文件。
第三种:从服务契约所在的的程序集(dll,exe)中导出元数据,然后从本地元数据生成代理类。
第四种:知道元数据的地址,通过自定义的代码生成代理类。
下面分别详细的阐述四种方法的操作过程
第一种:知道服务元数据地址,通过在项目中添加服务引用。
这种方法非常适合初学者,生成代理类的难度基本为0,也是这几种生成方式中最为简单的。但前提必须事先知道元数据的发布地址。下面是操作过程:
在项目中单击右键,选择添加【服务引用】,出现如下的对话框
一般情况下,填写完下面的对话框就可以点击确定,生成代理类了,但有的时候,我们需要对代理类对特殊的设置,比如我们要生成异步操作,要更改字典集合为数组等,这时候可以点击上图中左下角的高级按钮。出现如下的对话框:
经过上面的处理,就能生成代理类了,但是通过此种方法产生代理类存在一个问题,这个问题和WCF联系不大,但还是比较重要的,比如服务端是Java开发的,且采用的Soap1.1协议,那么采用上面这种方法,将无法产生匹配soap1.1的代理类,导致在调用服务的时候,出现如下的异常:
SOAP 版本可能不匹配: 出现意外的 Envelope 命名空间 http://schemas.xmlsoap.org/wsdl/。应为 http://schemas.xmlsoap.org/soap/envelope/。
这个是我在xml web service中的添加服务中发现的,新版本的添加服务引用仍热没有指定协议的设置。在xml web service中,解决上面问题的办法是采用wsdl.exe,然后指定参数/protocol:SOAP,也可以这样做:
第二种:知道服务元数据地址,通过svcutil.exe生成代理类和配置文件。
在WCF中的工具中Svcutil.exe是一个非常重要的工具,使用它,我们可以导出,导入,下载元数据,生成代理类,验证编译好的代理。如果我们已经知道元数据的发布地址,那么通过下面的操作,可以生成代理类
打开vs2015的命令行工具
Svcutil支持不同类型的元数据地址,如net.tcp://,http://等。下面分别进行演示:
元数据地址是net.tcp://格式:
svcutil /out:e:\client.cs /config:e:\app.config net.tcp://localhost:9000/MathService
配置文件格式为:
元数据地址格式是http://格式
svcutil /out:e:\client.cs /config:e:\app.config http://localhost:8000/
配置文件格式为:
生成代理类的过程和上图类似,不再添加注释。
第三种:从服务契约所在的的程序集(dll,exe)中导出元数据,然后从本地元数据生成代理类。
这种方式是用来处理不发布元数据,直接从服务契约所在程序集中提取元数据并生成代理类的,操作要分为两步:
第一步:从程序集中生成元数据 svcutil ServiceInterface.dll
运行此命令之后,文件夹中将产生如下的几个文件:
第二步:从元数据中生成代理类代码
这一步将使用上一步中生成的wsdl和xsd等元数据文件,最终生成代理类: svcutil *.wsdl *.xsd
通过上图,可以看到已经成功生成代理类schemas.microsoft.com.2003.10.Serialization.cs和客户端配置output.config
第四种:知道元数据的地址,通过自定义的代码生成代理类。
除了上面的生成代理类的方法,如果我们知道了元数据的地址,还可以通过自己的代码实现代理类的生成,自定义的方法为:
/// <summary>
/// 根据元数据发布地址生成代理类
/// </summary>
/// <param name="address">元数据地址</param>
/// <param name="outPutFile">代理类文件路径</param>
static void GenerateCode(EndpointAddress address, string outPutFile)
{
MetadataExchangeClient mexClient = new MetadataExchangeClient(address);
MetadataSet metadataSet = mexClient.GetMetadata();
WsdlImporter importer = new WsdlImporter(metadataSet);
CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
ServiceContractGenerator generator = new ServiceContractGenerator(codeCompileUnit);
foreach (ContractDescription contract in importer.ImportAllContracts())
{
generator.GenerateServiceContractType(contract);
}
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
using (StreamWriter sw = new StreamWriter(outPutFile))
{
using (IndentedTextWriter textWriter = new IndentedTextWriter(sw))
{
CodeGeneratorOptions options = new CodeGeneratorOptions();
provider.GenerateCodeFromCompileUnit(codeCompileUnit, textWriter, options);
}
}
}
通过上面的方法,都可以得到代理类,在没有双工的情况下,服务的代理类是System.ServiceModel.ClientBase<IService>的派生类,代理类包含下面四种构造方式
public ServiceClient()
{
}
public ServiceClient(string endpointConfigurationName) : base(endpointConfigurationName) { }
public ServiceClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { }
public ServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { }
public ServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { }
而如果服务中有双工Duplex,那么服务的代理类将不再继承System.ServiceModel.ClientBase<IService>,而是更改为:System.ServiceModel.DuplexClientBase<IDuplexService>,而且他的构造也会变成如下的四个:
public DuplexServiceClient(System.ServiceModel.InstanceContext callbackInstance) : base(callbackInstance) { }
public DuplexServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName) : base(callbackInstance, endpointConfigurationName) { }
public DuplexServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress) : base(callbackInstance, endpointConfigurationName, remoteAddress) { }
public DuplexServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(callbackInstance, endpointConfigurationName, remoteAddress) { }
public
DuplexServiceClient (System.ServiceModel.InstanceContext
callbackInstance, System.ServiceModel.Channels.Binding binding,
System.ServiceModel.EndpointAddress remoteAddress) :
base(callbackInstance, binding, remoteAddress) { }
通过调用上面代理类中任意的构造函数重载,都能创建客户端服务代理对象实例。具体使用方法可见实例项目Wcf.Client中的代码
所有代码都调试完毕,可以正常使用。
WCF生成客户端代理对象的两种方法的解释的更多相关文章
-
读取xml文件转成List<;T>;对象的两种方法(附源码)
读取xml文件转成List<T>对象的两种方法(附源码) 读取xml文件,是项目中经常要用到的,所以就总结一下,最近项目中用到的读取xml文件并且转成List<T>对象的方法, ...
-
取xml文件转成List<;T>;对象的两种方法
读取xml文件转成List<T>对象的两种方法(附源码) 读取xml文件转成List<T>对象的两种方法(附源码) 读取xml文件,是项目中经常要用到的,所以就总结一下,最 ...
-
wcf生成客户端代理类步骤及语句
通过svcutil.exe工具生成客户端代理类和客户端的配置文件 .在运行中输入cmd打开命令行 ()cd C:\Program Files (x86)\Microsoft SDKs\Windows\ ...
-
Intent传递对象的两种方法(Serializable,Parcelable) (转)
今天讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是Bundle.putParcela ...
-
Android中Intent传递对象的两种方法(Serializable,Parcelable)
今天要给大家讲一下Android中 Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是 Bundle.putP ...
-
在Delphi中使用C++对象(两种方法,但都要改造C++提供的DLL)
Delphi是市场上最好的RAD工具,但是现在C++占据着主导地位,有时针对一个问题很难找到Delphi或Pascal的解决方案.可是却可能找到了一个相关的C++类.本文描述几种在Delphi代码中使 ...
-
[转]Android中Intent传递对象的两种方法(Serializable,Parcelable)
http://blog.csdn.net/xyz_lmn/article/details/5908355 今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种 ...
-
Android高手进阶教程(十七)之---Android中Intent传递对象的两种方法(Serializable,Parcelable)!
[转][原文] 大家好,好久不见,今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object); ...
-
Intent传递对象的两种方法
Android为intent提供了两种传递对象参数类型的方法 分别需要使实体类实现Serializable接口.Parcelable接口 首先我们要知道,传递对象,需要先将对象序列化 一.那么为什么要 ...
随机推荐
-
SQL Server : Browser服务
SQL Server : Browser服务是SQL Server 2005新增的,简单的说,如果一个物理服务器上面有多个SQL Server实例,那么为了确保客户端能访问到正确的实例,所以SQL S ...
-
Unity小知识
这些是我在开发时遇到的一些问题: 2D的碰撞器和3D的碰撞器是没有任何物理反应的,必须是2D对2D,3D对3D 碰撞器Collision包含触发物体的速度等信息,触发器没有
-
effective c++:引用传递与值传递,成员函数与非成员函数
以pass-by-reference-to-const 替换pass-by-value 考虑以下class继承体系 class Person { public: Person(); // parame ...
-
ubuntu 停在开机界面
今天有解决了一个问题.我在win7虚拟机上装的64位的Ubuntu 12.04.忘了怎么个情况了,反正就是系统进不去了,停在了开机界面,5个点的那个. 解决方法如下: 开机的时候按住shift键,进入 ...
-
Cent OS 命令行和窗口界面默认登录切换方法
在 CentOS 中的修改方法如下: 1. root登陆,免得老是sudo 2. 打开/etc/inittab 文件 #vim /etc/inittab 3. 在默认的 run level 设 ...
-
无向图求割点 UVA 315 	Network
输入数据处理正确其余的就是套强联通的模板了 #include <iostream> #include <cstdlib> #include <cstdio> #in ...
-
F - Free DIY Tour(动态规划,搜索也行)
这道题可用动态规划也可以用搜索,下面都写一下 Description Weiwei is a software engineer of ShiningSoft. He has just excelle ...
-
mariaDB vs mysql
mariaDB vs mysql 今天遇到一个库使用的是mariaDB的数据库版本 Server version: 10.1.20-MariaDB MariaDB Server 理了一下mariaDB ...
-
【Python】【装饰器】
Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye()两个函数. def sa ...
-
使用 WebStorm IDE 调试 Pomelo 应用程序
使用得心应手的IDE来开发应用程序,可以使我们的工作事半功倍.而调试则更可以让我们准确的定位BUG,发现问题.本文讲述如何使用 WebStorm 这个怪兽级JavaScript IDE来调试 Chat ...