WCF宿主
WCF服务应用程序与WCF服务库
在平时开发的过程中常用的项目类型有“WCF 服务应用程序”和“WCF服务库”。
WCF服务应用程序,是一个可以执行的程序,它有独立的进程,WCF服务类契约的定义,可以直接看到运行的效果。此项目模板基于IIS托管的程序,第一个案例的开发基于IIS托管的WCF服务程序时,比较多见,自学的时候也可以使用这种类型,简单易懂。
WCF服务库,可以认为是一个包含WCF服务以及契约定义的类库。不能直接运行,你可以在其他项目里引用,在宿主里启用托管这个库,有点类似于我们在Web项目中应用的类库。考虑WCF服务设计的时候,服务类的定义为单独的库,可以为其它项目使用。提高代码的复用性。
也可以修改这些代码,比如把WCF服务程序里的类,移到一个单独的类库里,或是把类库里的类移到WCF服务程序中。
概述
通过前面的介绍我们知道,WCF在运行时必寄宿在“宿主程序”之上,WCF本身不能够独自运行(每个WCF服务必须宿主在一个Windows进程中)。.Net 提供了多种宿主(控制台、Winform、WPF、WebForm…)供WCF运行,WCF还是非常灵活的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q6O4mLCk-1585819244285)(img/7.jpg)]
WCF的宿主可以是 Windows 服务、COM+应用程序、WAS(Windows Activation Services,Windows进程激活服务)或IIS、Windows应用程序,或简单的控制台应用程序及任何.net程序。
案例
重新建立WCF类库项目为例做示例,名称为:WCFLibrary,并删除自动生成的两个文件(IFeed1.cs、Feed1.cs)。如下图所示:
鼠标右键查看项目属性。我们发现,其实“WCF类库项目”与我们平时建立的“类库项目”都是类库,只不过多了WCF的类库项目在新建时多了两个dll的引用(System.ServiceModel.dll、System.Runtime.Serialization.dll)和一个自动生成的配置文件(该配置文件只用于调试时使用,在WCF寄宿以后会应用宿主的配置文件与其他应用程序通信)。这更说明了我们在做分式程序开发的时候与我们平时开发的应用程序没有多大的区别,只要我们在应用程序间通信时“符合WCF的约定”即可。
服务端我们还和第一个案例一样(ICalcService接口与CalcService实现),只建立一个方法做为我们调用的示例代码如下:
[ServiceContract]
public interface ICalcService
{
[OperationContract]
double Add(double a,double b);
}
public class CalcService : ICalcService
{
public double Add(double a, double b)
{
return a + b;
}
}
由于原来的契约为IFeed,现在的为ICalcService,所以配置文件会自动添加一个节点service
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="WCFLibrary.Feed1">
<endpoint address="Feed1" behaviorConfiguration="WCFLibrary.Feed1Behavior"
binding="wsHttpBinding" contract="WCFLibrary.IFeed1" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Design_Time_Addresses/WCFLibrary/" />
</baseAddresses>
</host>
<--自动添加的配置信息
</service>
<service name="WCFLibrary.CalcService">
<endpoint address="" binding="basicHttpBinding" contract="WCFLibrary.ICalcService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Design_Time_Addresses/WCFLibrary/CalcService/" />
</baseAddresses>
</host>
</service>
-->
</services>
<behaviors>
<endpointBehaviors>
<behavior name="WCFLibrary.Feed1Behavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
IIS宿主
把WCF寄宿在IIS之上,在IIS中宿主一个服务的主要优点是在发生客户端请求时宿主进程会被自动启动,并且你可以依靠IIS来管理宿主进程的生命周期。在开发和使用的过程与Web Service非常相似。
Winform应用程序宿主
建立宿主
-
在解决方案下新建Winform项目“WCFIIS”
-
添加 System.ServiceModel.dll 的引用
-
添加 WCF 服务类库(WCFLibrary)的项目引用
-
创建宿主程序
public WCFService() { InitializeComponent(); toolStripStatusLabel1.Text = "WCF服务未开启!"; } ServiceHost host = null; private void StartBtn_Click(object sender, EventArgs e) { //创建宿主的基地址 Uri uri = new Uri("http://192.168.0.102:4455/CalcService"); //创建宿主 using (host=new ServiceHost(typeof(CalcService),uri)) { //向宿主中添加终结点 host.AddServiceEndpoint(typeof(ICalcService),new WSHttpBinding(),""); //将HTTPGetEnable属性设置为true ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); behavior.HttpGetEnabled = true; //添加行为到宿主的Behaviors里面 host.Description.Behaviors.Add(behavior); //打开宿主 host.Open(); toolStripStatusLabel1.Text = "WCF服务启动成功!"; } } private void CloseBtn_Click(object sender, EventArgs e) { if (host==null) { return; } host.Close(); host = null; toolStripStatusLabel1.Text = "WCF服务已关闭!"; } }
-
开启时必须使用管理特权来运行承载 WCF 服务的进程,如果从 Visual Studio 2019内运行服务,则必须以管理员身份运行 Visual Studio 2019。
说明宿主建立成功。在上例中用到"ServiceHost"类,这里只是简单的应用,具体请查看"MSDN ServiceHost"。
建立客户端
- 重新建立解决方案–>Winform应用程序项目。
- 添加对服务的引用(在引用上右键–>输入我们定义的服务宿主的基地址(此处为:http://192.168.0.102:4455/CalcService)–>前往–>确定),命名空间改成“CalcService”
3. 按照之前的流程编写客户端代码
public FrmClient()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
CalcService.CalcServiceClient client = new CalcService.CalcServiceClient();
double a = double.Parse(textBox1.Text);
double b = double.Parse(textBox2.Text);
label2.Text = client.Add(a,b).ToString();
}
- 在这个示例中我们把Endpoint中的ABC,基地址,Behaviors等都直接写在了代码里,但实际应用过程中都是去依赖配置文件,为了对比说配置明我们下面的例子中会使用配置文件。
Winform依赖配置文件
建立宿主
-
在解决方案下新建Winform应用程序项目 WCFIIS。
-
添加 System.ServiceModel.dll 的引用。
-
添加 WCF 服务类库(WCFLibrary)的项目引用。
-
修改应用程序配置文件App.config
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> </startup> <system.serviceModel> <services> <service name="WCFLibrary.CalcService"> <host> <baseAddresses> <add baseAddress="http://192.168.0.102:6789/CalcService"/> </baseAddresses> </host> <endpoint address="" binding="basicHttpBinding" contract="WCFLibrary.ICalcService"></endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
-
在程序中编写开启服务
private void StartBtn_Click(object sender, EventArgs e) { host = new ServiceHost(typeof(CalcService)); host.Open(); toolStripStatusLabel1.Text = "WCF服务启动成功!"; }
建立客户端
同之前的程序一样,这里要引用的地址为:<addbaseAddress=“http://192.168.0.102:6789/CalcService”/>
这个例子中与上一个应用程序不同的是,在Winform应用程序中配置是直接写在程序中的,而在本例中应用的是配置文件,区别在于如果写在配置文件中程序运行时直接到配置文件里取出相关的配置节去创建ServiceHost类。
WAS宿主
IIS7允许通过HTTP外的协议进行激活和网络通信。此环境适合开发可通过WCF支持的任何网络协议(包括http、net.tcp、net.pipe、net.msmq)进行通信的WCF服务。部署简单、管理方便,这些网络协议在部署时可像Http一样,直接丢到IIS7上即可,我们在下面的例子中以net.tcp为协议为例。IIS7以下的版本只能支持Http的通信。
确保已安装IIS7的激活组件
在应用WAS宿主时,必须确保IIS7的激活组件安装好。打开“控制面板”–>“打开或关闭Windows功能”–>“功能”,我的机器上已经安装过,如下图所示(WCF激活与非WCF激活)
WCF配置文件
配置也是WCF编程中的主要组成部分。在以往的.net应用程序中,我们会把DBConn和一些动态加载类及变量写在配置文件里。但WCF有所不同。他指定向客户端公开的服务,包括服务的地址、服务用于发送和接收消息的传输和消息编码,以及服务需要的安全类型等。使用配置文件后,我们无需编译即可修改WCF的变化的信息,提高了程序的灵活性。
如果在代码里写了配置,那么配置文件将不起作用。
Web程序在Web.config中配置,应用程序中在App.config中配置。
服务配置的主要部分
在Config中配置服务的结点为:<system.serviceModel></system.serviceModel>,在这个节点中主要有三个平级的部分。如下代码所示:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<!--配置服务和终结点开始-->
<services>
<service>
<endpoint></endpoint>
</service>
</services>
<!--配置服务和终结点结束-->
<!--配置绑定开始-->
<bindings>
<netTcpBinding>
<binding></binding>
</netTcpBinding>
</bindings>
<!--配置绑定结束-->
<!--配置行为开始-->
<behaviors>
<serviceBehaviors>
<behavior>
</behavior>
</serviceBehaviors>
</behaviors>
<!--配置行为结束-->
</system.serviceModel>
</configuration>
Service配置节[必须有]:配置服务、接口和终结点。每个Service都会有以下两个属性。name:名称空间.类名[服务的具体实现类]。behaviorConfiguration:一个在behaviors节点中找到的名称。
**Binding配置节[可有可无]:**配置绑定,如http,tcp等。
Behavior配置节[可有可无]:配置行为,如认证等。