为 WCF 解决方案设置项目框架
本文说明了如何通过完美组织项目结构来手动设置 WCF 解决方案。

引言
Windows Communication Foundation (WCF) 是 Microsoft .NET Framework 的一个扩展,它已被证明是构建分布式企业应用程序的绝佳工具。它是不断发展的分布式计算技术的成果。WCF 是一个统一的框架,它结合了 MSMQ、.NET Remoting 和 Web Services 等技术。使用 WCF 框架,您可以在面向服务的体系结构上构建松耦合的应用程序模块,或者构建实现应用程序业务逻辑的内部应用程序服务器。
在本文中,我将向您展示使用 Visual Studio 2008 创建 WCF 项目结构的最简单方法。这里提到的步骤同样适用于 Visual Studio 2010 (Beta)。
背景
开发人员在使用 WCF 时面临的一个主要问题是:WCF 解决方案的理想项目结构是什么?WCF 解决方案至少包含 2 个项目;一个用于定义和实现服务的项目,称为服务器,另一个用于利用这些服务的项目,称为客户端。开发人员必须同时处理这两个项目,因为在边界的两侧都需要进行大量的调试工作。互联网上有大量关于 WCF 及其相关技术的信息。然而,在花费了大量时间在互联网上搜索后,我仍然找不到任何关于如何为 WCF 解决方案创建基本项目框架的直接解释。也许我不是一个好的互联网搜索者,或者我的眼睛已经模糊到会忽略我正在寻找的东西。但无论如何,我需要向我的海外项目团队解释在 WCF 解决方案中连接项目的最佳方法。因此,我决定写一篇并将其发布,以造福每一位相关的开发人员。
目标
Visual Studio 2008 附带了一个名为 WCF Service Library 的项目模板,可以与 .NET Framework 3.0/3.5 一起使用。当您选择此类型项目时,Visual Studio 会为您完成许多底层工作,并自动化许多手动 WCF 任务。它还会将项目连接到使用预构建的程序wcfSvcHost.exe和wcfTestClient.exe。这是快速启动 WCF 应用程序的好方法。但是,使用此模板有很多副作用。最显著的问题是
- 它不支持同时在两端进行调试。要同时调试实际的客户端和服务器,需要大量手动工作,并要求对整个解决方案进行重构。
- 它在项目执行时运行测试客户端。这是一个很好的功能。但是,停止调试器并不会终止测试客户端。因此,随着时间的推移,您的桌面会充斥着孤立的客户端。
- 它会在项目中创建一个web.config文件,假设您正在构建将在 IIS 中托管的服务。在大多数情况下都是如此。但是,构建和托管服务的场景有很多。例如,如果您要构建一个将被 Windows 服务应用程序托管的应用程序服务器,并且该服务器使用 TCP 绑定,那么您需要对项目结构进行大量更改。
在本文中,我们的目标是创建一个可以克服上述所有缺点的项目结构。它确实需要一些手动工作,但最终会产生一个便于编码、调试、测试和部署的项目结构。说了这么多,现在是时候切换到实际行动模式了。
项目结构
为了说明起见,我们将构建一个提供温度转换方法的 WCF 服务。该服务公开两个方法;一个用于将温度从华氏度转换为摄氏度,另一个用于将温度从摄氏度转换为华氏度。
任何在一个项目中至少使用过 WCF 的人都会明白,构建 WCF 应用程序有 3 个阶段:创建契约(定义接口)、实现服务(构建类)以及利用这些服务(创建客户端应用程序)。出于同样的原因,我们将解决方案分成 3 个项目
- 契约定义项目(contracts 项目):此项目将存储所有接口和契约定义。它将生成一个程序集文件,该文件本质上是一个包含接口规范和契约定义的 DLL。此代理程序集最终将为客户端提供元数据。如果您严格构建仅在 Internet 上使用的服务,则此项目是可选的。但是,我使用的是更像 .NET Remoting 类型应用程序的示例。因此,创建此项目非常有帮助。
- 服务实现项目(services 项目):所有服务的实际实现代码将放在此项目中。
- 客户端项目:客户端项目将创建代理对象并调用其上的方法来使用服务。
涉及的步骤如下
1. 打开 Visual Studio 2008 并创建一个空白解决方案
在 Visual Studio 中创建一个空白解决方案,如下图所示,并将其命名为TConvertApp
。
2. 添加一个契约存储项目
创建一个类库类型的项目,并将其命名为TConvertAS.Contracts
。后缀 AS 用于指示该项目是应用程序服务器的一部分。
3. 添加一个服务实现项目
在上一步中,我们创建了一个用于存储契约定义项目的。我们还需要一个项目来存储这些接口的实现代码。
因此,创建一个类库类型的项目,并将其命名为TConvertAS.Services
。此项目将为托管提供服务实现。
4. 添加一个客户端项目
我们还需要一个客户端项目来利用主机公开的服务。通常的趋势是创建一个控制台应用程序用于测试和调试。但是,为了更好地说明,我们将创建一个 Windows 窗体应用程序。因此,创建一个类型为 Windows 窗体应用程序的项目,名称为TConvertClient
。
现在,我们的解决方案中已添加了三个项目;两个类库类型的项目和一个 Windows 窗体应用程序项目。
5. 为所有项目添加 WCF 程序集引用
在所有三个项目中,添加以下程序集的引用
System.ServiceModel;
System.Runtime.Serialization;
6. 添加契约项目的引用
由于契约项目中包含的接口将由实现项目和客户端项目使用,因此我们需要在这两个项目中添加契约项目的引用。
7. 删除代理和服务的默认类
创建契约和服务的项目时,Visual Studio 会自动在每个项目中添加带有默认类名的class1.cs文件。从这两个项目中删除这些文件。我们将添加自己的类。
8. 添加服务的接口
在契约项目中,添加一个名为ITempConverter.cs的接口类文件,并插入以下代码
namespace TConvertAS.Contracts
{
public interface ITempConverter
{
int ConvertFtoC(int Tf); // Converts Fahrenheit to Celsius
int ConvertCtoF(int Tc); // Converts Celsius to Fahrenheit
}
}
9. 添加命名空间和属性
此时,我们需要在接口中添加 WCF 属性。但在添加这些属性之前,请在文件中添加以下命名空间
using System.ServiceModel;
using System.Runtime.Serialization;
添加 WCF 属性后,更新后的接口如下
namespace TConvertAS.Contracts
{
[ServiceContract]
public interface ITempConverter
{
[OperationContract]
int ConvertFtoC(int Tf); // Converts Fahrenheit to Celsius
[OperationContract]
int ConvertCtoF(int Tc); // Converts Celsius to Fahrenheit
}
}
10. 编写服务实现代码
服务契约接口中指定的方法在服务项目中实现。实际代码如下
namespace TConvertAS.Services
{
public class TempConverter : ITempConverter
{
public int ConvertFtoC(int Tf)
{
int Tc = (int)((5.0 / 9.0) * (Tf - 32));
return Tc;
}
public int ConvertCtoF(int Tc)
{
int Tf = (int)((9.0 / 5.0) * (Tc + 32));
return Tf;
}
}
}
11. 添加应用程序配置文件并设置启动项目
在分布式计算中,客户端程序调用服务器上的方法。在 WCF 术语中,这称为与服务交换消息。为了促进消息交换,我们需要添加用于托管服务、创建终结点以及在客户端程序中创建用于连接到服务的通道的代码。我们可以以编程方式添加所有这些功能。但是,更好的方法是在配置文件中指定这些详细信息,以便我们可以在运行时动态更改参数。为此,请在服务项目和客户端项目中添加配置文件。
我们还需要指定启动项目。由于我们将同时运行和调试两个项目,因此我们需要指定多个启动项目。右键单击解决方案名称并选择“属性”选项。在“启动项目”选项中,选择“多个启动项目”并按照下图所示进行设置
12. 设置服务项目的调试主机引用
Visual Studio 2008(以及 Visual Studio 2010)附带了一个名为wcfSvcHost.exe的通用现成服务主机。这是一个很棒的工具,可以用于调试我们的服务代码。它位于C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE文件夹下。Microsoft 提供此程序作为一个简单的命令行实用程序,它接受两个参数:服务类程序集名称和应用程序配置文件名称。
WcfSvcHost.exe /service:MyService.dll /config:App.config
由于我们项目的程序集位于..\Project Name\Bin\文件夹下,而配置文件位于..\Project Name\文件夹下,因此我们可以通过设置下图所示的项目属性选项来运行主机程序:
我们现在可以运行该项目,您会看到 Visual Studio 无缝启动了主机程序。但是,服务实例不会启动,因为我们还没有定义服务终结点。值得注意的是,我们在这里使用的现成主机程序可能不适用于所有 WCF 解决方案。如果您需要以编程方式访问主机实例,wcfSvcHost.exe程序无法提供此功能。但是,在大多数其他情况下,它是开发周期中的理想程序。
13. 添加和配置服务终结点
现在是时候通过服务终结点公开我们的服务类了。此终结点使用 ABC 规则(地址、绑定、契约)定义,其在配置文件中的条目结构如下
<system.serviceModel>
<services>
<service
name="TConvertAS.Services.TempConverter">
<endpoint address="net.tcp://:8080/TempConverter"
binding="netTcpBinding"
contract="TConvertAS.Contracts.ITempConverter" name="TEMPCONV_SVC_TCP" />
</service>
</services>
</system.serviceModel>
如果您不想手动更新app.config文件,Microsoft 提供了一个很好的配置实用程序,名为svcConfigEditor.exe。它位于C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin文件夹下。请按照以下步骤在您的项目中使用它
- 在解决方案资源管理器窗口中,右键单击app.config文件。如果看到 WCF 配置实用程序选项,只需单击它,它就会打开该实用程序。
- 如果您没有看到上述选项,只需单击“打开方式”选项。它会打开一个新窗口,其中显示了程序列表。在该窗口中单击“添加”按钮,您将看到以下对话框。
- 现在,单击浏览按钮并为程序svcConfigEditor.exe选择路径。在“友好名称”字段中键入“WCF Config Utility”,然后单击“确定”按钮关闭对话框。
- 在上一个窗口中,选择实用程序名称并单击“确定”以在配置实用程序程序中打开配置文件。
- 选中服务选项后,单击“创建新服务”选项。作为第一步,它会要求您选择实际服务实现代码所在的程序集。在我们的例子中,我们必须选择TConvertAS.Services.dll文件。
- 一个 .NET 程序集可能包含多个服务。因此,在第二步中,实用程序提示我们选择服务。由于我们只写了一个示例服务,它将默认选中。
- 现在,我们必须选择通信模式。WCF 提供了多种协议作为通信选项。为说明起见,我们将选择 TCP 选项。
- 下一个页面提示我们提供地址。地址是客户端进行通信的位置。它包括协议、主机名(或 IP 地址)和端口号。虽然我们可以选择任何端口,但我们将使用端口 8080。因此,只需输入下图所示的值
- 单击“完成”按钮创建终结点。关闭配置实用程序并保存设置。
14. 添加和配置客户端终结点
就像我们在服务项目的配置文件中配置了服务终结点一样,我们也需要更新客户端项目的配置文件。创建客户端终结点需要以下基本条目。
<system.serviceModel>
<client>
<endpoint address="net.tcp://:8080/TempConverter"
binding="netTcpBinding"
contract="TConvertAS.Contracts.ITempConverter" name="TEMPCONV_CLT_TCP" />
</client>
</system.serviceModel>
您也可以使用 WCF 配置实用程序来更新配置文件。只需按照以下步骤操作
- 右键单击config文件打开配置实用程序,然后从列表中选择实用程序名称。选择“客户端”选项,然后单击“创建新客户端”链接。此时,向导页面提示我们选择服务项目的配置文件。
- 在选择配置文件后单击“下一步”按钮,实用程序会找出可用的终结点并提示我们从列表中选择一个。由于我们在服务端只有一个终结点,它将默认选中。单击“完成”按钮保存设置并关闭向导。
- 请确保将客户端终结点命名为
TEMPCONV_CLT_TCP
。
15. 添加代码以连接服务并调用方法
最后,我们必须在客户端项目中添加代码以连接到服务并调用其上的方法。
private void btnFtoC_Click(object
sender, EventArgs e)
{
try
{
ChannelFactory<ITempConverter> TcpFactory = new ChannelFactory<ITempConverter>
("TEMPCONV_CLT_TCP");
ITempConverter tcpProxy = TcpFactory.CreateChannel();
int tempval = int.Parse(tbxTempr.Text);
if (tcpProxy != null)
MessageBox.Show(tcpProxy.ConvertFtoC(tempval).ToString());
}
catch (Exception ex)
{
if (ex is EndpointNotFoundException)
{
MessageBox.Show("The server is either not running or is inaccessible.");
}
else
MessageBox.Show(ex.Message);
}
}
逻辑在以下 3 个步骤中实现
- 使用客户端终结点信息创建通道工厂对象。
- 从通道工厂实例化代理对象。
- 在代理实例上调用方法。
现在,构建解决方案并运行它。您会看到 Visual Studio 启动了 2 个项目:一个公开服务的宿主项目和一个客户端项目。在客户端项目窗体中,单击按钮,您将看到转换后的温度值作为响应。太棒了。创建这样的项目框架最大的优点是便于同时进行编码、调试和运行项目。此外,部署服务也变得容易。只需复制服务程序集和代理 DLL,并在远程机器上进行托管,并设置好配置文件即可。就是这样。
享受 WCF 项目的开发。
历史
- 2010年1月6日:初版