如何:在 WAS 中承载 WCF 服务
本主题概述了创建由 Windows 进程激活服务(也称为 WAS)承载的 Windows Communication Foundation (WCF) 服务所需的基本步骤。 WAS 是新的进程激活服务,是对使用非 HTTP 传输协议的 Internet Information Services (IIS) 功能的泛化。 WCF 使用监听器适配器接口传递激活请求,这些请求是通过由 WCF 支持的非 HTTP 协议(如 TCP、命名管道和消息队列)收到的。
此主机选项要求正确安装和配置 WAS 激活组件,但不要求编写任何主机代码作为应用程序的一部分。 有关安装和配置 WAS 的详细信息,请参阅如何:安装和配置 WCF 激活组件。
警告
如果将 Web 服务器的请求处理管道设置为经典模式,则将不支持 WAS 激活。 如果要使用 WAS 激活,则必须将 Web 服务器的请求处理管道设置为集成模式。
在 WAS 中承载 WCF 服务时,可按照常规使用标准绑定。 但是,在使用 NetTcpBinding 和 NetNamedPipeBinding 配置 WAS 承载的服务时,必须满足一个约束条件。 当不同的终结点使用相同的传输时,绑定设置必须在以下的七个属性上相匹配:
ConnectionBufferSize
ChannelInitializationTimeout
MaxPendingConnections
MaxOutputDelay
MaxPendingAccepts
ConnectionPoolSettings.IdleTimeout
ConnectionPoolSettings.MaxOutboundConnectionsPerEndpoint
否则,最先初始化的终结点总是确定这些属性的值,并且以后添加的终结点若与这些设置不匹配,则将引发 ServiceActivationException。
有关此示例的源副本,请参阅 TCP 激活。
创建 WAS 承载的基本服务
为该类型的服务定义服务协定。
[ServiceContract] public interface ICalculator { [OperationContract] double Add(double n1, double n2); [OperationContract] double Subtract(double n1, double n2); [OperationContract] double Multiply(double n1, double n2); [OperationContract] double Divide(double n1, double n2); }
在服务类中实现该服务协定。 请注意,在服务的实现内部,未指定地址或绑定信息。 而且,不必编写代码也可从配置文件中检索该信息。
public class CalculatorService : ICalculator { public double Add(double n1, double n2) { return n1 + n2; } public double Subtract(double n1, double n2) { return n1 - n2; } public double Multiply(double n1, double n2) { return n1 * n2; } public double Divide(double n1, double n2) { return n1 / n2; } }
创建 Web.config 文件,以定义要由 NetTcpBinding 终结点使用的
CalculatorService
绑定。<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <netTcpBinding> <binding portSharingEnabled="true"> <security mode="None" /> </binding> </netTcpBinding> </bindings> </system.serviceModel> </configuration>
创建包含以下代码的 Service.svc 文件。
<%@ServiceHost language=c# Service="CalculatorService" %>
将 Service.svc 文件放到 IIS 虚拟目录中。
创建要使用服务的客户端
从命令行中使用 ServiceModel 元数据实用工具 (Svcutil.exe),根据服务元数据生成代码。
Svcutil.exe <service's Metadata Exchange (MEX) address or HTTP GET address>
生成的客户端包含
ICalculator
接口,该接口定义了客户端实现必须满足的服务协定。//Generated interface defining the ICalculator contract [System.ServiceModel.ServiceContractAttribute( Namespace="http://Microsoft.ServiceModel.Samples", ConfigurationName="Microsoft.ServiceModel.Samples.ICalculator")] public interface ICalculator { [System.ServiceModel.OperationContractAttribute( Action="http://Microsoft.ServiceModel.Samples/ICalculator/Add", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/AddResponse")] double Add(double n1, double n2); [System.ServiceModel.OperationContractAttribute( Action="http://Microsoft.ServiceModel.Samples/ICalculator/Subtract", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/SubtractResponse")] double Subtract(double n1, double n2); [System.ServiceModel.OperationContractAttribute( Action="http://Microsoft.ServiceModel.Samples/ICalculator/Multiply", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/MultiplyResponse")] double Multiply(double n1, double n2); [System.ServiceModel.OperationContractAttribute( Action="http://Microsoft.ServiceModel.Samples/ICalculator/Divide", ReplyAction="http://Microsoft.ServiceModel.Samples/ICalculator/DivideResponse")] double Divide(double n1, double n2); }
生成的客户端应用程序还包含
ClientCalculator
的实现。 请注意,在服务的实现内部,未指定地址和绑定信息。 而且,不必编写代码也可从配置文件中检索该信息。// Implementation of the CalculatorClient public partial class CalculatorClient : System.ServiceModel.ClientBase<Microsoft.ServiceModel.Samples.ICalculator>, Microsoft.ServiceModel.Samples.ICalculator { public CalculatorClient() { } public CalculatorClient(string endpointConfigurationName) : base(endpointConfigurationName) { } public CalculatorClient(string endpointConfigurationName, string remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public CalculatorClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : base(endpointConfigurationName, remoteAddress) { } public CalculatorClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : base(binding, remoteAddress) { } public double Add(double n1, double n2) { return base.Channel.Add(n1, n2); } public double Subtract(double n1, double n2) { return base.Channel.Subtract(n1, n2); } public double Multiply(double n1, double n2) { return base.Channel.Multiply(n1, n2); } public double Divide(double n1, double n2) { return base.Channel.Divide(n1, n2); } }
使用 NetTcpBinding 的客户端配置也通过 Svcutil.exe 生成。 在使用 Visual Studio 时,应在 App.config 文件中命名此文件。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <netTcpBinding> <binding name="NetTcpBinding_ICalculator"> <security mode="None"/> </binding> </netTcpBinding> </bindings> <client> <endpoint address="net.tcp://localhost/servicemodelsamples/service.svc" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculator" contract="ICalculator" name="NetTcpBinding_ICalculator" /> </client> </system.serviceModel> </configuration>
在应用程序中创建
ClientCalculator
的实例,然后调用服务操作。//Client implementation code. class Client { static void Main() { // Create a client with given client endpoint configuration CalculatorClient client = new CalculatorClient(); // Call the Add service operation. double value1 = 100.00D; double value2 = 15.99D; double result = client.Add(value1, value2); Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result); // Call the Subtract service operation. value1 = 145.00D; value2 = 76.54D; result = client.Subtract(value1, value2); Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result); // Call the Multiply service operation. value1 = 9.00D; value2 = 81.25D; result = client.Multiply(value1, value2); Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result); // Call the Divide service operation. value1 = 22.00D; value2 = 7.00D; result = client.Divide(value1, value2); Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result); //Closing the client gracefully closes the connection and cleans up resources client.Close(); Console.WriteLine(); Console.WriteLine("Press <ENTER> to terminate client."); Console.ReadLine(); } }
编译并运行客户端。