调用WCF服务的几种方式
首先发布了一个名为PersonService的WCF服务。服务契约如下:

[ServiceContract]
public interface IPersonService
{
[OperationContract]
string GetPersonName(string name); [OperationContract]
Person GetPerson(Person person);
} [DataContract]
public class Person
{
[DataMember]
public int Age { get; set; } [DataMember]
public string Address { get; set; } [DataMember]
public string Name { get; set; }
}
Contract
  在控制台中,实例化PersonService.PersonServiceClient,并调用服务中所包含的方法即可。

class Program
{
static void Main(string[] args)
{
PersonService.PersonServiceClient client = new
PersonService.PersonServiceClient();
Console.WriteLine(client.GetPersonName("Lily"));
PersonService.Person person = client.GetPerson(new PersonService.Person() {
Age = 20, Address = "Nanshan district", Name = "Lily" });
Console.WriteLine("Name:" + person.Name + "\r\n" + "Age:" + person.Age +
"\r\n" + "Address:" + person.Address);
Console.Read();
}
}
Console
第二种方法是使用SvcUtil工具生成服务代理。首先在菜单栏-工具-外部工具中,添加SvcUtil工具,一般其地址是:
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\SvcUtil.exe
选中“使用输出窗口”和“提示输入参数”

添加好工具后,点击SvcUtil,在参数栏输入服务的地址,点击“确定”,就会生成一个的PersonService.cs文件和一个output.config文件。将output.config改名为App.config,同PersonService.cs一起复制到控制台应用目录中


class Program
{
static void Main(string[] args)
{
PersonServiceClient client = new PersonServiceClient();
Console.WriteLine(client.GetPersonName("Lily"));
WcfInvokeDemo.Person person = client.GetPerson(new WcfInvokeDemo.Person() {
Age = 20, Address = "Nanshan district", Name = "Lily" });
Console.WriteLine("Name:" + person.Name + "\r\n" + "Age:" + person.Age +
"\r\n" + "Address:" + person.Address);
Console.Read();
}
}
Console
注:需要在控制台项目中引用System.ServiceModel.dll和System.Runtime.Serialization.dll
第三种方法是使用ChannelFactory,即通道工厂连接客户端和服务器端的终结点。首先在客户端需要知道服务契约(ServiceContract)。但是这里有个问题,关于DataContract。如果存在ComplexType,即本例中的Person类,是需要编译成一个第三方的assembly,并分别被服务器端和客户端引用。
调用CreateChannel()方法获得代理的引用,使用代理的方法。最后,通过将代理强制转换为IDisposable类型,调用Dispose()方法关闭代理。也可以将代理强制转换为ICommunicationObject类型,通过调用Close()方法关闭代理。

class Program
{
static void Main(string[] args)
{
string uri = @"http://localhost:7003/WcfInvokeDemo.PersonService.svc";
EndpointAddress endpointAddress = new EndpointAddress(uri);
BasicHttpBinding basicBind = new BasicHttpBinding();
ChannelFactory<IPersonService> factory = new
ChannelFactory<IPersonService>(basicBind, endpointAddress);
IPersonService channel = factory.CreateChannel();
// 可以使用IDisposable using(channel as IDisposable)
{
Console.WriteLine(channel.GetPersonName("Lily"));
SharedAssembly.Person person = new SharedAssembly.Person() { Address =
"Nanshan district", Age = 20, Name = "Lily" };
SharedAssembly.Person _person = channel.GetPerson(person);
Console.WriteLine("Name:" + _person.Name + "\r\n" + "Age:" + _person.Age +
"\r\n" + "Address:" + _person.Address);
}
// 也可以使用Close()
IPersonService channel1 = factory.CreateChannel();
Console.WriteLine(channel1.GetPersonName("Spencer"));
ICommunicationObject channel2 = channel1 as ICommunicationObject;
channel2.Close();
Console.Read();
}
}
ChannelFactory
第四种方法使用反射读取服务的元数据,即
http://larissa-pc:7003/WcfInvokeDemo.PersonService.svc?wsdl
因此需要保证<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>都是True。总之,这个方法非常复杂。
先创建代理的实例

public static class InvokeService
{
// 创建代理实例
public static object GetProxyInstance(ref CompilerResults compilerResults, string
uri, string contractName)
{
object proxyInstance = null;
Uri address = new Uri(uri);
MetadataExchangeClientMode mexMode = MetadataExchangeClientMode.HttpGet;
MetadataExchangeClient metadataExchangeClient = new
MetadataExchangeClient(address, mexMode);
metadataExchangeClient.ResolveMetadataReferences = true;
MetadataSet metadataSet = metadataExchangeClient.GetMetadata();
WsdlImporter wsdlImporter = new WsdlImporter(metadataSet);
Collection<ContractDescription> contracts = wsdlImporter.ImportAllContracts();
ServiceEndpointCollection allEndPoints = wsdlImporter.ImportAllEndpoints();
ServiceContractGenerator serviceContractGenerator = new
ServiceContractGenerator();
var endpointsForContracts = new Dictionary<string,
IEnumerable<ServiceEndpoint>>();
foreach(ContractDescription contract in contracts)
{ serviceContractGenerator.GenerateServiceContractType(contract);
endpointsForContracts[contract.Name] = allEndPoints.Where(x =>
x.Contract.Name == contract.Name).ToList();
} CodeGeneratorOptions codeGeneratorOptions = new CodeGeneratorOptions();
codeGeneratorOptions.BracingStyle = "C";
CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("C#");
CompilerParameters compilerParameters = new CompilerParameters(new string[] {
"System.dll", "System.ServiceModel.dll", "System.Runtime.Serialization.dll" });
compilerParameters.GenerateInMemory = true;
compilerResults = codeDomProvider.CompileAssemblyFromDom(compilerParameters,
serviceContractGenerator.TargetCompileUnit);
if (compilerResults.Errors.Count == 0)
{
Type proxyType = compilerResults.CompiledAssembly.GetTypes().First(t =>
t.IsClass && t.GetInterface(contractName) != null &&
t.GetInterface(typeof(ICommunicationObject).Name) != null);
ServiceEndpoint serviceEndpoint =
endpointsForContracts[contractName].First();
proxyInstance =
compilerResults.CompiledAssembly.CreateInstance(proxyType.Name, false,
BindingFlags.CreateInstance,
null, new object[] { serviceEndpoint.Binding, serviceEndpoint.Address
}, CultureInfo.CurrentCulture, null);
}
return proxyInstance;
}
}
CreatInstance

class Program
{
static void Main(string[] args)
{
// 这里给出的是WSDL的地址
// 我现在严重怀疑这种方法就是SvcUtil工具的实现原理?
string uri = @"http://localhost:7003/WcfInvokeDemo.PersonService.svc?wsdl";
string contractName = "IPersonService";
CompilerResults compilerResults = null;
// 获取代理实例,本例中即为PersonServiceClient
var proxyInstance = InvokeService.GetProxyInstance(ref compilerResults, uri,
contractName);
// 输出proxyInstance的类型名称,为“PersonServiceClient"
//Console.WriteLine(proxyInstance.GetType().Name);
string operationName = "GetPersonName";
string operationName1 = "GetPerson";
// 获取PersonServiceClient中名为“GetPersonName"的方法
//MethodInfo methodInfo = proxyInstance.GetMethod(operationName);
MethodInfo methodInfo1 = proxyInstance.GetType().GetMethod(operationName1);
// 获取方法所需的参数
//ParameterInfo[] parameterInfo = methodInfo.GetParameters();
ParameterInfo[] parameterInfo1 = methodInfo1.GetParameters();
/*foreach(var item in parameterInfo)
{
// 在本例中,参数为name,类型为String,因此输出为name:String
Console.WriteLine(item.Name + ":" + item.ParameterType.Name);
}
foreach(var item in parameterInfo1)
// 再试一下,如果为ComplexType,会输出person:Person
Console.WriteLine(item.Name + ":" + item.ParameterType.Name);*/
// 获取ComplexType的属性,这里是因为只有一个参数,即为person
var properties = parameterInfo1[0].ParameterType.GetProperties();
foreach (var item in properties)
/**
输出的结果为:
ExtensionData: ExtensionDataObject
Address:String
Age:Int32
Name:String
其中,ExtensionDataObject类用于存储已经通过添加新成员扩展的版本化数据协定中的数据
用于解决两个版本的数据契约之间某个参数被添加或者删除的问题
详情可见: https://www.cnblogs.com/CharlesLiu/archive/2010/02/09/1666605.html
**/
Console.WriteLine(item.Name + ":" + item.PropertyType.Name);
// 如果调用GetPerson方法,需要给参数的属性赋值
// 创建参数的实例
var parameter =
compilerResults.CompiledAssembly.CreateInstance(parameterInfo1[0].ParameterType.FullName,
false, BindingFlags.CreateInstance, null, null, null, null);
//Console.WriteLine(parameter.GetType().Name);
// 给参数的属性赋值时,一定要根据顺序来
properties[1].SetValue(parameter, "Home");
properties[2].SetValue(parameter, 20);
properties[3].SetValue(parameter, "Lily");
object[] operationParameters = new object[] { parameter };
// 调用methodInfo1方法
var ans = methodInfo1.Invoke(proxyInstance, operationParameters);
// 输出返回值的每个属性的值
foreach(var item in ans.GetType().GetProperties())
{
Console.WriteLine(item.Name + ":" + item.GetValue(ans));
}
Console.Read();
}
}
Console
此外,还有一种方式,就是把服务发布为RESTful样式,直接通过URL访问服务。在服务契约中需要使用WEBGET或者WEBINVOKE,并且使用webHttpBinding绑定方式。

[OperationContract]
[WebGet(UriTemplate="person/name={name}",
RequestFormat =WebMessageFormat.Json,
ResponseFormat =WebMessageFormat.Json,
BodyStyle =WebMessageBodyStyle.WrappedRequest)]
string GetPersonName(string name);
Contract

<endpoint address="" binding="webHttpBinding" behaviorConfiguration="WebBehavior"
contract="WcfInvokeDemo.IPersonService">
...
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
Config
注:本例中只编写了一个简单的WebGet。关于WebGet和WebInvoke,网上有很多介绍,这里就不再详述了。
这样发布后,可以直接在浏览器中通过URL调用服务:
调用WCF服务的几种方式的更多相关文章
- 学习之路十四:客户端调用WCF服务的几种方法小议
		
最近项目中接触了一点WCF的知识,也就是怎么调用WCF服务,上网查了一些资料,很快就搞出来,可是不符合头的要求,主要有以下几个方面: ①WCF的地址会变动,地址虽变,但是里面的逻辑不变! ②不要引用W ...
 - C# 调用WCF服务的两种方法
		
项目简介 之前领导布置一个做单点登录的功能给我,实际上就是医院想做一个统一的平台来实现在这个统一的平台登录后不需要在His.Emr.Lis等系统一个个登录,直接可以登录到对应的系统,然后进行相应的操作 ...
 - C#动态调用WCF接口,两种方式任你选。
		
写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去研究,最近自己做一个项目时用到了WCF. 从这 ...
 - 【Java EE 学习 80 下】【调用WebService服务的四种方式】【WebService中的注解】
		
不考虑第三方框架,如果只使用JDK提供的API,那么可以使用三种方式调用WebService服务:另外还可以使用Ajax调用WebService服务. 预备工作:开启WebService服务,使用jd ...
 - WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载]
		
原文:WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载] 我们有两种典型的WCF调用方式:通过SvcUtil.exe(或者添加Web引用)导入发布的服务元数据生成服务代理相关的代码 ...
 - 完全使用接口方式调用WCF 服务
		
客户端调用WCF服务可以通过添加服务引用的方式添加,这种方式使用起来比较简单,适合小项目使用.服务端与服务端的耦合较深,而且添加服务引用的方式生成一大堆臃肿的文件.本例探讨一种使用接口的方式使用WCF ...
 - Post方式调用wcf服务
		
我们平常在PC端调用WCF服务,只要知道WCF服务的地址,客户端直接添加引用服务就可以使用了,殊不知还有其他方式,其实,我们也可以 通过HTTP POST的方式调用WCF服务,这样就不用添加引用了,在 ...
 - 实现jquery.ajax及原生的XMLHttpRequest调用WCF服务的方法
		
废话不多说,直接讲解实现步骤 一.首先我们需定义支持WEB HTTP方法调用的WCF服务契约及实现服务契约类(重点关注各attribute),代码如下: //IAddService.cs namesp ...
 - SharePoint 2013 调用WCF服务简单示例
		
内容比较简单,主要记录自己使用SharePoint 2013WCF服务遇到的小问题和小经验,分享给大家,希望能够给需要的人有所帮助.好吧,进入正题! 第一部分 SharePoint 2013调用自带W ...
 
随机推荐
- STC8H开发(七): I2C驱动MPU6050三轴加速度+三轴角速度检测模块
			
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
 - QMainWindow(一)
			
mainwindow.h: #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> class MainWindo ...
 - Chrome DevTools 面板全攻略
			
李华西,微医云服务团队前端开发工程师,喜欢瞎折腾,典型猫奴 Console 面板 此章节请打开 devtools/console/console.html 一起食用 一方面用来记录页面在执行过程中的信 ...
 - web服务组件
 - 详解ElasticAPM实现微服务的链路追踪(NET)
			
前言 Elastic APM实现链路追踪,首先要引用开源的APMAgent(APM代理),然后将监控的信息发送到APMServer,然后在转存入ElasticSearch,最后有Kibana展示:具体 ...
 - 从服务端生成Excel电子表格(Node.js+SpreadJS)
			
Node.js是一个基于Chrome V8引擎的JavaScript运行环境,通常用于创建网络应用程序.它可以同时处理多个连接,并且不像其他大多数模型那样依赖线程. 对于 Web 开发者来说,从数据库 ...
 - 学习MyBatis必知必会(5)~了解myBatis的作用域和生命周期并抽取工具类MyBatisUtil、mybatis执行增删改查操作
			
一.了解myBatis的作用域和生命周期[错误的使用会导致非常严重的并发问题] (1)SqlSessionFactoryBuilder [ 作用:仅仅是用来创建SqlSessionFactory,作用 ...
 - 如何在pyqt中通过OpenCV实现对窗口的透视变换
			
窗口的透视变换效果 当我们点击UWP应用中的小部件时,会发现小部件会朝着鼠标点击位置凹陷下去,而且不同的点击位置对应着不同的凹陷情况,看起来就好像小部件在屏幕上不只有x轴和y轴,甚至还有一个z轴.要做 ...
 - js-reduce方法源码
			
// 数组中的reduce方法源码复写 //先说明一下reduce原理:总的一句,reduce方法主要是把数组遍历, //然后把数组的每个元素传入回调函数中,回调函数怎么处理,就会的到什么样的效果 A ...
 - [论文][半监督语义分割]Adversarial Learning for Semi-Supervised Semantic Segmentation
			
Adversarial Learning for Semi-Supervised Semantic Segmentation 论文原文 摘要 创新点:我们提出了一种使用对抗网络进行半监督语义分割的方法 ...