WCF - DataContract 继承
发布日期:2021-06-29 03:54:10 浏览次数:2 分类:技术文章

本文共 5971 字,大约阅读时间需要 19 分钟。

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);
    }
  }
}

转载地址:https://blog.csdn.net/zengjibing/article/details/3812388 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:WCF - 版本问题
下一篇:WCF - DataContractSerializer

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月02日 06时01分07秒