WCF - DataContract 继承

DataContract 支持继承方式,但和我们前面所提到的 ServiceContract 一样,有点小小的问题。看下面的例子。

(为显示方便,以下代码有删减。)

[DataContract]
public class Data
{
  [DataMember]
  public int X;
}

[DataContract]
public class Data2 : Data
{
  [DataMember]
  public int Y;
}

[ServiceContract]
public interface IMyService
{
  [OperationContract]
  void Test(Data d);
}


客户端代理

//------------------------------------------------------------------------------
// <auto-generated>
//   此代码由工具生成。
//   运行库版本:2.0.50727.42
//
//   对此文件的更改可能会导致不正确的行为,并且如果
//   重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------

namespace ConsoleApplication1.localhost
{
  [GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [DataContractAttribute(Namespace = "...")]
  [SerializableAttribute()]
  public partial class Data : object, IExtensibleDataObject
  {
  }
}


从 客户端生成的代码来看,我们显然不能使用 Data2。怎样才能使用 Data2 呢?将契约 IMyService 的 Test 方法参数改成 "Data2 d"?当然不行,这样一来 Data 就不能用了,更不要说什么多态了。这时候就要使用另外一个特性 —— ServiceKnownTypeAttribute。继续看我们修改后的代码。

[DataContract]
public class Data
{
  [DataMember]
  public int X;
}

[DataContract]
public class Data2 : Data
{
  [DataMember]
  public int Y;
}

[ServiceContract]
[ServiceKnownType(typeof(Data2))]
public interface IMyService
{
  [OperationContract]
  void Test(Data d);
}


客户端代理

//------------------------------------------------------------------------------
// <auto-generated>
//   此代码由工具生成。
//   运行库版本:2.0.50727.42
//
//   对此文件的更改可能会导致不正确的行为,并且如果
//   重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------

namespace ConsoleApplication1.localhost
{
  [GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [DataContractAttribute(Namespace = "...")]
  [SerializableAttribute()]
  [KnownTypeAttribute(typeof(Data2))]
  public partial class Data : object, IExtensibleDataObject
  {
  }

  [GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [DataContractAttribute(Namespace = "...")]
  [SerializableAttribute()]
  public partial class Data2 : Data
  {
  }
}


非常好,Data2 出现了,而且它也继承自 Data,我们写个完整的例子,看看是否是我们所设想的多态。

服务器端代码

[DataContract]
public class Data
{
  [DataMember]
  public int X;
}

[DataContract]
public class Data2 : Data
{
  [DataMember]
  public int Y;
}

[ServiceContract]
[ServiceKnownType(typeof(Data2))]
public interface IMyService
{
  [OperationContract]
  void Test(Data d);
}

public class MyServie : IMyService
{
  public void Test(Data d)
  {
    Console.WriteLine(d.GetType());
    Console.WriteLine(d.X);
    Console.WriteLine((d as Data2).Y);
  }
}


客户端代码

using (MyServiceClient client = new MyServiceClient())
{
  Data2 d = new Data2();
  d.X = 1234;
  d.Y = 5678;

  client.Test(d);
}


执行后服务器端输出:
Data2
1234
5678

ServiceKnownTypeAttribute 还可以直接用在 Method 上,另外还要注意我们将 ServiceKnownTypeAttribute 放在服务契约上,而不是其他什么地方。

[AttributeUsage(AttributeTargets.Interface|
  AttributeTargets.Method |
  AttributeTargets.Class,
  AllowMultiple = true)]
public sealed class ServiceKnownTypeAttribute : Attribute
{
}


相应地,我们还可以直接在配置文件中添加 ServiceKnownTypeAttribute,这样可以避免修改服务器端代码(也许吧?前提是 Data2 要放到另外一个程序集中)。

看另外一种情形。

public interface IData
{
  int X { get; set; }
}

[DataContract]
public class Data : IData
{
  private int x;

  [DataMember]
  public int X
  {
    get { return x; }
    set { x = value; }
  }
}

[ServiceContract]
public interface IMyService
{
  [OperationContract]
  void Test(IData d);
}


麻烦依旧,看看自动生成的客户端代理。

//------------------------------------------------------------------------------
// <auto-generated>
//   此代码由工具生成。
//   运行库版本:2.0.50727.42
//
//   对此文件的更改可能会导致不正确的行为,并且如果
//   重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------

namespace ConsoleApplication1.localhost
{
  [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  [ServiceContractAttribute(ConfigurationName = "ConsoleApplication1.localhost.IMyService")]
  public interface IMyService
  {
    [OperationContractAttribute(Action = "http://tempuri.org/IMyService/Test", ReplyAction = "...")]
    void Test(object d);
  }

  [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  public interface IMyServiceChannel : IMyService, IClientChannel
  {
  }

  [DebuggerStepThroughAttribute()]
  [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  public partial class MyServiceClient : ClientBase<IMyService>, IMyService
  {
    public void Test(object d)
    {
      base.Channel.Test(d);
    }
  }
}


没有 IData,没有 Data,取而代之的是 object。这意味着很大的麻烦,不是吗?还是让 ServiceKnownTypeAttribute 出来吧。

[ServiceContract]
public interface IMyService
{
  [OperationContract]
  [ServiceKnownType(typeof(Data))]
  void Test(IData d);
}


更 新后的客户端代理虽然出现了 Data,但 IData 依然不见踪影,Test 方法参数依然是 "object d"。查阅了 MSDN 的一些说明,原因可能是 "the interface itself will not be included in the exported metadata"。不过这并不妨碍我们调用服务,看来 DataContract 不支持 Interface 也是有些原因的。

//------------------------------------------------------------------------------
// <auto-generated>
//   此代码由工具生成。
//   运行库版本:2.0.50727.42
//
//   对此文件的更改可能会导致不正确的行为,并且如果
//   重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------

namespace ConsoleApplication1.localhost
{
  [GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
  [DataContractAttribute(Namespace = "...")]
  [SerializableAttribute()]
  public partial class Data : object, IExtensibleDataObject
  {
  }

  [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  [ServiceContractAttribute(ConfigurationName = "ConsoleApplication1.localhost.IMyService")]
  public interface IMyService
  {
    [OperationContractAttribute(Action = "http://tempuri.org/IMyService/Test", ReplyAction = "...")]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(ConsoleApplication1.localhost.Data))]
    void Test(object d);
  }

  [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  public interface IMyServiceChannel : IMyService, IClientChannel
  {
  }

  [DebuggerStepThroughAttribute()]
  [GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
  public partial class MyServiceClient : ClientBase<IMyService>, IMyService
  {
    public void Test(object d)
    {
      base.Channel.Test(d);
    }
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值