阅读目录
一:前言
二:WCF服务的创建
三:托管WCF服务
四:WCF服务的调用
五:总结
一:前言
大家看到三个工程图一,分别对应图二里面的不同部分,Client工程对应图二里面的Client,HelloWorldService工程对应了图二里面的Service,也就是说具体的服务是由HelloWorldService来进行提供的,Host工程对应图二里面的ServiceHost,要为HelloWorldService这个服务来提供一个运行的环境
图一
图二
二:WCF服务的创建
下面咱们来看具体的工程里面的代码,第一个工程:HelloWorldService,也就是服务创建的这个工程,为了能够使用WCF,在引用里面需要添加System.ServiceModel和System.IdentityModel这两个命名空间
在这个接口中实际上是定义了我们这个服务它要完成哪些事情,在这个接口中它要完成GetHelloWorld这个操作并且要有一个字符串类型的返回值,大家看到在接口上面多了一些属性ServiceContract和OperationContract,这些属性是在WCF当中特有的一些标记,这些标记我们把它称之为契约,这个实际上是WCF一个非常显著的特点,在WCF当中来说客户端与服务端进行通信必须要遵循某个契约来完成,客户端和服务端保证这些契约必须是相吻合的
1:IHelloWorldService.cs
using System;
using System.ServiceModel;
namespace HelloWorldService
{
/*加了契约的接口*/
[ServiceContract(Namespace="http://www.monkeyfu.net/")]
public interface IHelloWorldService
{
[OperationContract]
string GetHelloWorld();
}
}
2:HelloWorldService.cs
namespace HelloWorldService
{
/*来实现这个接口的一个具体类,对于加了契约的接口来进行实现*/
class HelloWorldService:IHelloWorldService
{
public string GetHelloWorld()
{
return string.Format("消息收到了在{0}:{1}", DateTime.Now, "世界如此美好,我却如此暴躁,不好,不好!");
}
}
}
三:托管WCF服务
第二个工程:Host,为了能够给客户提供服务的话,这个Service必然要被执行,它被执行的时候必然要放到主机里面,也就是必然要放到服务的主机里面,也就是ServiceHost里面来进行执行
1:创建主机
在Main这个主函数里面,我们创建一个ServiceHost host = new ServiceHost(),也就是创建一个主机,并且这个host所对应的服务实例是HelloWorldService.HelloWorldService也就是第一个工程里面的实现那个类,ServiceHost host = new ServiceHost(typeof(HelloWorldService.HelloWorldService))这句代码的意思就是说我们启动了一个新的主机,这个主机里面现在运行着一个服务,这个服务是由HelloWorldService.HelloWorldService这个类来进行实现的
2:添加新的Endpoint
然后在创建完一个host我们需要添加一个新的Endpoint,之前我们说过Endpoint叫端点也叫终结点,它的主要作用是用来提供Service向外发布的接口以实现客户端和服务端之间的通信,在我们添加一个新的Endpoint需要指定一些参数,第一个参数是这个Endpoint绑定到了哪个接口上,在这里是绑定到了IHelloWorldService这个接口上面,也就是说所有经过这个Endpoint的消息它都是遵循这个接口的,也就意味着所有通过我们添加的这个Endpoint的消息必须都要满足IHelloWorldService接口里面相应的契约当中的要求,第二个参数还要指定我们的这个Endpoint传输消息的时候需要绑定在哪个协议上面,在这里是使用new NetTcpBinding(), 就是使用TCP的协议来进行消息的传递,在指定完协议绑定完以后,第三个参数是要指定我们在进行消息传递的时候,通信的具体地址是哪里,在这里是net.tcp://localhost:9000/HelloWorldService
3:打开主机
然后host.Open();是打开主机,当host打开后可以对来提供服务了,客户端也可以连到主机上面来使用主机上面提供的这个HelloWorldService的这个服务了
1:Program.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using HelloWorldService;
namespace Host
{
class Program
{
static void Main(string[] args)
{
//step1启动了一个新的主机,这个主机里面现在运行着一个服务
using (ServiceHost host = new ServiceHost(typeof(HelloWorldService.HelloWorldService)))
{
//step2用来提供Service向外发布的接口以实现客户端和服务端之间的通信
host.AddServiceEndpoint(typeof(IHelloWorldService), new NetTcpBinding(), "net.tcp://localhost:9000/HelloWorldService");
//step3打开主机
host.Open();
Console.ReadLine();
}
}
}
}
四:WCF服务的调用
第三个工程:Client
1:创建Proxy代理
前面讲到Client它想要与Service进行交互的话需要一个Proxy代理,因此我们首先需要创建一个Proxy,我们使用ChannelFactory通道厂类创建一个新的channel通道出来,ChannelFactory它本身是一个泛型,在这个泛型指明这个Proxy遵循了哪一个契约,在这里我们使用了IHelloWorldService这个契约,这个契约的描述我们定义在了class Program的上面,大家可以看到这个描述和我们定义的IHelloWorldService描述是一摸一样的,客户端要想使用这个服务的话,必须使用和这个服务相匹配的契约来进行访问,这个是必须要遵守的要求,CreateChannel(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:9000/HelloWorldService"))在CreateChannel方法里面来指定一些通信相关的参数,第一个参数也是绑定在Tcp上面的通信方法,第二个参数是创建一个新的EndpointAddress,并且它的地址是指向ServiceHost的地址,大家会看到当我们创建完Proxy代理以后,实际上是把我们的Client端和Host端建立的一个等价的联系,这个联系就是我们大家都是使用Tcp协议,来访问Host提供的地址net.tcp://localhost:9000/HelloWorldService,并且使用相同的契约
2:通过代理访问服务
在创建完Proxy代理以后,我们就可以调用Proxy代理里面的GetHelloWorld这个方法了,这个GetHelloWorld就是前面的IHelloWorldService接口提供的方法,在执行GetHelloWorld的这个方法时候,WCF会通过Tcp协议来访问Host里面的net.tcp://localhost:9000/HelloWorldService这个地址,在Host端的Endpoint会接收到这个消息以后会根据契约IHelloWorldService找到HelloWorldService类里面相应的业务逻辑,并且执行逻辑里面实际的代码,对于客户端这些底层我们不需要去关心的,我们只需要调用GetHelloWorld这个方法就行了,跟我们本地调用是没什么区别的,其实就是通过代理类完成类似本地调用实现了分布式调用
1:Program.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
namespace Client
{
//step1创建服务契约的一个副本
[ServiceContract(Namespace = "http://www.monkeyfu.net/")]
public interface IHelloWorldService
{
[OperationContract]
string GetHelloWorld();
}
class Program
{
static void Main(string[] args)
{
//step2创建Proxy代理
IHelloWorldService proxy = ChannelFactory<IHelloWorldService>.CreateChannel(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:9000/HelloWorldService"));
//step3通过代理访问服务
string Result = proxy.GetHelloWorld();
Console.WriteLine(Result);
Console.ReadLine();
}
}
}
运行时效果
Client端通过Tcp协议去访问了Host端里面的HelloWorldService服务里面的GetHelloWorld这个方法, 这样我们就完成了一个简单的基于Tcp协议的分布式的调用
1:首先启动Host端
2:然后启动Client端
五:总结
客户端和服务端的基本要求
. 服务端
1:定义和实现服务契约
就是说在服务这一端的话,它不但要完成具体服务的业务逻辑,还要完成这个服务相应的契约
2:为服务类型创建ServiceHost实例,暴露Endpoint
创建ServiceHost实例可以理解为我们创建了一个服务器,并且把这个服务放到服务器里来进行处理,同时要暴露出Endpoint端点来,使得客户端能够来访问ServiceHost里面对应的Service服务
3:打开通信的通道
使得客户端能够访问服务端的这些服务
. 客户端
1:需要服务契约的一个副本和关于Endpoints端点的信息
服务契约的一个副本可以理解为在这个服务当中包含契约的一个接口,虽然说客户端不需要服务的具体的业务逻辑,但是客户端需要这个服务当中包含契约的一个接口,来告诉客户端它如何与服务端进行通信应该遵循哪些规则,Endpoint端点的信息主要包含了服务器端服务的具体地址以及使用什么样的协议进行具体的通信
2:为特定的Endpoints构建通信通道并且执行调用操作已完成我们具体的服务
下面这个图三更好的说明了客户端和服务端具体的Endpoint的一个作用
我们就以ABC来进行一下阐述,一个消息要想传送出去或者想要接收到的话必须要有ABC这三样东西的,这三样是缺一不可的
-A表示Address地址,这个主机在哪,像上面提到的”net.tcp://localhost:9000/HelloIndigo“,这个就是我们所说的地址,它告诉客户端要去哪里访问主机当中的服务
-B表示Binding绑定,Binding告诉我们如何来进行通信,像上面提到的我们使用的Tcp的协议来进行通信
-C表示Contract契约,Contract告诉我们究竟要传什么,要干什么,还对我们要干什么的操作进行了具体的约束,我们做这件事情的名称和参数都是用Contract契约来描述的
图三