WCF通信的几个必要信息就是:地址、终结点、协议。
本文整理一下客户端的调用方法(通过使用函数的形式)
我目前只使用过几种binding类型,不同的Binding类型,其客户端的调用方式可能也会有些许区别,所以,一下内容仅作参考。
1、使用Channel的形式
也就是用ChannelFactory。
参考上一篇「服务」WCF中NetNamedPipeBinding的应用实例 客户端的调用方式;
1、需要服务协议内容,也就是把服务端,接口(文件)复制过来,添加到项目中,
比如,服务端的【IServer1.cs】:
//服务端的接口文件!!!
using System.ServiceModel;
//注意命名空间
namespace ConsolePipeWcf1.Server1
{
[ServiceContract]
interface IServer1
{
[OperationContract]
string GetData(int value);
}
}
在客户端,应用这个命名空间、并添加【System.ServiceModel】引用,接着就可以通过如下代码进行调用:
//客户端调用
using System;
//!!
using System.ServiceModel;
using ConsolePipeWcf1.Server1;//step1: Contract
namespace ConsoleServer1Client
{
class Program
{
static void Main(string[] args)
{
//step2: Binding
var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
//step3: Address
var address = new EndpointAddress("net.pipe://localhost/console/server1/");
//------------------------------- ↓(1)---- ↓(2)--- ↓(3)---
var factory = new ChannelFactory<IServer1>(binding, address);
IServer1 channel = factory.CreateChannel();
string s = channel.GetData(5);//随便给个数
Console.WriteLine(s);
Console.ReadKey();
}
}
}
2、使用Client的形式
2.1、添加服务引用的方式
很多教程的方法是在客户端中,直接添加“服务引用”,然后写代码。这种方式更加方便,先来说一下这种方式的操作步骤:
1、首先要把服务端启动起来,启动起来。
2、在客户端的程序上,右键项目名,选择【添加】->【服务引用】
接着把服务地址,确切的讲是mex地址(如果没有单独设置mex地址的话,默认的是在基地址后面添加“/mex”),填进去。
点击【转到】,会检测到现有的服务,如下图:
可以修改下命名控件,然后点击【确定】,即添加服务引用成功。
然后使用如下代码进行调用:
//客户端调用
using System;
//!!
using System.ServiceModel;
namespace ConsoleServer1Client
{
class Program
{
static void Main(string[] args)
{
//添加服务引用的命名空间
ServiceReference1.Server1Client client = new ServiceReference1.Server1Client();
string str = client.GetData(9);
Console.WriteLine(str);
Console.ReadKey();
}
}
}
2.2、纯手工的方式
如果我在写服务端、别人在写客户端,或者反过来,但在开发阶段,通过添加【服务应用】的方式并不方便,或者添加完后,最终代码整合、迁移,搞得不能用了怎么办?
仔细看了下添加【服务应用】后,在代码种XXXClient(例如上面代码种的Server1Client)的定义,发现其实只是VS自动生成了一部分代码,这部分代码分两部分(或者说三部分):一是服务端的接口,二是对接口进行封装,创建客户端类,(三是一些地址、绑定类型的配置文件),这些文件在客户端代码根目录下的【Connected Services】文件夹下。
把自动生成的【ServiceReference1.cs】文件种的Client类主体分割出来,如下:
class Server1Client: System.ServiceModel.ClientBase<NS.IServer1>,NS.IServer1
{
public Server1Client()
{
}
public Server1Client(string endpointConfigurationName) :
base(endpointConfigurationName)
{
}
public Server1Client(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public Server1Client(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public Server1Client(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}
public string GetData(int value)
{
return base.Channel.GetData(value);
}
}
类似于前面介绍的channel方法,在有了接口文件之后,再用上面的代码创建一个Server1Client类即可(类名可以随便起,注意命名空间写对),效果是一样的。
比如我复制上面的代码,然后删除【服务引用】,把服务端的【IServer1.cs】文件复制过来,然后利用上面复制的代码,写一个新类:
//引用复制过来的IServer1的命名空间
using ConsolePipeWcf1.Server1;
//客户端命名空间下的
namespace WCFNetNamedClientDemo
{
class MyNewClient : System.ServiceModel.ClientBase<IServer1>, IServer1
{
//无参构造函数 需要搭配【App.Config】文件使用
public MyNewClient(){}
public MyNewClient(string endpointConfigurationName) :
base(endpointConfigurationName)
{}
public MyNewClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{}
public MyNewClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{}
//通过代码的方式 指定Binding和Address
public MyNewClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{}
public string GetData(int value)
{
return base.Channel.GetData(value);
}
}
}
换句话说,如果我开发服务端,我只需要把接口文件,以及这个MyNewClient 类文件,提供给客户端一样可以实现调用。
区别的一点是,通过VS添加服务应用,会自动配置地址和绑定类型。
如果用纯手工的方式,就需要在代码种指定一下Address和Binding了,例如:
//声明是什么Binding
NetNamedPipeBinding binding = new NetNamedPipeBinding();
//申明地址
EndpointAddress address = new EndpointAddress("net.pipe://localhost/console/server1/");
//使用对应参数的构造函数
MyNewClient client = new MyNewClient(binding, address);
string str = client.GetData(9);
Console.WriteLine(str);