一丶什么是WCF
Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分。由.NET Framework 3.0开始引入。
WCF的最终目标是通过进程或不同的系统、通过本地网络或是通过Internet收发客户和服务之间的消息。
WCF合并了Web服务、.net Remoting、消息队列和Enterprise Services的功能并集成在Visual Studio中。
WCF专门用于面向服务开发。
客户机使用浏览器访问服务器A,服务器A为了业务需要与其他各种应用部署在服务器B、C、D…再通过WCF技术互相通信,相互访问…然而面向服务的好处不仅仅在此,他还提供了不同语言不同操作系统的可交互性。
二丶创建WCF的基本流程
环境是建立在VS2017的基础上,不同版本VS操作上可能会有点不同
新建项目
创建之后,生成这样的目录
删除系统生成的两个文件IService1.cs与Service1.svc
添加自定义的WCF【服务文件】
添加自定义的WCF【服务文件】CalcServicce.svc,此时vs2017会自动生成WCF接口文件ICalcServicce.cs,我们在ICalcServicce中定义WCF方法PlusNumber,在CalcServicce.svc.cs对该接口的方法进行实现。
自定义的服务文件中自带了一个接口DoWork函数,如果不需要可以删除
创建服务内容
先创建接口
[ServiceContract]
public interface ICalcService
{
[OperationContract]
double PlusNumber(double num1,double num2);
}
再实现接口
public class CalcService : ICalcService
{
public double PlusNumber(double num1, double num2)
{
return num1 + num2;
}
}
大家可以看到,在WCF中的接口与普通接口的区别只在于两个上下文,其他的和我们正常学习的接口一样。定义这个上下文要添加System.ServiceModel的引用。
[ServiceContract]
,来说明接口是一个WCF的接口,如果不加的话,将不能被外部调用。
[OperationContract]
,来说明该方法是一个WCF接口的方法,不加的话同上。
调试
此时我们的第一个WCF服务程序就建立好了,将CalcServicce.svc“设为起始页”,然后F5运行一下试试,如下图所示,VS自动调用了WCF的客户端测试工具以便我们测试程序,然后双击PlusNumber()
方法名,就会出现下图:
在请求窗口中的值中输入参数“num1”与“num2”,然后点击“调用”,在响应窗口中会出现返回值“WCF服务计算结果:num1+num2的值
”,说明测试成功,点击下面的XML也可以看到XML的数据传输。我们现在建立好了服务的应用程序和业务逻辑。
将WCF部署到IIS
到IIS右击网站,然后添加网站,将下图的参数填上。
然后就可以浏览此服务
点击CalcService.svc,跳转到以下调用页面
点击 http://192.168.1.99:8022/CalcService.svc?wsdl
,从这里可以看到我写的方法,这个地址也是我们后用将要引用的地址:
现在我们的WCF服务就算是已经部署完成了
调用WCF
创建一个Winform程序
选择添加服务引用
将服务地址输入选择转到
寻找到创建的服务CalcService选择确定
然后在项目中通过CalcService命名空间可以找到一个CalcServiceClient客户端实例化
public MainWindow()
{
InitializeComponent();
}
CalcService.CalcServiceClient client = new CalcService.CalcServiceClient();
private void Button_Click(object sender, RoutedEventArgs e)
{
double num1 = double.Parse(textBox.Text);
double num2 = double.Parse(textBox_Copy.Text);
label.Content = client.PlusNumber(num1, num2).ToString();
}
三丶WCF服务宿主
WCF服务应用程序与WCF服务库
我们在平时开发的过程中常用的项目类型有“WCF服务应用程序”和“WCF服务库”。
WCF服务应用程序,是一个可以执行的程序,它有独立的进程,WCF服务类契约的定义,可以直接看到运行的效果。此项目模板基于IIS托管的程序,在开发基于IIS托管的WCF服务程序时,比较多见,自学的时候也可以使用这种类型,简单易懂。
WCF服务库,可以认为是一个包含WCF服务以及契约定义的类库。不能直接运行,你可以在其他项目里引用,在宿主里启用托管这个库,有点类似于我们在Web项目中应用的类库。考虑WCF服务设计的时候,服务类的定义为单独的库,可以为其它项目使用。提高代码的复用性。
当然你也可以修改这些代码,比如把WCF服务程序里的类,移到一个单独的类库里,或是把类库里的类移到WCF服务程序中。
概述
通过前面的介绍我们知道,WCF在运行时必寄宿在“宿主程序”之上,WCF本身不能够独自运行(每个WCF服务必须宿主在一个Windows进程中)。.net提供了多种宿主供WCF运行,WCF还是非常灵活的。
WCF的宿主可以是 Windows 服务、COM+应用程序、WAS(Windows Activation Services,Windows进程激活服务)或IIS、Windows应用程序,或简单的控制台应用程序及任何.net程序。
创建宿主
创建一个宿主程序
private void button1_Click(object sender, EventArgs e)
{
double num1 = double.Parse(textBox1.Text);
double num2 = double.Parse(textBox2.Text);
string type = comboBox1.Text;
switch (type)
{
case "+":
label1.Text =( num1 + num2).ToString();
break;
case "-":
label1.Text = (num1 - num2).ToString();
break;
case "*":
label1.Text = (num1 * num2).ToString();
break;
case "/":
label1.Text = (num1 / num2).ToString();
break;
default:
break;
}
}
建立WCF类库项目
鼠标右键查看项目属性。我们发现,其实“WCF类库项目”与我们平时建立的“类库项目”都是类库,只不过多了WCF的类库项目在新建时多了两个dll的引用(System.ServiceModel.dll、System.Runtime.Serialization.dll)和一个自动生成的配置文件(该配置文件只用于调试时使用,在WCF寄宿以后会应用宿主的配置文件与其他应用程序通信)。这更说明了我们在做分式程序开发的时候与我们平时开发的应用程序没有多大的区别,只要我们在应用程序间通信时“符合WCF的约定”即可。
服务端我们还和第一个教程一样
namespace WCFLibrary
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“ICalcService”。
[ServiceContract]
public interface ICalcService
{
[OperationContract]
double Add(double num1,double num2);
[OperationContract]
double Mul(double num1, double num2);
[OperationContract]
double Max(double num1, double num2);
[OperationContract]
double Div(double num1, double num2);
}
}
namespace WCFLibrary
{
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“CalcService”。
public class CalcService : ICalcService
{
public double Add(double num1, double num2)
{
return num1 + num2;
}
public double Div(double num1, double num2)
{
return num1 / num2;
}
public double Max(double num1, double num2)
{
return num1 * num2;
}
public double Mul(double num1, double num2)
{
return num1 - num2;
}
}
}
因为我们直接添加的是WCF服务类,所以会在WCF类库的配置文件中自动添加这个服务类的配置内容
<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>
建立宿主
(1)添加 System.ServiceModel.dll 的引用。
(2)添加 WCF 服务类库(WCFLibrary)的项目引用。
(3)创建宿主程序,代码如下:
先写配置文件,在宿主程序的配置文件中,将WCF服务库中的配置文件中的Service节点全部拷贝
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<system.serviceModel>
<services>
<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>
<serviceBehaviors>
<behavior>
<!-- 为避免泄漏元数据信息,
请在部署前将以下值设置为 false -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<!-- 要接收故障异常详细信息以进行调试,
请将以下值设置为 true。在部署前设置为 false
以避免泄漏异常信息 -->
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
接下来在开启服务的时候,实现宿主Host并开启
private void Form1_Load(object sender, EventArgs e)
{
ServiceHost host = new ServiceHost(typeof(CalcService));
host.Open();
}
当配置文件中不使用WCF默认端口则宿主程序执行会报错
解决方案:以管理员身份运行宿主程序即可,因为管理员权限可以自主选择端口,或者手动将程序的入口函数通过代码设置为以管理员身份运行
static void Main(string[] arg)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//获得当前登录的Windows用户标示
System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);
//自身就具有管理员权限则按照默认情况运行
if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
{
//如果是管理员,则直接运行
Application.EnableVisualStyles();
Application.Run(new Form1());
}
else
{
//创建启动对象
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
//设置运行文件
startInfo.FileName = System.Windows.Forms.Application.ExecutablePath;
//设置启动参数
startInfo.Arguments = String.Join(" ",arg);
//设置启动动作,确保以管理员身份运行
startInfo.Verb = "runas";
//如果不是管理员,则启动UAC
System.Diagnostics.Process.Start(startInfo);
//退出
System.Windows.Forms.Application.Exit();
}
}