WCF版本相容性:指WCF的服务端在更新为新版本的情况下,客户端对服务端的引用不进行更新到最新的服务端,而继续引用旧的服务端但不发性异常。WCF契约缺省是提供版本相容性支持的,所有的服务契约,数据契约与消息契约,都允许缺失、非必需(non-required)的数据存在;且可以忽略多余的数据;DataContractSerializer提供相容性支持;适当的变化并不会对现存的客户端或者服务端产生影响。
开发环境:Visual Studio 2010 + Net Framework 4.0 。
服务契约的变化对客户端产生的影响如下:
服务契约的变化 |
对现存客户端的影响 |
在操作签名上添加新的参数 |
客户端不会被影响 新的参数在服务中被初始化为缺省值 |
从操作签名中删除参数 |
客户端不会被影响 客户端传递的多余参数将被忽略,这些数据在服务端被丢失 |
修改参数类型 |
如果从客户端进入的类型无法转换为参数的数据类型,将会抛出异常 |
修改返回数值的类型 |
如果从服务端返回的值无法转换为在客户端操作签名中所期望的数据类型,那么将会抛出异常 |
添加新的操作 |
客户端不会被影响 由于客户端不知道新加入操作的存在,因此其不会被调用 |
删除操作 |
抛出异常 客户端发送给服务端的消息会被认为使用了未知的action头 |
数据契约为变化对客户端产生的影响如下:
数据契约的变化 |
对现存客户端的影响 |
添加新的non-required成员 |
客户端不会被影响 缺少的数值将会被初始化为缺省值 |
添加新的required成员 |
对于缺少的值,将会抛出异常 |
删除non-required成员 |
服务端数据丢失 无法将全部数据集返回给客户端 不会抛出异常 |
删除required成员 |
当客户端收到来自服务端带有缺失数据的响应时,将会抛出异常 |
修改已存的成员的数据类型 |
如果类型兼容,那么不会产生异常,但是可能会导致未知的结果 |
下面通过DEMO来演示服务端数据契约的变化对现存客户端的影响:
1、新增一个WCF Service Library程序,修改解决方案名称为ContractVersion,修改项目名称为ExplicitContract,删除自动添加的文件。
2、新建Item.cs类,代码如下:
[DataContract(Name = "ItemContract", Namespace = "http://schemas.xinhaijulan.com/demos/ExplicitContract")]
public class Item
{
[DataMember(Name = "IdContract", IsRequired = true, Order = 0)]
public int Id { get; set; }
[DataMember(Name = "NameContract", IsRequired = true, Order = 1)]
public string Name { get; set; }
[DataMember(Name = "MessageContract", IsRequired = true, Order = 2)]
public string Message { get; set; }
/*
/// <summary>
/// 使用IsRequired = true :重新生成服务端代码,客户端不更新服务,则会引发异常
/// 使用IsRequired = false:重新生成服务端代码,客户端不更新服务,则不会引发异常
/// </summary>
[DataMember(Name = "CreateDateContract", IsRequired = true, Order = 3)]
//[DataMember(Name = "CreateDateContract", IsRequired = false, Order = 3)]
public DateTime CreateDate { get; set; }
*/
}
注意注释部分。
3、创建服务接口文件IExplicitService.cs,代码如下:
[ServiceContract(Name = "ExplicitServiceContract", Namespace = "http://schemas.xinhaijulan.com/demos/ExplicitContract")]
public interface IExplicitService
{
[OperationContract(Name = "SaveItemContract")]
void SaveItem(Item item);
[OperationContract(Name = "GetItemContract")]
Item GetItem();
}
4、创建ExplicitService.cs类文件,代码如下:
public class ExplicitService : IExplicitService
{
private Item _item;
public void SaveItem(Item item)
{
this._item = item;
}
public Item GetItem()
{
this._item.Message = "IExplicitService.GetItem() invoked.";
return this._item;
}
}
5、修改App.config中的服务名称 、端点契约、服务地址,代码如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="ExplicitContract.ExplicitService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8732/Design_Time_Addresses/ExplicitContract/ExplicitService/" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="wsHttpBinding" contract="ExplicitContract.IExplicitService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
6、创建客户端控制台程序Client,添加Service Reference,修改名称空间为TestExplicitContract,并添加测试TestExplicitContract方法,代码如下:
class Program
{
static void Main(string[] args)
{
TestExplicitContract();
}
private static void TestExplicitContract()
{
Console.WriteLine("-----------------Test ExplicitContract Begin-----------------");
ExplicitContract.ExplicitServiceContractClient client = new ExplicitContract.ExplicitServiceContractClient();
//ExplicitDataContract
ExplicitContract.ItemContract item = null;
string readValue = "";
Console.WriteLine("Input exit to close the client, others continue.");
readValue = Console.ReadLine();
while (readValue != "exit")
{
//ExplicitDataContract
item = new ExplicitContract.ItemContract();
Console.WriteLine("Please input the id:");
item.IdContract = GetInt(Console.ReadLine());
Console.WriteLine("You have input item.IdContract:{0}", item.IdContract);
Console.WriteLine("Please input the name:");
item.NameContract = Console.ReadLine();
Console.WriteLine("You have input item.NameContract:{0}", item.NameContract);
//ExplicitServiceContract
client.SaveItemContract(item);
//ExplicitServiceContract
item = client.GetItemContract();
if (item != null)
{
Console.WriteLine(" ");
Console.WriteLine("Get from server item.IdContract is : {0}", item.IdContract);
Console.WriteLine("Get from server item.NameContract is : {0}", item.NameContract);
Console.WriteLine("Get from server item.MessageContract is : {0}", item.MessageContract);
}
Console.WriteLine("----------------------------------------------");
Console.WriteLine("Input exit to close the client, others continue.");
readValue = Console.ReadLine();
}
client.Close();
Console.WriteLine("-----------------Test ExplicitContract End-----------------");
}
private static int GetInt(object obj)
{
int i = 0;
if (obj != null)
{
int.TryParse(obj.ToString(), out i);
}
return i;
}
}
7、设置Client为启动项目,运行调试ExplicitContract程序,然后,将在控制台看到如下输出:
-----------------Test ExplicitContract Begin-----------------
Input exit to close the client, others continue.
Please input the id:
88
You have input item.IdContract:88
Please input the name:
xinhaijulan
You have input item.NameContract:xinhaijulan
Get from server item.IdContract is : 88
Get from server item.NameContract is : xinhaijulan
Get from server item.MessageContract is : IExplicitService.GetItem() invoked.
----------------------------------------------
Input exit to close the client, others continue.
8、修改Item.cs中的代码,把注释去掉,新增属性:CreateDate,且使用IsRequired=true,重新生成服务端ExplicitContract项目,不更新客户端Service Reference,设置Client为启动项目,运行调试ExplicitContract程序,然后,将看到如下异常:
9、修改Item.cs中的代码,把注释去掉,新增属性:CreateDate,且使用IsRequired=false,重新生成服务端ExplicitContract项目,不更新客户端Service Reference,设置Client为启动项目,运行调试ExplicitContract程序,然后,程序将正常运行,客户端输出同第7步。
至此,WCF契约版本管理—版本相容性介绍完毕,下一章,我们将介绍IExtensibleDataObject对数据契约的变化产生的影响。
作者:心海巨澜
出处:http://xinhaijulan.cnblogs.com
版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。