电脑技术学习

WinVista新技术 WCF开发指南之构建服务

dn001

  四. 服务合同

  在WCF中,所有的服务都暴露合同。合同是一种描述服务所实现功能的平台中立的标准的方式。WCF定义了四种类型的合同:

  · 服务合同描述你可以在服务上执行哪些操作。

  · 数据合同定义哪些数据类型被传入和传出服务。WCF为内置类型定义隐式合同,例如int和string,但是你可以容易地为定制类型定义显式的选入式数据合同。

  · 错误合同定义哪些错误将被该服务所激发,以及该服务怎样处理错误信息和把如何把它们传播到客户端。

  · 消息合同允许服务直接与消息进行交互。消息合同可以被类型化或非类型化,并且有点类似于CLR中的迟绑定调用。不过,消息合同很少为SOA开发者所用。

  在这4种类型的合同中,本文将集中讨论服务合同。

  你可以使用ServiceContractAttribute来定义一个服务合同,并且你可以把该属性应用于一个接口或一个类,如列表1(见本文相应下载源码)所示。

  服务合同独立于接口或类可见性-公共或内部可见性是一个CLR概念,而不是WCF概念。在一个内部接口上应用ServiceContractAttribute将把该接口暴露为一个公共服务合同(可以跨越服务边界进行消费)。没有ServiceContractAttribute的话,该接口对WCF客户端是不可见的,这与面向服务的宗旨一致(服务边界是显式的)。为了强制实现这一点,所有的合同必须是严格选入的。

  OperationContractAttribute仅能被应用到方法(而不是属性,索引器或事件,这都是一些CLR概念)中。OperationContractAttribute把一个合同方法暴露为在服务合同上执行的一种逻辑操作。该接口上的其它不具有OperationContractAttribute属性的方法不会成为合同的一部分。这可以强制实现显式的服务边界,并且,对于操作本身来说,保持一种选入模型。注意,合同操作独立于方法可见性。列表1展示了通过定义一个合同接口把服务合同与其实现分离开来的最好应用。

  另外,你还可以直接把ServiceContractAttribute和OperationContractAttribute应用于类,在这种情况下,WCF使用OperationContractAttribute从类中推断出一个服务合同和方法。这是一种应该尽量避免使用的技术:

//尽量避免使用
[ServiceContract]
class MyService
{
 [OperationContract] //可见性并不要紧
 string MyMethod(string text)
 {
  return "Hello " + text;
 }
 public string MyOtherMethod(string text)
 {
  return "Cannot call this method over WCF";
 }
}

  这个ServiceContractAttribute把CLR接口(或推断的接口)映射到一个技术中立的WCF合同上。通过派生和实现多个带有ServiceContractAttribute的接口,单个类可以支持多个合同。类能够通过隐式或显式方式实现这个接口,因为该方法可见性对WCF没有任何影响。然而,存在许多实现约束:避免使用参数化的构造器,因为WCF仅使用默认的构造器。尽管该类能够使用内部属性,索引器和静态成员,但是没有WCF客户端能够存取它们。

  五. 宿主

  每个WCF服务必须宿主在一个Windows进程中(称为宿主进程)。单个宿主进程可以宿主多个服务,而相同的服务类型可以宿主在多个进程中。WCF并不要求是否该宿主进程也是客户端进程。

  显然,应该有一个独立的进程支持错误和安全的隔离。另外,谁提供进程或调用哪种类型的进程都不是实质性的问题。这个宿主可以由IIS或Windows Vista中的Widows活动服务(WAS)或由开发者作为应用程序的一部分来提供。

  六. IIS宿主

  在IIS中宿主一个服务的主要优点是,在发生客户端请求时宿主进程会被自动启动,并且你可以依靠IIS来管理宿主进程的生命周期。IIS宿主的主要不利在于,你仅仅可以在IIS5和IIS6上使用HTTP传输数据;而且当使用IIS5时,你仅可以使用80端口。在IIS上宿主非常类似于宿主一个典型的ASMX Web服务。你需要在IIS下创建一个虚拟的目录并且提供一个.svc文件。这个.svc文件的功能就象一个被用来标识服务的code-behind文件和类的.asmx文件一样。

<%@ ServiceHost
Language = "C#"
Debug = "true"
CodeBehind = "~/App_Code/MyService.cs"
Service = "MyService"
%>

  你甚至可以把服务代码以内联方式注入到.svc文件中,但是不建议这样用(就象对于ASMX的情形一样)。一旦你准备好了.svc文件,你就可以使用一个浏览器来观看它。如果一切顺利,那么你将得到一个确认页面。

  Visual Studio 2005能够为你生成一个新的IIS宿主的服务。这只要从File菜单下选择"New Website",然后从"New Web Site"对话框中选择WinFX服务。这使得Visual Studio 2005创建一个新的Web站点,服务代码和匹配的.svc文件。另外,Web站点配置文件必须列举出你想要暴露的服务类型。你需要使用完全限定类型名(包括程序集名),如果类型来自于一个未引用的程序集的话。

<system.serviceModel>
<services>
<service name="MyNamespace.MyService">
...
</service>
</services>
</system.serviceModel>

  七. 自宿主

  自宿主是当开发者负责提供和管理宿主进程的生命周期时使用的技术名词。自宿主被应用在位于客户端和服务之间的一个进程(或计算机)边界环境中,以及当使用进程中服务的情况下(也就是说,与客户端处于相同的进程中)。你需要提供的进程可能是任何Windows进程,例如,一个Windows表单应用程序,一个控制台应用程序或一个Windows NT服务。注意,该进程必须在客户端调用服务之前先运行起来;典型情况下,这意味着,你必须预先启动它。对于NT进程中服务来说这并不是一个问题。

  类似于IIS宿主,宿主应用程序配置文件必须列出你想宿主的服务的类型并且暴露给外界。而且,该宿主进程必须在运行时刻显式地注册服务类型并且打开该宿主以便于客户端调用。典型地,这是在Main()方法中使用如下定义的助理类ServiceHost实现的:

public interface ICommunicationObject : IDisposable
{
void Open();
void Close();
//更多成员
}
public abstract class CommunicationObject :
ICommunicationObject
{...}
public class ServiceHostBase : CommunicationObject,...
{...}
public class ServiceHost : ServiceHostBase,...
{
public ServiceHost(Type serviceType,
params Uri[]baseAddresses);
//更多成员
}

  提供给ServiceHost的构造函数的信息有:服务类型和(可选)默认的基地址。该基地址集可以是一个空集(以后,你可以配置不同的基地址)。拥有一组基地址能够使服务接受在多个地址和协议上的调用。注意,每个ServiceHost实例都关联与一个特定的服务类型,并且如果宿主进程需要宿主多个类型的服务的话,你需要一些匹配的ServiceHost实例。通过调用宿主中的ServiceHost.Open()方法,你允许调入(call-in);并且通过调用ServiceHost.Close()方法,你可以体面地退出宿主实例并完成到当前客户端的数据发送,并且还要拒绝未来的客户端调用-即使宿主进程仍在运行中。典型地,关闭操作是在宿主进程关闭时实现的。例如,为了把这个服务宿主在一个Windows表单应用程序中:

[ServiceContract]
interface IMyContract
{...}
class MyService : IMyContract
{...}
你可以编写:
public static void Main()
{
Uri baseAddress = new Uri("http://localhost:8000/");
ServiceHost serviceHost;
serviceHost = new ServiceHost(typeof(MyService),baseAddress);
serviceHost.Open();
//能够拦截调用:
Application.Run(new MyForm());
serviceHost.Close();
}

  注意,你可以在调用ServiceHost.Open()之后拦截调用,因为该宿主接收在工作者线程上的所有调用。对ServiceHost.Open()的调用将加载WCF运行时刻并且支持接收客户端调用。该宿主能注册多个基地址,只要它们至少在传输方面存在不同:

Uri tcpBaseAddress = new Uri("net.tcp://localhost:8001/");
Uri httpBaseAddress = new Uri("http://localhost:8002/");
ServiceHost serviceHost = new ServiceHost(typeof(MyService),tcpBaseAddress,httpBaseAddress);

  通过从"Add New Item"对话框中选择WCF服务,Visual Studio 2005允许你把一个WCF服务添加到任何应用程序工程。以此方式添加的服务当然是进程中服务(相对于宿主进程来说),但是也可以由外部客户端存取。

标签: