WCF(.net 3.0)

 

Visual Studio 2008 中 WCF 的新增功能
Juval Lowy


代码下载位置: Foundations2008_02.exe (329 KB)
Browse the Code Online

Visual Studio ® 2008 和基础 Microsoft ® .NET Framework 3.5 提供了新工具,并支持 Windows ® Communication Foundation (WCF)。它们并未改变 WCF 1.0(与 .NET Framework 3.0 一起发布)的基本功能,而是对其进行了扩展和完善。
Visual Studio 2008 可自动执行 WCF 手动任务,包括更新代理引用和消除重复任务(例如创建简单托管项目)。Visual Studio 还能解决跨目标和数据协定类型共享等一些困难问题。在本专栏中,我将逐步介绍其新功能及优势,并对其任何缺陷和解决方法做出解释。尽管我将在此使用 C# 项目设置,但除非我另行说明,否则所有设置同样适用于 Visual Basic ®

 

.NET Framework 跨目标
Visual Studio 的早期版本通常针对随其一起提供的 .NET Framework 版本。例如,Visual Studio 2005 只能生成针对 .NET Framework 2.0 的程序集,而此惯例并不能反映大多数开发人员所面临的真实情况。通常,开发人员需要在维护针对早期版本的 .NET 而编写的旧版应用程序的同时,还要在其新版应用程序中使用新版 Visual Studio。
此外,此惯例还意味着开发人员在维护为早期版本的 .NET Framework 而编写的应用程序时,无法从效率增强功能(例如 Visual Studio 2005 中引入的代码重构支持)中获益。
问题在于 .NET Framework 各版本不支持跨目标功能。您要么必须安装多个版本的 Visual Studio,要么使用独立的测试和部署内部版本进行补偿。Visual Studio 2008 尝试通过为多个版本的 .NET Framework 提供充分支持(虽然不完美)来解决这一问题。由于实际上 .NET Framework 3.0 和 .NET Framework 3.5 使用的 CLR 版本与 .NET Framework 2.0 使用的相同,唯一的区别在于新引用的程序集,因此 Visual Studio 仍可针对相同运行库,而为 .NET Framework 版本 2.0、3.0 和 3.5(其中 .NET Framework 版本号对应的是发行版本,而不是运行库版本,运行库版本仍为 CLR 2.0)提供跨目标功能。
在 Visual Studio 2008 中,“Properties”(项目)的“Application”(应用程序)窗格包含一个称为“Target Framework”(目标框架)的新组合框,通过该组合框您就可以针对 .NET Framework 版本 2.0、3.0 和 3.5(参见 图 1)。
图 1  Visual Studio 2008 中的目标框架属性 (单击该图像获得较大视图)
Target Framework 值仅在开发时有效,而在运行时无效(您的程序集仍指向 .NET 2.0 CLR)。您选择的值表示您构建程序集时可针对的 .NET Framework 的最早版本。新项目默认被配置为针对 .NET Framework 3.5。如果添加引用,则会变得有些复杂;如果在引用较高版本程序集时,降低 Target Framework 版本,Visual Studio 2008 将提示您引用出错和内部版本失败。Visual Studio 2008 不允许您向其所需 Framework 版本高于现有项目的 .NET Framework 程序集添加引用。如果您向版本更高的同一解决方案中的其他项目添加引用,Visual Studio 2008 将警告您可能会发生冲突。如果通过浏览程序集来添加引用,Visual Studio 2008 将不会干预您进行操作。
在语言和跨目标方面,请注意,您可以在 C# 中(而不是 Visual Basic 中),通过限制编译器版本来限制使用 .NET Framework 2.0 或 3.0 项目中诸如匿名类型和扩展方法等功能。您可以转至“Build”(内部版本)窗格,然后单击“Advanced”(高级)按钮,并选择“ISO-2 (C# 2.0)”作为语言版本(而不是尚未标准化的默认版本)来执行此操作。
在 Visual Studio 2008 中打开 Visual Studio 2005 WCF 项目时,升级过程中框架版本保持为 2.0。实际上这可以正常运行(请记住,基础运行库版本并未改变),但我建议根据需要手动将其设置为版本 3.0 或 3.5。
使用新项目模板时,Target Framework 版本是最重要的因素。WCF 工作流和整合项目必须针对 .NET Framework 3.5 进行构建;Service Library 项目要求针对 .NET Framework 3.0 或 3.5。“Add Service Reference”(添加服务引用)功能仅当为项目选择 Framework 版本 3.0 或 3.5 时可用,本专栏稍后将介绍此功能。

 

WCF 提供的主机
Visual Studio 2008 附带了一款名为 WcfSvcHost.exe 的现成的通用服务主机。它位于 C:/Program Files/Microsoft Visual Studio 9.0/Common7/IDE 中。为了方便使用,我建议将该位置添加到系统的 Path 变量中。WcfSvcHost 是一种简单的命令行实用工具,可接受两个参数:一个是指向包含一个或多个服务类的 .NET 程序集的文件路径,另一个是指向托管 .config 文件的文件路径。例如:
WcfSvcHost.exe /service:MyService.dll  /config:App.config
指定的服务程序集可以是类库程序集 (DLL),也可以是应用程序程序集 (EXE)。WcfSvcHost 将启动一个新进程,该进程将自动托管指定 .config 文件的服务部分中列出的所有服务类。请注意,这些服务类及其服务约定和数据协定不必是公共类型,可以是内部类型。此外,自动托管的服务不需要提供任何元数据,但是它们可以发布元数据(如果选择发布)。
WcfSvcHost 是一种以桌面任务栏图标驻留的 Windows 窗体应用程序。若要关闭主机,只需从任务栏图标上下文菜单中选择“Exit”(退出)即可。使用这种方式终止托管不太妥当,因为 WcfSvcHost 将中止当前正在进行的所有调用,客户端很可能会收到异常。如果单击 WcfSvcHost 任务栏图标,将出现一个对话框,其中列出托管的所有服务(参见 图 2)。
图 2  WcfSvcHost 服务列表 (单击该图像获得较大视图)
该对话框还显示服务的状态及其元数据地址,您可以将这些信息复制到剪贴板,稍后向服务添加引用时可能会用得到。关闭 WcfSvcHost UI 只是将其折叠回任务栏。
WcfSvcHost 的目的就是在开发过程中不再需要使用独立托管程序集来配合服务库。诸如托管项目等的开发工作是一种重复任务,这些主机通常包含大量相同的代码行,当有多个服务库时,这些重复代码容易导致解决方案变得臃肿。为了便于开发和测试,可以将 WcfSvcHost 直接集成到您的 Visual Studio 2008 服务库项目中。在项目属性的“Debug”(调试)窗格中,将 WcfSvcHost.exe 指定为要启动的外部程序,然后将您的类库名及其 .config 文件(自动生成并自动复制到 bin 文件夹)指定为参数。
完成后,当您运行类库(完成上述操作后才能执行运行)时,它将借助该进程附带的调试器由 WcfSvcHost 自动托管。停止调试时,Visual Studio 2008 将以不妥当的方式中止托管。
您甚至可以在 .NET Framework 3.0 应用程序中与 Visual Studio 2005 项目一起使用 WcfSvcHost,由于 WcfSvcHost 只需要 .NET Framework 3.0,因此只需从安装了 Visual Studio 2008 的计算机上复制 WcfSvcHost 即可。为了使用更加方便,建议您将 WcfSvcHost 添加到 .NET Framework 3.0 计算机上的全局程序集缓存 (GAC) 中。
WcfSvcHost 的最后一个功能是能够自动启动客户端应用程序,甚至能够为客户端提供特定于该应用程序的可选参数:
WcfSvcHost.exe /service:MyService.dll  /config:App.config                  
               /client:MyClient.exe    /clientArgs:123,ABC
此功能对于在自动测试、甚至是简单部署的情况下启动主机和客户端非常有用。
WcfSvcHost 的最大缺陷是只适用于简单情况,例如在打开主机实例之前无需以编程方式访问主机实例的情况,或在其打开之后以编程方式访问其事件模型的情况。与使用 IIS 或 Windows Activation Service (WAS) 进行托管不同,WcfSvcHost 没有对等的服务主机工厂支持。因此,不具备动态添加基址、配置终结点、中止调用以及在主机级别配置自定义行为等功能。通过我对 WCF 的使用体验发现,除了最简单的情况之外,所有其他情况中最终都需要以编程方式访问主机实例,因此我并不将 WcfSvcHost 视为一种成熟、高效的主机,而我自己执行 WAS 或进行专用自托管。

 

WCF 提供的测试客户端
除服务主机外,Visual Studio 2008 还随附了一个用于进行基本测试的简单通用的测试客户端,您可以使用它调用大多数服务上的操作。正常安装后,测试客户端 WcfTestClient.exe 位于 WcfTestClient.exe, is found after normal installation at C:/Program Files/Microsoft Visual Studio 9.0/Common7/IDE 下。您必须为 WcfTestClient 提供一个命令行参数,其中包含要测试的服务的元数据地址:
WcfTestClient.exe http://localhost:9000/
您可以指定任何元数据地址,例如 HTTP-GET 或者 HTTP、TCP 或 IPC(命名管道)上的元数据终结点。也可以指定多个元数据地址:
WcfTestClient.exe http://localhost:8000/ net.tcp://localhost:9000/MEX
WcfTestClient 是一个 Windows Forms 3.5 应用程序(参见 图 3)。在此图中,左侧的树控件包含测试的服务及其终结点。您可以详细查看某个终结点的约定并选择某项操作。特定于该调用的信息将显示在右侧窗格的选项卡中。 图 4 所示为一个简单约定及其实现的示例。
图 3  使用 WcfTestClient (单击该图像获得较大视图)
您可以在方法选项卡的“Request”(请求)部分中输入作为操作参数的一个整数和一个字符串,如 图 3 所示。单击“Invoke”(调用)按钮时,它将向服务调度调用,并在“Response”(响应)中显示返回值或输出参数。如果是单向操作,WcfTestClient 将在消息框中通知您已成功调度此操作。如果出现异常,WcfTestClient 将在消息框中显示异常信息,并让您发出其他调用。
WcfTestClient 不使用测试服务来维护传输层会话(或任何其他会话)。所有调用均在新代理实例上进行。此外,所有调用均异步进行,这样 UI 能随时进行响应。但是,尽管是异步调用,WcfTestClient 只允许一次调度一个调用。
WcfTestClient 从代理文件(包括 .config 文件)以静默方式创建程序集,然后从临时位置加载该程序集。如果单击树中的“Config File”(配置文件)项,您可以获取该 .config 文件(添加服务引用时生成的同一 .config 文件),并可以将其显示其选项卡中。
与早期的 Visual Studio ASMX Web 服务测试页不同,通过 WcfTestClient 您可以借助枚举、类或结构(每个类或结构都是其他类或结构的组成部分)等复合参数、甚至是参数集合和参数数组来调用操作。只需展开“Request”(请求)部分中的项,从下拉列表中设置其值(例如枚举值),并进行调用即可。如果操作接受集合或数组,您还需要设置其长度。例如, 图 5 显示了以下操作的结果请求和响应:
图 5  指定数组长度和值 (单击该图像获得较大视图)
[OperationContract]
bool ProcessNumbers(int[] numbers]
类似地,“Response”(响应)窗格将包含所有返回的复合值或输出参数。这样我们发现了 WcfTestClient 的一个缺陷:为了指定要测试的不同服务,您必须先关闭,并在更改命令行参数后重新启动 WcfTestClient。如果能同时在 GUI 中提供服务地址,则可能会很好地缓解这个问题。
您可以直接将 WcfTestClient 集成到您的 Visual Studio 2008 解决方案中。首先,将类库项目添加到解决方案,并删除所有引用、文件夹和源文件(因为您不需要这些项)。然后,将 WcfTestClient.exe 设置为外部启动程序,并提供一个或多个测试服务的一个或多个元数据地址,例如 IIS 或 WAS 托管项目的 .svc 地址,或者就此而言,解决方案内部或外部主机项目的任何其他元数据地址。
请注意,如果计算机上只安装了 .NET Framework 3.0,则您不能在其上使用 WcfTestClient,因为 WcfTestClient 需要使用内部 .NET Framework 3.5 树网格控件(用于表示复合参数的控件)。
当然,您可以在一个步骤中结合 WcfTestClient 和 WcfSvcHost,这样即可自动托管服务库中的服务并对其进行测试:
WcfSvcHost.exe /service:MyService.dll    /config:App.config 
               /client:WcfTestClient.exe 
               /clientArgs:http://localhost:9000/
但是,可以使用 WcfSvcHost 指定元数据参数。默认情况下,WcfSvcHost 将向指定客户端应用程序传送它在服务 .config 文件中找到的元数据地址。仅当服务未提供自己的元数据或您希望测试客户端使用其他地址时,才应显式指定元数据地址。此外,如果服务 .config 文件包含给定服务的多个元数据终结点,则这些终结点将按以下优先顺序提供:HTTP、TCP、IPC 和 HTTP-GET。您可以在 Visual Studio 2008 中合并这些步骤以进行无缝托管和测试体验。将 WcfSvcHost.exe 指定为启动程序,并将 .config 文件和 WcfTestClient.exe 指定为客户端。

 

WCF 服务库
作为 Target Framework 的一项功能,Visual Studio 2008 提供了多个新的 WCF 项目模板。通过“New Project”(新建项目)对话框中的组合框,您可以指定 Target Framework 的版本(2.0、3.0 或 3.5),如 图 6 所示。
图 6  WCF 项目模板 (单击该图像获得较大视图)
如果选择 Framework 2.0,则没有任何新模板可用。Framework 3.0 中提供了一个称为 WCF 服务库的新项目模板。此项目类型只是 WcfSvcHost 和 WcfTestClient 的预构建用法,与我前面提到的技术(将两者合二为一)非常类似。请注意,使用 WCF 服务库模板,就不需要将 WcfSvcHost.exe 指定为启动程序或 .config 文件,因为项目文件包含适用于 WCF 服务库的新 ProjectTypeGuids 元素。
但是该模板有一个负面影响:停止调试程序不会终止测试客户端;时间久了,您的桌面会由于孤立客户端而变得杂乱。要解决此问题,只需还原到前面清晰介绍的手动步骤。
WCF 服务库还提供了一个用于服务约定、服务约定的实施及匹配的 .config 文件的简单模板。
利用聚合服务库,您可以通过 WCF 终结点实现 RSS 源,并且可以从返回源的简单服务约定、服务约定的实施及匹配的 .config 文件着手操作。您可以托管和显示自己的源,与托管和显示任何其他服务一样。聚合终结点使用新的 WebHttpBinding 绑定。此新绑定旨在用于接收 Web 请求,而不能用于常规服务调用。
使用“顺序工作流服务库”模板,您可以将终结点的约定操作作为工作流活动来实现,或者将工作流显示为服务。项目将包含一个用于实现简单约定和匹配的 .config 文件的顺序活动。尽管客户端也将与类似传统终结点的终结点进行交互,但其实现完全是工作流驱动的。
“状态机工作流服务库”模板使用状态机而不是顺序工作流来实施其操作(触发状态转换)。工作流项目模板使用 WcfSvcHost 和 WcfTestClient,如同普通 WCF 服务库那样。工作流模板还使用新的上下文绑定对工作流实例 ID 的传递进行管理,从而支持持续工作流。我将在以后的专栏中详细介绍这些绑定。

 

添加服务引用
Visual Studio 2005 extensions for .NET Framework 3.0 提供了一项用于向 WCF 服务添加引用的基本功能,而不具有 SvcUtil 的许多高级功能。Visual Studio 2008 具有一个新的服务引用对话框,如 图 7 所示。
图 7  “添加服务引用”对话框 (单击该图像获得较大视图)
您可以在任何项目中打开此新对话框,方法是:右键单击解决方案资源管理器中项目内的任意位置,然后从上下文菜单中选择“Add Service Reference”(添加服务引用)。请注意,必须将项目配置为针对 .NET Framework 3.0(及更高版本)才能启用此选项。
在“Add Service Reference”(添加服务引用)对话框中,首先需要指定服务元数据地址(不是服务 URL,如对话框中所述),然后单击“Go”(执行)查看可用服务终结点(不是服务,如标记所示)。必须指定命名空间(如 MyService)才能包含生成的代理,然后单击“OK”(确定)生成代理并更新 .config 文件。请注意,在多数情况下,Visual Studio 2008 不是足够的智能来推断最清楚的绑定值,因此,它将通过声明绑定的所有默认值来删除 .config 文件。Visual Studio 的未来版本中将会解决此问题。如果您关注对 .config 文件的维护,请先打开 .config 文件,再添加引用,然后执行一次撤消 (Ctrl+Z) 操作,最后手动将 .config 文件条目添加到客户端部分中。
只要 WCF 服务位于网站项目或某个新 WCF 服务库中,您就可以使用“Discover”(搜索)按钮在自己的解决方案中查找这些服务。如果位于网站项目中,Visual Studio 2008 将检索 IIS 中的元数据或启动基于文件系统的 ASP.NET 开发服务器。如果位于 WCF 服务库中,则 WCF 将自动启动其主机 (WcfSvcHost) 以便获取元数据。
可以通过“Advanced”(高级)按钮打开设置对话框,从而调整代理生成,如同使用 SvcUtil(参见 图 8)一样。通过使用更直观的选项,您可以配置生成的代理和约定(公共或内部)的可见性;可以为数据类型生成适用于高级互操作方案的消息约定,在此方案中必须遵从现有消息格式(通常为自定义),并可以单击“Add Web Reference”(添加 Web 引用)按钮将引用转换为旧 ASMX Web 服务引用。
图 8  服务引用高级选项 (单击该图像获得较大视图)
“Generate asynchronous operations”(生成异步操作)复选框可以为导入的约定中的每个操作添加一对匹配的 Begin<operation> 和 End<operation> 元素,这两个元素允许客户端在工作线程中异步发出调用,并且通过提供完成回调方法或阻止完成来允许客户端稍后与操作完成进行同步。例如,假设约定的定义如下
[ServiceContract]
interface ICalculator
{
   [OperationContract]
   int Add(int number1,int number2);
}
则导入的约定将如 图 9 所示。
异步调用的匹配客户端代码将类似于如下所示:
CalculatorClient proxy = new CalculatorClient();
int sum;
AsyncCallback completion = (result)=>
                           {
                              sum = proxy.EndAdd(result);
                              Debug.Assert(sum == 5);
                              proxy.Close(); 
                           };
proxy.BeginAdd(2,3,completion,null);
虽然您可以按原样使用这些方法,但是提供给 Begin<operation> 的完成回调是从线程池中的线程调用的。如果使用回调访问某些与特定线程相关联的资源,则这样做会出现严重问题。Windows 窗体(或 WPF)应用程序即为典型示例,此应用程序异步调度较长的服务调用(避免阻止 UI),然后希望使用调用结果来更新 UI。不允许使用原始 Begin<operation> 进行更新,因为只允许 UI 线程更新 UI。为了更好地处理此情况,已用受保护的 InvokeAsync 方法扩展了 ClientBase<T> 基类,该方法可以获取客户端的同步上下文并将其用于调用完成回调,如 图 10 所示。
ClientBase<T> 还提供了一个事件参数帮助器类和两个用于启动和结束异步调用的专用委托。生成的代理类由 ClientBase<T> 派生而来,此代理类将使用这些基本功能。代理将具有一个 <operation>Completed 公共事件(该事件使用特定于异步方法结果的强类型事件参数类)和两个 <operation>Async 方法(用于异步调度调用):
partial class AddCompletedEventArgs : AsyncCompletedEventArgs
{
   public int Result
   {get;}
}

class CalculatorClient : ClientBase<ICalculator>,ICalculator
{
   public event EventHandler<AddCompletedEventArgs> AddCompleted;

   public void AddAsync(int number1,int number2,object userState);
   public void AddAsync(int number1,int number2);

   //Rest of the proxy 
}
客户端还可以为 <operation>Completed 事件订阅事件处理程序,以便在完成时调用此事件处理程序。使用 <operation>Async 与 Begin<operation> 的主要差别在于:<operation>Async 方法获取客户端的同步上下文,并在该同步上下文中激发 <operation>Completed 事件,如 图 11 所示。
通过“Collection”(集合)类型组合框,您可以指定如何向客户端显示在服务元数据中找到的某些类型的集合和数组。例如,如果服务操作返回 IEnumerable<T>、IList<T> 或 ICollection<T> 集合中的某一个,则默认情况下代理会将其显示为数组。例如,以下服务端操作
[OperationContract]
IEnumerable<int> GetNumbers();
将在代理上表示为:
[OperationContract]
int[] GetNumbers();
但是,您可以请求 Visual Studio 2008 使用其他集合(例如用于进行数据绑定的 BindingList、List<T>、Collection 和 LinkedList<T> 等)。如果可以进行转换,代理将使用请求的集合类型而不是数组,如下所示:
[OperationContract]
List<int> GetNumbers();
字典也具有类似功能。通常情况下,如果服务操作返回可序列化的字典,如下所示
[Serializable]
class MyDictionary<K,T> : IDictionary<K,T> 
{...}

[OperationContract]
MyDictionary<int,string> GetDictionary();
代理类随后会将该字典表示为 Dictionary<T,K>,这是以下 Dictionary 集合类型组合框的默认值:
[OperationContract]
Dictionary<int,string> GetDictionary();
但是,您可以请求其他字典类型(如 SortedDictionary<T,K>、HashTable 或 ListDictionary),代理将改为使用这些字典(如果可能):
[OperationContract]
SortedDictionary<int,string> GetDictionary();
综上所述,新服务引用最重要的功能就是能够在程序集之间共享数据协定类型。使用 Visual Studio 2005,如果客户端将服务引用添加到两个支持相同数据协定的独立服务中,那么客户端将获得两个类型完全相同(表示相同数据协定)的不同服务引用。使用 Visual Studio 2008,默认情况下,如果客户端引用的任何程序集所具有的数据协定类型与引用服务的元数据中显示的数据协定类型相匹配,则 Visual Studio 2008 将不会再次导入该类型。有必要再次强调一下,现有数据协定引用必须位于另一个引用程序集中,而不是位于客户端项目本身中。Visual Studio 的未来版本中可能会解决此限制。目前,解决方法和最佳实践都很明显:将所有共享数据协定都构建到指定的类库中,并让所有客户端都引用该程序集。
通过服务引用的高级设置对话框,您可以配置数据协定共享。默认情况下“Reuse types in the referenced assemblies”(重用引用程序集中的类型)复选框处于选中状态,但您可以关闭此功能。不管复选框的名称是什么,此复选框都将只能共享数据协定而不能共享服务约定。使用复选框下面的单选按钮(参见 图 8),还可以指示 Visual Studio 2008 在所有引用的程序集中重用数据协定,或者通过选中列表中的特定程序集来限制共享这些程序集。
添加引用后,项目将具有一个新文件夹 Service References,该文件夹中显示了每个引用的服务的服务引用项(参见 图 12)。
图 12  服务引用文件夹 
随时可以右键单击引用并选择“Update Service Reference”(更新服务引用)来重新生成代理并更新客户端的 .config 文件。由于服务引用项中还包含一个记录了所使用的原始元数据地址的文件,因此可以执行此操作。
还可以选择“Configure Service Reference”(配置服务引用)打开一个对话框,该对话框与添加引用时使用的高级设置对话框类似。通过配置服务引用对话框,您可以更改服务元数据地址以及其他高级代理设置。
  1.什么是WCF

      Windows通信基础(Windows Communication Foundation,简称WCF)是基于Windows平台下开发和部署服务的软件开发包(Software Development Kit,SDK)。WCF为服务提供了运行时环境(Runtime Environment),使得开发者能够将CLR类型公开为服务,又能够以CLR类型的方式使得创建服务的任务事半功倍。WCF是微软对一系列产业标准定义的实现,包括服务交互、类型转换、封送(Marshaling)以及各种协议的管理。正因为如此WCF才能够提供服务之间的互操作性。WCF为服务开发提供了许多有用的功能,包括托管(Hosting)、服务实例管理(Service Instance Management)、异步调用、可靠性、事务管理、离线队列调用(Disconnected Queued Call)以及安全性。同时,WCF还提供了设计优雅的可扩展模型,使开发人员能够丰富它的基础功能。事实上,WCF自身的实现正是利用了这样的一种可扩展型。本书的其余章节会专注于介绍诸多方面的内容与特征。WCF的大部分功能都包含在一个单独的程序集 System.ServiceModel.dll 中,命名空间为 System.ServiceModel
     WCF是使用托管代码建立和运行面向服务(Service Oriented)应用程序的统一框架。它使得开发者能够建立一个跨平台的、安全、可信赖、事务性的解决方案,且能与已有系统兼容协作。WCF是微软分布 式应用程序开发的集大成者,它整合了.Net平台下所有的和分布式系统有关的技术,例如.Net Remoting、ASMX、WSE和MSMQ。以通信(Communiation)范围而论,它可以跨进程、跨机器、跨子网、企业网乃至于 Internet;以宿主程序而论,可以以ASP.NET,EXE,WPF,Windows Forms,NT Service,COM+作为宿主(Host)。WCF可以支持的协议包括TCP,HTTP,跨进程以及自定义,安全模式则包括SAML, Kerberos,X509,用户/密码,自定义等多种标准与模式。也就是说,在WCF框架下,开发基于SOA的分布式系统变得容易了,微软将所有与此相 关的技术要素都包含在内,掌握了WCF,就相当于掌握了叩开SOA大门的钥匙。

     2.WCF之Hello

     我们了解了什么是WCF之后,先来看一个简单的实例:Hello(开发环境VS2008SP1)

     开发步骤:

     第一步:打开VS2008,新建项目,选择Visual c#,.NET Framework选择3.5 选择已安装的模板WCF 服务应用程序模板,并将项目改名为Hello,如下图:

     2.创建好了项目,会自动给我们生成IService1.cs和Service1.svc等文件,我们要将这些删除掉,同时在生成的WebConfig中的system.serviceModel的配置节的services下面把以下服务配置删除掉:
             < service  name ="hello.Service1"  behaviorConfiguration ="hello.Service1Behavior" >
                
<!--  Service Endpoints  -->
                
< endpoint  address =""  binding ="wsHttpBinding"  contract ="hello.IService1" >
                    
<!--  
              部署时,应删除或替换下列标识元素,以反映
              在其下运行部署服务的标识。删除之后,WCF 将
              自动推导相应标识。
          
-->
                    
< identity >
                        
< dns  value ="localhost" />
                    
</ identity >
                
</ endpoint >
                
< endpoint  address ="mex"  binding ="mexHttpBinding"  contract ="IMetadataExchange" />
            
</ service >
     同时删除掉serviceBehaviors节中的:
< behavior  name ="hello.Service1Behavior" >
     
< serviceMetadata  httpGetEnabled ="true"   />
     
< serviceDebug  includeExceptionDetailInFaults ="false"   />
    
</ behavior >
      3.接下来我们手动添加我们要的服务hello,点击项目,添加新建项,选择WCF服务模板,修改名称为Hello.svc,确定后在项目中生成IHello.cs和Hello.svc,同时在Web.config中的system.serviceModel会变成如下:
     < system.serviceModel >
        
< services >
            
< service  behaviorConfiguration ="Hello.HelloBehavior"  name ="Hello.Hello" >
                
< endpoint  address =""  binding ="wsHttpBinding"  contract ="Hello.IHello" >
                    
< identity >
                        
< dns  value ="localhost" />
                    
</ identity >
                
</ endpoint >
                
< endpoint  address ="mex"  binding ="mexHttpBinding"  contract ="IMetadataExchange" />
            
</ service >
        
</ services >
        
< behaviors >
            
< serviceBehaviors >
                
< behavior  name ="Hello.HelloBehavior" >
                    
< serviceMetadata  httpGetEnabled ="true" />
                    
< serviceDebug  includeExceptionDetailInFaults ="false" />
                
</ behavior >
            
</ serviceBehaviors >
        
</ behaviors >
    
</ system.serviceModel >

     4.我们将IHello.cs修改为:

    [ServiceContract]
    
public   interface  IHello
    {
        [OperationContract]
        
string  SayHello( string  Name);
    }

     5.我们在Hello.svc中实现IHello中的SayHello:

         public   string  SayHello( string  Name)
        {
            
return   " Hello, "   +  Name;
        } 
     6.创建客户端:通过以上步骤,我们的WCF的Hello的服务已经创建好了。现在我们开始创建一个调用WCF的客户端,在我们所在的解决方案中添加一个名为Client的ASP.Net的web应用程序,在Default.aspx中添加如下代码:
< asp:TextBox  ID ="TextBox1"  runat ="server" ></ asp:TextBox >
        
< asp:Button  ID ="Button1"  runat ="server"  onclick ="Button1_Click"  Text ="Button"   />

     7.添加Hello服务引用:将Hello服务设为启动项,将Hello.svc设为起始页,运行得到服务地址http://localhost:3095/Hello.svc,我们在Client的项目中添加服务引用,将http://localhost:3095/Hello.svc填入地址栏中,点击前往,就会自动获取服务。获取到服务后,修改一下命名空间,如下图所示:

      8.在Default的按钮事件中添加如下代码:
         protected   void  Button1_Click( object  sender, EventArgs e)
        {
            ServiceReferenceHello.HelloClient proxy 
=   new  Client.ServiceReferenceHello.HelloClient();

            Page.ClientScript.RegisterStartupScript(
            
this .GetType(),
            
" js " ,
            
string .Format( " alert('{0}') " , proxy.SayHello(TextBox1.Text.ToString())),
            
true );
            proxy.Close();
        }
     9.查看效果,把Client项目设为启动项目,把Default.aspx设为起始页,运行项目,在文本框中输入文字,点击按钮看看运行效果:

     哈哈,简单吧,这样我们就创建了一个完整的简单的WCF项目。今天早上就学习到这儿,时间不早了,洗漱上班去了,哈哈,晚上回来继续学习。。。。。。。

     Hello源代码: http://files.cnblogs.com/peida/hello.rar

 

 

 前面我和WCF(mm)见了个面,基本了解了一下WCF的情况,并和她打了个招呼,发现还是很喜欢她的呀,以后怎么找她呢,哈哈,WCF(mm)给我提供了可以找到它的地址,哈哈,羡慕不? 言归正传,开始学习WCF的地址(Address).

     WCF的每一个服务都具有一个唯一的地址(Addresses).地址包括两个重要的元素:服务的位置和传输协议(下次见MM的碰头地点和碰头暗号,有点不恰当)或者用于服务通信的传输样式。服务位置包括目标机器名、站点或网络、通信端口、管道或队列,以及一个可选的特定路径或者URI。URI及统一资源表示,他可以是任意的唯一标示的字符串,例如服务名称或GUID。例如上一步我们简单的WCF实例中的客户端中的:http://localhost:5509/hello.svc

< client >
 
< endpoint  address ="http://localhost:5509/Hello.svc"  binding ="basicHttpBinding"  bindingConfiguration ="BasicHttpBinding_IHello"  contract ="ServiceReference1.IHello"  name ="BasicHttpBinding_IHello" />
</ client >

     Address在WCF中的用System.ServiceModel.EndpointAddress对象来表示的,它的结构如下:

      

Address的组成部分及其作用: 
1.Uri:指示EndPoint的地址,是必须的
2.Identity:能保证地址的唯一性,当Uri一致的时候,可以用Identity来区分EndPoint,可有可无 
3.Headers:为地址提供了一些附加信息,用于Soap Message Filter,最后会添加到Soap消息的Header中
4.此外,Address还包括IsAnonymous属性,用于指示终节点是否能匿名访问。

     WCF支持的地址的样式有如下:

          1.HTTP,

          2.TCP,

          3.Peer network(对等网),

          4.IPC(基于管道的内部进程通信),

          5.MSMQ(微软消息队列)

     地址通常采用格式如下:

          [基地址]/[可选的URI]

     基地址的通常格式如下:

          [传输协议]://[机器名或域名][:可选端口]

     HTTP地址:

     HTTP使用HTTP协议进行传输,也可以利用https进行安全传输,http地址通常会被用作对外的的基于Internet的服务,并为其指定端口号,例如:http://localhost:8001 ,如果没有指定端口号,则默认为80端口。两个相同宿主的http地址可以共享一个端口,甚至相同的机器。

     TCP地址:

     TCP地址采用net.tcp协议进行传输,通常他还包括端口号,例如:net.tcp://localhost:8002/myservice ,如果没有指定端口号,则默认端口号为808:

net.tcp://localhost/myservice,两个TCP地址(来自相同的宿主)可以共享一个端口。

     IPC地址:

     IPC地址使用net.pipe进行传输,这以为着他将使用Windows的命名管道机制。在WCF中,使用命名管道的服务只能接受来自同一台机器上的调用。因此,在使用时必须指定明确的本地机器名或者直接命名为localhost,为管道名提供唯一的表示字符串:net.pipe://localhost/mypipe。每台机子只能打开一个命名管道,因此,两个命名管道地址在同一台机器上不能共享一个管道名。    

     MSMQ地址:

     MSMQ 使用 net.msmq 进行传输,及使用了微软消息队列(Microsoft Message Queue,MSMQ)机制。使用时必须为MSMQ地址指定队列名。如果是处理私有队列,则必须指定队列类型,但对于公有队列而言,队列类型可以省略:net.msmq://localhost/private/myservice  net.msmq://localhost/myservice.

     Peer network地址(对等网地址):

     使用net.p2p 进行传输,它使用了Windows的对等网传输机制。如果没有使用解析器,我们就必须为对等网地址指定对等网名,唯一的路径以及端口。(很少用到)

 

参考:

http://msdn.microsoft.com/zh-cn/magazine/cc163289.aspx

http://www.cnblogs.com/peida/archive/2008/08/19/1270793.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值