[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class DerivativesCalculatorServiceType: IDerivativesCalculator
某些行为是属性,如 ServiceBehaviorAttribute。 其他具有管理员希望设置的属性的行为可以在配置应用程序时修改。
在编程服务类型中,通常使用 OperationContext 类。 它的静态 Current 属性提供对有关运行操作上下文的信息的访问权限。 OperationContext 类似于 HttpContext 和 ContextUtil 类。
Hosting
ASP.NET Web 服务编译为类库程序集。 将提供一个称为服务文件且扩展名为 .asmx 的文件,该文件包含一条 @ WebService 指令,该指令标识的类包含表示服务和服务所在程序集的代码。
<%@ WebService Language="C#" Class="Service,ServiceAssembly" %>
在 Internet 信息服务 (IIS) 中,服务文件将复制到 ASP.NET 应用程序根目录下,程序集则复制到此应用程序根目录的 \bin 子目录下。 然后,您可以在应用程序根目录下使用服务文件的统一资源定位符 (URL) 访问此应用程序。
在 IIS 5.1 或 6.0 中、作为 IIS 7.0 一部分提供的 Windows 进程激活服务 (WAS) 中以及任意 .NET 应用程序中,都可以很容易承载 WCF 服务。 若要在 IIS 5.1 或 6.0 中承载某项服务,此服务必须使用 HTTP 作为通信传输协议。
若要在 IIS 5.1、6.0 或 WAS 中承载某项服务,请使用下列步骤:
将此服务类型编译为类库程序集。
使用标识服务类型的 @ ServiceHost 指令创建一个扩展名为 .svc 的服务文件:
<%@ServiceHost language="c#" Service="MyService" %>
将服务文件复制到虚拟目录下,并将程序集复制到该虚拟目录的 \bin 子目录下。
将配置文件复制到虚拟目录下,并将其命名为 Web.config。
然后,您可以在应用程序根目录下使用服务文件的 URL 访问此应用程序
若要在 .NET 应用程序中承载某项 WCF 服务,请将此服务的类型编译为由该应用程序引用的类库程序集,然后使用 ServiceHost 类对应用程序进行编程,使其承载此服务。 下面是所需基本编程的示例:
string httpBaseAddress = "http://www.contoso.com:8000/";
string tcpBaseAddress = "net.tcp://www.contoso.com:8080/";
Uri httpBaseAddressUri = new Uri(httpBaseAddress);
Uri tcpBaseAddressUri = new Uri(tcpBaseAddress);
Uri[] baseAddresses = new Uri[] {
httpBaseAddressUri,
tcpBaseAddressUri};
using(ServiceHost host = new ServiceHost(
typeof(Service), //"Service" is the name of the service type baseAddresses))
host.Open();
[…] //Wait to receive messages
host.Close();
此示例演示如何在构造 ServiceHost 时指定一个或多个传输协议的地址。 这些地址称为基址。
为 WCF 服务的任意终结点提供的地址是与终结点主机的基址相关的地址。 对于每个通信传输协议,宿主都可以有一个基址。 在上面的配置文件配置示例中,为终结点选定的 BasicHttpBinding 将 HTTP 用作传输协议,因此终结点的地址 EchoService 与宿主的 HTTP 基址相关。 对于以上示例中的宿主,HTTP 基址为 http://www.contoso.com:8000/。 对于在 IIS 或 WAS 中承载的服务,其基址为服务的服务文件的 URL。
只有在 IIS 或 WAS 中承载并将 HTTP 配置为独有传输协议的服务,才可以使用 WCF ASP.NET 兼容模式选项。 启用此选项需要执行下列步骤。
程序员必须将 AspNetCompatibilityRequirementsAttribute 属性添加到服务类型中,并指定是允许还是需要 ASP.NET 兼容模式。
[System.ServiceModel.Activation.AspNetCompatibilityRequirements(
RequirementsMode=AspNetCompatibilityRequirementsMode.Require)]
public class DerivativesCalculatorServiceType: IDerivativesCalculator
管理员必须将应用程序配置为使用 ASP.NET 兼容模式。
<configuration>
<system.serviceModel>
<services>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
</configuration>
WCF 应用程序也可以配置为使用 .asmx(而非 .svc)作为服务文件的扩展名。
<system.web>
<compilation>
<compilation debug="true">
<buildProviders>
<remove extension=".asmx"/>
<add extension=".asmx"
type="System.ServiceModel.ServiceBuildProvider,
System.ServiceModel,
Version=3.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
</buildProviders>
</compilation>
</compilation>
</system.web>
此选项可以使您在将服务修改为使用 WCF 时,免于修改配置为使用 .asmx 服务文件 URL 的客户端。
客户端开发
ASP.NET Web 服务的客户端通过使用命令行工具 WSDL.exe 生成,该工具可将 .asmx 文件的 URL 作为输入提供。 WCF 提供的相应工具是 ServiceModel 元数据实用工具 (Svcutil.exe)。 它使用服务协定的定义和 WCF 客户端类的定义生成一个代码模块。 它还使用服务的地址和绑定生成一个配置文件。
通常,建议您基于异步模式对远程服务的客户端进行编程。 默认情况下,不论是同步模式还是异步模式,始终都会提供由 WSDL.exe 工具生成的代码。 可为任一模式提供 ServiceModel 元数据实用工具 (Svcutil.exe ) 生成的代码。 默认为对同步模式提供。 如果执行该工具时使用 /async 开关,则将为异步模式提供生成的代码。
不能保证由 ASP.NET 的 WSDL.exe 工具生成的 WCF 客户端类中的名称在默认情况下与由 Svcutil.exe 工具生成的 WCF 客户端类中的名称相匹配。 尤其是,在默认情况下,必须使用 XmlSerializer 序列化的类的属性名将在 Svcutil.exe 工具生成的代码中获得后缀 Property,这与 WSDL.exe 工具的情况并不一样。
消息表示形式
可以对由 ASP.NET Web 服务发送和接收的 SOAP 消息头执行自定义操作。 将从 SoapHeader 派生一个类,用于定义消息头的结构,然后 SoapHeaderAttribute 用于指示存在消息头。
public class SomeProtocol : SoapHeader
public long CurrentValue;
public long Total;
[WebService]
public interface IEcho
SomeProtocol ProtocolHeader
[WebMethod]
[SoapHeader("ProtocolHeader")]
string PlaceOrders(PurchaseOrderType order);
public class Service: WebService, IEcho
private SomeProtocol protocolHeader;
public SomeProtocol ProtocolHeader
return this.protocolHeader;
this.protocolHeader = value;
string PlaceOrders(PurchaseOrderType order)
long currentValue = this.protocolHeader.CurrentValue;
WCF 提供 MessageContractAttribute、MessageHeaderAttribute 和 MessageBodyMemberAttribute 等属性来描述服务发送和接收的 SOAP 消息的结构。
[DataContract]
public class SomeProtocol
[DataMember]
public long CurrentValue;
[DataMember]
public long Total;
[DataContract]
public class Item
[DataMember]
public string ItemNumber;
[DataMember]
public decimal Quantity;
[DataMember]
public decimal UnitPrice;
[MessageContract]
public class ItemMessage
[MessageHeader]
public SomeProtocol ProtocolHeader;
[MessageBody]
public Item Content;
[ServiceContract]
public interface IItemService
[OperationContract]
public void DeliverItem(ItemMessage itemMessage);
此语法将生成消息结构的显式表示形式,同时 ASP.NET Web 服务的代码也将暗示消息结构。 而且,在 ASP.NET 语法中,消息头表示为服务的属性,如上面示例中的 ProtocolHeader 属性;而在 WCF 语法中,它们更准确地表示为消息的属性。 此外,WCF 还允许将消息头添加到终结点的配置中。
<service name="Service ">
<endpoint
address="EchoService"
binding="basicHttpBinding"
contract="IEchoService ">
<headers>
<dsig:X509Certificate
xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
</dsig:X509Certificate>
</headers>
</endpoint>
</service>
使用此选项,可以在客户端或服务的代码中避免任何对基础协议标头的引用:标头将根据终结点的配置方式添加到消息中。
使用查询 WSDL 对 ASP.NET Web 服务的 .asmx 文件发出 HTTP GET 请求将使 ASP.NET 生成描述服务的 WSDL。 ASP.NET 将返回该 WSDL 作为此请求的响应。
通过 ASP.NET 2.0,用户可以验证服务是否与 Web 服务互操作性组织 (WS-I) 的基本配置文件 1.1 兼容,还可以插入一个声明表明服务与其 WSDL 兼容。 这可以通过使用 ConformsTo 属性的 EmitConformanceClaims 和 WebServiceBindingAttribute 参数实现。
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(
ConformsTo = WsiProfiles.BasicProfile1_1,
EmitConformanceClaims=true)]
public interface IEcho
可以自定义 ASP.NET 为服务生成的 WSDL。 通过创建 ServiceDescriptionFormatExtension 的派生类以将项目添加到 WSDL 中可实现自定义。
对 IIS 51、IIS 6.0 或 WAS 中承载 HTTP 终结点的 WCF 服务的 .svc 文件使用查询 WSDL 发出 HTTP GET 请求将导致 WCF 以描述服务的 WSDL 作为响应。 如果 httpGetEnabled 设置为 true,则使用查询 WSDL 对 .NET 应用程序所承载服务的 HTTP 基址发出 HTTP GET 请求具有相同的效果。
但是,WCF 也会使用为描述服务而生成的 WSDL 响应 WS-MetadataExchange 请求。 ASP.NET Web 服务没有对 WS-MetadataExchange 请求的内置支持。
可以广泛地自定义 WCF 生成的 WSDL。 ServiceMetadataBehavior 类提供了一些用于自定义 WSDL 的功能。 WCF 也可以配置为不生成 WSDL,而是在给定的 URL 中使用静态 WSDL 文件。
<behaviors>
<behavior name="DescriptionBehavior">
<metadataPublishing
enableMetadataExchange="true"
enableGetWsdl="true"
enableHelpPage="true"
metadataLocation=
"http://localhost/DerivativesCalculatorService/Service.WSDL"/>
</behavior>
</behaviors>
在 ASP.NET Web 服务中,未处理的异常将作为 SOAP 错误返回客户端。 您还可以显式抛出 SoapException 类的实例并对传输到客户端的 SOAP 错误内容加大控制力度。
在 WCF 服务中,未处理的异常并不会作为 SOAP 错误返回客户端,以防止敏感信息通过异常意外公开。 为了进行调试,系统将提供一个配置设置以将未处理的异常返回客户端。
若要将 SOAP 错误返回客户端,您可以使用数据协定类型作为泛型类型抛出泛型类型的实例 FaultException<TDetail>。 您还可以将 FaultContractAttribute 属性添加到操作中以指定操作可能会生成的错误。
[DataContract]
public class MathFault
[DataMember]
public string operation;
[DataMember]
public string problemType;
[ServiceContract]
public interface ICalculator
[OperationContract]
[FaultContract(typeof(MathFault))]
int Divide(int n1, int n2);
这样做会导致在服务的 WSDL 中显示对可能错误的建议,从而使客户端程序员可以预计操作可能会导致哪些错误,并编写相应的 Catch 语句。
result = client.Divide(value1, value2);
catch (FaultException<MathFault> e)
Console.WriteLine("FaultException<MathFault>: Math fault while doing "
+ e.Detail.operation
+ ". Problem: "
+ e.Detail.problemType);
用于实现 ASP.NET Web 服务的类可以从 WebService 派生。
public class Service : WebService, IEcho
public string Echo(string input)
return input;
在此情况下,可以将此类编程为使用 WebService 基类的“上下文”属性访问 HttpContext 对象。 通过使用 HttpContext 对象的 Application 属性,该对象可用于更新和检索应用程序状态信息,而且通过使用其 Session 属性,该对象可用于更新和检索会话状态信息。
ASP.NET 通过使用实际存储着 HttpContext 的 Session 属性对会话状态信息的访问位置提供高度控制。 它可以存储在 Cookie、数据库、当前服务器的内存或指定服务器的内存中。 在服务的配置文件中做出此项选择。
WCF 为状态管理提供可扩展对象。 可扩展对象就是实现 IExtensibleObject<T> 的对象。 最重要的可扩展对象为 ServiceHostBase 和 InstanceContext。 ServiceHostBase 允许你保持同一个主机上所有服务类型的所有实例都可访问的状态,而 InstanceContext 允许你保持可以被某个服务类型的同一个实例中运行的任意代码访问的状态。
此处,服务类型 TradingSystem 具有 ServiceBehaviorAttribute,此属性可指定所有来自同一个 WCF 客户端实例的调用都将发送至此服务类型的相同实例。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class TradingSystem: ITradingService
DealData 类用于定义可以由某个服务类型的相同实例中运行的任意代码访问的状态。
internal class DealData: IExtension<InstanceContext>
public string DealIdentifier = null;
public Trade[] Trades = null;
在实现服务协定中任一操作的服务类型的代码中,将 DealData 状态对象添加到当前服务类型实例的状态中。
string ITradingService.BeginDeal()
string dealIdentifier = Guid.NewGuid().ToString();
DealData state = new DealData(dealIdentifier);
OperationContext.Current.InstanceContext.Extensions.Add(state);
return dealIdentifier;
随后,可以使用实现另一个服务协定操作的代码检索和修改此状态对象。
void ITradingService.AddTrade(Trade trade)
DealData dealData = OperationContext.Current.InstanceContext.Extensions.Find<DealData>();
dealData.AddTrade(trade);
尽管 ASP.NET 对 HttpContext 类中状态信息的实际存储位置提供控制,但 WCF(至少在其初始版本中)并不对可扩展对象的存储位置提供控制。 这充分说明了为什么要对 WCF 服务选择 ASP.NET 兼容模式。 如果必须管理可配置状态,则选择 ASP.NET 兼容模式使您可以按照它们在 ASP.NET 中的使用方式使用 HttpContext 类的功能,而且还可以通过使用存储的 HttpContext 类配置状态信息的管理位置。
用于保证 ASP.NET Web 服务安全的选项就是那些用于保证任意 IIS 应用程序安全的选项。 因为 WCF 应用程序不仅可以在 IIS 中承载,还可以在任意 .NET 可执行文件中承载,用于保护 WCF 应用程序安全的选项必须独立于 IIS 的功能。 但是,为 ASP.NET Web 服务提供的功能也可用于在 ASP.NET 兼容模式下运行的 WCF 服务。
安全性:身份验证
IIS 可提供对应用程序的访问进行控制的功能,您可以使用此功能选择匿名访问或各种身份验证模式:Windows 身份验证、摘要式身份验证、基本身份验证和 .NET Passport 身份验证。 Windows 身份验证选项可以用于控制对 ASP.NET Web 服务的访问。 但是,当在 IIS 中承载 WCF 应用程序时,必须将 IIS 配置为允许匿名访问应用程序,以便 WCF 自身能够管理身份验证(在其他各个选项中,它支持 Windows 身份验证)。 其他内置选项包括用户名令牌、X.509 证书、SAML 令牌和 CardSpace 卡,但是也可以定义自定义身份验证机制。
安全性:模拟
ASP.NET 提供一个标识元素,ASP.NET Web 服务可通过使用该元素模拟当前请求提供了某个特定用户或任何用户的凭据。 此元素可用于配置在 ASP.NET 兼容模式下运行的 WCF 应用程序中的模拟行为。
WCF 配置系统提供自己的标识元素,用于指定要模拟的特定用户。 此外,还可以对 WCF 客户端和服务进行独立的模拟配置。 当客户端发送请求时,可将它们配置为模拟当前用户。
<behaviors>
<behavior name="DerivativesCalculatorClientBehavior">
<clientCredentials>
<windows allowedImpersonationLevel="Impersonation"/>
</clientCredentials>
</behavior>
</behaviors>
可将服务操作配置为模拟当前请求提供了任意用户的凭据。
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public void Receive(Message input)
安全性:使用访问控制列表进行授权
访问控制列表 (ACL) 可用于限制对 .asmx 文件的访问。 但是,WCF .svc 文件中的 ACL 将被忽略,处于 ASP.NET 兼容模式时除外。
安全性:基于角色的授权
IIS Windows 身份验证选项可与由 ASP.NET 配置语言提供的授权元素一起使用,以便根据将用户指定到的 Windows 组简化对 ASP.NET Web 服务的基于角色的授权。 ASP.NET 2.0 引入了一种更常用的基于角色的授权机制:角色提供程序。
角色提供程序就是所有实现基本接口以查询对用户分配哪些角色的类,但每个角色提供程序都知道如何从其他来源检索此信息。 ASP.NET 2.0 提供一个可从 Microsoft SQL Server 数据库检索角色分配的角色提供程序,同时还提供另一个可从 Windows Server 2003 授权管理器检索角色分配的角色提供程序。
实际上,角色提供程序机制可独立于 ASP.NET 在任意 .NET 应用程序(包括 WCF 应用程序)中使用。 下面的 WCF 应用程序配置示例演示如何通过 ServiceAuthorizationBehavior 选择使用 ASP.NET 角色提供程序。
<system.serviceModel>
<services>
<service name="Service.ResourceAccessServiceType"
behaviorConfiguration="ServiceBehavior">
<endpoint
address="ResourceAccessService"
binding="wsHttpBinding"
contract="Service.IResourceAccessContract"/>
</service>
</services>
<behaviors>
<behavior name="ServiceBehavior">
<serviceAuthorization principalPermissionMode="UseAspNetRoles"/>
</behavior>
</behaviors>
</system.serviceModel>
安全性:基于声明的授权
WCF 的最重要的创新之一就是它全面支持基于声明授权访问受保护的资源。 声明包含类型、权限和值等,例如驾驶执照。 它提出一组有关持有人的声明,其中一个是持有人的出生日期。 此声明的类型为出生日期,而声明的值为司机的出生日期。 声明授予持有人的权限指定持有人可对声明的值执行的操作。 如果是要声明司机的出生日期,权限为拥有:司机拥有该出生日期但是不能更改它。 基于声明的授权包含基于角色的授权,因为角色也是一种声明类型。
基于声明的授权可通过将一组声明与操作的访问要求进行比较实现,根据比较的结果,可获得操作的访问权或遭到拒绝。 在 WCF 中,您可以指定一个类来运行基于声明的授权,同样也可通过为 ServiceAuthorizationBehavior 的 ServiceAuthorizationManager 属性分配一个值实现。
<behaviors>
<behavior name='ServiceBehavior'>
<serviceAuthorization
serviceAuthorizationManagerType=
'Service.AccessChecker, Service' />
</behavior>
</behaviors>
用于运行基于声明的授权的类必须派生自只有一种重写方法(即 ServiceAuthorizationManager)的 AccessCheck()。 只要调用此服务的一项操作并提供一个 OperationContext 对象,WCF 就会调用该方法,其 ServiceSecurityContext.AuthorizationContext 属性中包含此用户的声明。 WCF 将组合任何来自用户为身份验证提供的安全令牌的用户声明,这将引发这些声明是否满足操作需要的评估任务。
WCF 自动组合来自任意安全令牌类型的声明是非常重要的创新,因为这使得基于声明的授权的代码完全独立于身份验证机制。 与此相反,使用 ACL 或 ASP.NET 中的角色进行授权则与 Windows 身份验证息息相关。
安全性:机密性
通过将 IIS 中的应用程序配置为使用安全超文本传输协议 (HTTPS),可以在传输级别确保与 ASP.NET Web 服务交换的消息的机密性。 也可以对 IIS 中承载的 WCF 应用程序进行同样的配置。 但是,在 IIS 外部承载的 WCF 应用程序也可以配置为使用安全传输协议。 更重要的是,通过使用 WS-Security 协议,WCF 应用程序还可以配置为在消息传输前保护消息的安全。 如果使用 WS-Security 协议保护消息正文的安全,则消息正文到达最终目的地之前在中介中加密传输。
通过 ASP.NET 配置语言,您可以为这些服务单独指定区域性。 WCF 不支持配置设置,ASP.NET 兼容模式下除外。 若要对不使用 ASP.NET 兼容模式的 WCF 服务进行本地化,请将服务类型编译为区域性特定的程序集,并为每个区域性特定的程序集提供独立的区域性特定终结点。
基于目标和使用的标准比较 ASP.NET Web 服务与 WCF