WCF之契约

以下是WCF常用的三种契约,

服务契约:服务契约描述服务所实现的功能操作。服务契约将.NET类型中的元素映射到WSDL元素。服务契约中的操作契约描述了实现服务功能的方法。

数据契约:数据契约描述了服务端与客户端通讯时使用的数据结构。数据契约将CLR数据类型映射到XML模式定义(XML Schema Definition,XSD),并定义如何对其进行序列化和反序列化。

消息契约:消息契约将CLR类型映射成SOAP消息,描述SOAP消息的格式,并影响这些消息的WSDL和XSD定义。消息契约可以精确地控制SOAP信头和信体。

下面以水果类为例,写一些简单的代码,来演示下契约

服务契约:

using System.ServiceModel;
using FruitModel;
namespace IFruitPrice
{
[ServiceContract(Namespace
= "http://www.cnblogs.com/qiuwuyu")]
public interface IFruitPriceService
{
[OperationContract]
Fruit GetFruit();
}
}

服务端实现:

using FruitModel;
using IFruitPrice;
namespace FruitPrice
{
public class FruitPriceService : IFruitPriceService
{
public Fruit GetFruit()
{
Fruit f
= new Fruit();
f.Name
= "banana";
f.Price
= "6.00";
return f;
}
}
}

数据契约:

using System.ServiceModel;
using System.Runtime.Serialization;
namespace FruitModel
{
[DataContract]
public class Fruit
{
[DataMember]
private string m_Name;
[DataMember]
private string m_Price;

public string Name
{
get
{
return m_Name;
}
set
{
m_Name
= value;
}
}
public string Price
{
get
{
return m_Price;
}
set
{
m_Price
= value;
}
}
}
}

寄存服务:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using FruitPrice;
using IFruitPrice;

namespace WcfFruitHost
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(FruitPriceService),
new Uri("http://localhost:8000/Fruit")))
{
host.AddServiceEndpoint(
typeof(IFruitPriceService), new BasicHttpBinding(), "FruitService");

ServiceMetadataBehavior behavior
= new ServiceMetadataBehavior();
behavior.HttpGetEnabled
= true;
host.Description.Behaviors.Add(behavior);
host.AddServiceEndpoint(
typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");

host.Open();
Console.WriteLine(
"Fruit Service Is Running...");
Console.ReadLine();
}
}
}
}

客户端调用:

using System;
using System.ServiceModel;
using IFruitPrice;
using FruitModel;

namespace WcfFruitClient
{
class Program
{
static void Main(string[] args)
{
EndpointAddress epAddr
= new EndpointAddress("http://localhost:8000/Fruit/FruitService");
IFruitPriceService proxy
= ChannelFactory<IFruitPriceService>.CreateChannel(new BasicHttpBinding(), epAddr);
Console.WriteLine(
"Name:" + proxy.GetFruit().Name + " Price:" + proxy.GetFruit().Price);
Console.WriteLine(
"Fruit Client Is Running...");
Console.ReadLine();
}
}
}

程序执行结果如下:

生成的WSDL如下:

下面是为数据契约生成的XSD:

修改一下代码,演示消息契约

数据契约通过XSD标准来达成互通性,消息契约则可以与任何通过SOAP通信的系统互通。消息契约可以直接访问SOAP的消息头和消息体,从而可以完全掌控服务所收发的SOAP消息。所以需要精确定义SOAP各部分内容时可以从DataContract 转用MessageContract。

修改数据契约为消息契约

using System.ServiceModel;
using System.Runtime.Serialization;
namespace FruitModel
{
[MessageContract(WrapperNamespace
= "http://www.cnblogs.com/qiuwuyu")]
public class FruitKey
{
[MessageHeader]
private string m_Key;
public string Key
{
get
{
return m_Key;
}
set
{
m_Key
= value;
}
}
}
[MessageContract(WrapperNamespace
= "http://www.cnblogs.com/qiuwuyu")]
public class Fruit
{
[MessageBodyMember]
private string m_Name;
[MessageBodyMember]
private string m_Price;

public string Name
{
get
{
return m_Name;
}
set
{
m_Name
= value;
}
}
public string Price
{
get
{
return m_Price;
}
set
{
m_Price
= value;
}
}
}
}

增加一个类做为消息头,可以添加一些安全验证信息。

修改服务契约传递参数

using System.ServiceModel;
using FruitModel;
namespace IFruitPrice
{
[ServiceContract(Namespace
= "http://www.cnblogs.com/qiuwuyu")]
public interface IFruitPriceService
{
[OperationContract]
Fruit GetFruit(FruitKey key);
}
}

修改服务实现

using FruitModel;
using IFruitPrice;
using System.ServiceModel;
namespace FruitPrice
{
public class FruitPriceService : IFruitPriceService
{
public Fruit GetFruit(FruitKey key)
{
if (!key.Key.Equals( "wcf"))
{
throw new FaultException("Invalid Key");
}
Fruit f
= new Fruit();
f.Name
= "banana";
f.Price
= "6.00";
return f;
}
}
}

修改客户端调用

using System;
using System.ServiceModel;
using IFruitPrice;
using FruitModel;

namespace WcfFruitClient
{
class Program
{
static void Main(string[] args)
{
EndpointAddress epAddr
= new EndpointAddress("http://localhost:8000/Fruit/FruitService");
IFruitPriceService proxy
= ChannelFactory<IFruitPriceService>.CreateChannel(new BasicHttpBinding(), epAddr);
FruitKey key
= new FruitKey();
key.Key
= "w";
Fruit f
=null;
try
{
f
= proxy.GetFruit(key);
}
catch (Exception ex)
{
f
=null;
Console.WriteLine(ex.Message);
}
if (f != null)
{
Console.WriteLine(
"Name:" + f.Name + " Price:" + f.Price);
}
Console.WriteLine(
"Fruit Client Is Running...");
Console.ReadLine();
}
}
}

传入一个错误的key ,运行结果

把key改为wcf后,运行结果

如果想看数据契约和消息契约生成的元数据有何不同,可以用SvcUtil.exe工具查看,用如下命令

posted @ 2011-04-08 08:14  秋无语  阅读(...)  评论(... 编辑 收藏