WCF基础:创建、托管和消费,并处理SOAP错误
一个创建WCF服务、在托管代码应用程序中托管它并在另一个应用程序中消费它的示例
引言
在.NET Framework 3.0之前,微软发布了许多用于开发网络分布式服务的技术和平台,包括Web Services (ASMX)、Web Service Enhancement (WSE)、Enterprise Services (COM+)、Microsoft Message Queue (MSMQ)和Remoting。为了一个目的而有太多的技术会导致在开发软件系统时需要考虑太多的因素。并且由于它们有不同的开发模型,所以几乎不可能在技术之间进行切换。
Windows Communication Foundation (WCF) 是下一代用于构建网络分布式服务的编程平台。它随.NET Framework 3.0一起发布,与Windows Presentation Foundation (WPF)、Windows Workflow Foundation (WF)和Windows CardSpace同属于一个系列。
WCF提供了一个单一的编程模型,统一了ASMX、WSE、Enterprise Services、MSMQ和Remoting的功能。开发者现在只需要精通一种编程模型。
WCF实现
WCF服务包含三个关键的必做之事:
- 定义契约(服务契约、操作契约和数据契约)并实现它们。
- 定义一个服务绑定,该绑定配置传输、安全等设置...
- 通过将服务契约绑定到一个地址(终结点)来托管服务。
本示例实现了一个服务,该服务公开了一个允许客户端注册带有用户名和用户地址的账户的方法。用户名必须是大写字母并且至少包含6个字符。用户地址是可选的。注册成功后,客户端会收到一个具有新分配的令牌和用户信息たプロファイル对象。
这个例子非常简单,但它演示了创建WCF服务、SOAP错误处理、托管和使用。
Using the Code
创建服务项目
名称:RegisterService
项目模板:WCF 服务库
名称:RegisterServiceHost
项目模板:控制台应用程序
定义契约
服务合同
-
服务契约定义了服务在终结点上可用的一组操作,并向外界公开。
-
使用
ServiceContract
属性将接口或类定义为服务契约。
操作契约
-
操作契约是服务契约中的一个方法,该方法被标记为操作契约。
-
默认情况下,服务契约的
public
方法不会作为服务操作公开。要使一个方法在服务的终结点可用,我们需要用ServiceOperation
属性标记该方法。[ServiceContract()] namespace DemoServices { [ServiceContract()] public interface IRegisterService { [OperationContract] [FaultContract(typeof(RegisterFault))] Profile Register(Profile newProfile); } }
错误合同
-
在托管应用程序中,错误通过Exception对象处理,但在SOAP应用程序中,错误是通过SOAP Faults来通信的。服务器端的异常会在发送到客户端之前被转换为SOAP Faults。
-
方法的
FaultContract
属性指定该方法的自定义SOAP Fault类型。
数据合同
-
数据契约描述了要交换的数据。
-
通过用
DataContract
属性标记类来定义数据契约。
数据成员
-
DataMember
属性定义了数据契约内部哪些数据将被交换。namespace DemoServices { /// <summary> /// Represents for a user profile /// </summary> [DataContract] public class Profile { private string _name; private string _address; private string _token; [DataMember] public string Name { get { return _name; } set { _name = value; } } [DataMember] public string Address { get { return _address; } set { _address = value; } } [DataMember] public string Token { get { return _token; } set { _token = value; } } } }
服务实现
namespace DemoServices
{
public class RegisterService: IRegisterService
{
#region IRegisterService Members
public Profile Register(Profile newProfile)
{
ValidateProfile(newProfile);
newProfile.Token = Guid.NewGuid().ToString();
return newProfile;
}
private static void ValidateProfile(Profile profile)
{
if (profile.Name.Length < 6)
{
throw new FaultException<registerfault>(
new RegisterFault(1, "Name must has at least 6 characters"));
}
if (!Regex.IsMatch(profile.Name, "^[A-Z]*$"))
{
throw new FaultException<registerfault>(
new RegisterFault(2, "Name must contain capital alphabets only"));
}
}
#endregion
}
}
</registerfault>
托管
托管WCF服务有很多选项,包括IIS、托管代码、Windows Service和WAS (Windows Process Activation Service)。
为了简单演示,我将讨论IIS托管和托管代码(使用控制台应用程序)托管。
IIS 托管
-
创建一个Web应用程序(或虚拟目录)。
-
将服务的输出DLL复制到创建的Web应用程序的bin文件夹中。
-
创建一个*.svc文件来公开WCF服务。
<% @ServiceHost Service="MyNamespace.MyServiceImplementationTypeName" %> <%@Assembly Name="MyAssemblyName" %> Ex: RegisterService.svc <% @ServiceHost Service="DemoServices.RegisterService" %> <%@Assembly Name="RegisterService" %>
-
在web.config中为服务定义终结点。
<system.serviceModel> <services> <service name="DemoServices.RegisterService" behaviorConfiguration="RegisterServiceBehavior"> <endpoint address="RegisterService" binding="basicHttpBinding" contract="DemoServices.IRegisterService" /> </service> </services> <behaviors> <behavior name="RegisterServiceBehavior"> <serviceMetadata httpGetEnabled="true" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
现在,您可以为您的应用程序添加服务引用。服务URL应该是:
[your web application url][/your virtual directory]/RegisterService.svc
托管代码应用程序托管
在IIS上托管WCF服务的限制是只允许HTTP通信。对于其他协议,如TCP、namepipe等,我们需要在托管代码应用程序、Windows服务或WAS中托管WCF服务。
在本文中,我使用了一个控制台应用程序来托管Register服务。
这是控制台应用程序的配置文件的内容。它表明我们将使用TCP协议托管服务,并允许客户端使用元数据交换来生成服务代理。
<system.serviceModel>
<services>
<service name="DemoServices.RegisterService"
behaviorConfiguration="RegisterServiceBehavior">
<endpoint address="net.tcp://:12347/RegisterService"
binding="netTcpBinding"
contract="DemoServices.IRegisterService" />
<endpoint address="https://:12348/RegisterService/mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="RegisterServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="True"/>
<serviceMetadata/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
完成以上步骤后,运行您的宿主应用程序以使服务激活。
消费服务
-
创建一个控制台应用程序。
-
为您的项目添加服务引用,服务URI应该是:https://:12348/RegisterService/mex(如上配置),并给它一个名称,例如
WCFRegisterService
。
将此示例代码添加到消费Register服务并自定义SOAP错误处理。
static void Main(string[] args)
{
WCFRegisterService.RegisterServiceClient client =
new WCFRegisterService.RegisterServiceClient();
WCFRegisterService.Profile newProfile = new WCFRegisterService.Profile();
newProfile.Name = "MYNAME";
newProfile.Address = "My Address";
WCFRegisterService.Profile result;
try
{
result = client.Register(newProfile);
Console.WriteLine("New token: {0}", result.Token);
client.Close();
}
catch (FaultException<WCFRegisterService.registerfault> fault)
{
Console.WriteLine("Register error code: {0}", fault.Detail.ErrorCode);
Console.WriteLine
("Register error message: {0}", fault.Detail.Message);
client.Abort();
}
catch(Exception ex)
{
Console.WriteLine("General exception: {0}", ex.Message);
client.Abort();
}
Console.ReadLine();
}
关注点
正如您所见,使用WCF开发面向服务的应用程序相当容易。开发者只需要学习WCF,就可以在不改变代码的情况下以多种方式开发和托管他们的服务。