WCF:为什么重构服务器接口会破坏客户端代理合同?

时间:2016-11-25 03:32:51

标签: c# .net wcf

我有一个现有的WCF Web服务,它使用类似

的界面
 [ServiceContract]
  public interface IMyWebServices
  {    
    [OperationContract]
    bool MethodA();

    [OperationContract]
    bool MethodB();
  }

然后执行...

public class MyWebServices : IMyWebServices
{
  public bool MethodA(){...}
  public bool MethodB(){...}
 }

我有一个客户端,我生成了一个代理,一切都很好。

稍后,此服务中的数量或操作会增加。因此,通过实现,我将所有代码分解到其他类中并将它们注入主类。

[ServiceContract]
   public interface IMyWebServices : IServices1, IServices2
   {            
   }

   [ServiceContract]
   public interface IServices1
   {            
     [OperationContract]
      bool MethodA();
   }

   [ServiceContract]
   public interface IServices2
   {            
     [OperationContract]
     bool MethodB();
   }

   public class MyWebServices : IMyWebServices
    {
      private IServices1 _s1;
      private IServices2 _s2;
      public MyWebServices(IServices1, s1, IServices2, s2)
      {
          _s1 = s1;
          _s2 = s2;
      }

      public bool MethodA()
      {
          return _s1.MethodA()
      }
      public bool MethodB()
      {
            return _s2.MethodB()
      }
     }

现在的问题是,如果部署了新服务,现有的已部署客户端(因此没有代理重新生成)现在将收到错误。事件虽然合同完全相同但我得到的错误是

由于EndpointDispatcher上的ContractFilter不匹配,

...无法在接收方处理。这可能是由于合同不匹配(发送方与接收方之间的操作不匹配)或发送方与接收方之间的绑定/安全性不匹配。检查发件人和收件人是否具有相同的合同和相同的约束(包括安全要求,例如邮件,传输,无)。

所以看起来你不能对服务器端接口进行任何重构。

有没有办法(为了将来的重构),或者这只是我们必须使用WCF生活的东西(所以我们需要重新复制任何现有客户端的代理)?

提前感谢任何信息。

1 个答案:

答案 0 :(得分:1)

Svcutil生成的服务客户端代理基于服务元数据。因此,修改服务端签名可能会导致新的wsdl和损坏的客户端(基于旧的服务元数据)。这是不使用(自动)生成的客户端代理代码的另一个原因。通过一些努力,您可以根据您的服务合同(仅在单独的程序集中为服务客户端共享它)和ChannelFactory(...)创建自己的代码(更易于管理).CreateChannel()。这种方式会对你有所帮助。服务合同重构将有客户端代码反映。

WSHttpBinding myBinding = new WSHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress("http://localhost:8000/MyService.svc");
ChannelFactory<IMyService> myChannelFactory = new ChannelFactory<IMyService>(myBinding, myEndpoint);
IMyService instance = myChannelFactory.CreateChannel();            
var result = instance.MyMethod(...);

ChannelFactory<IMyService> myChannelFactory = new ChannelFactory<IMyService>("WSHttpBinding_IMyService");

其中“WSHttpBinding_IMyService”是客户端绑定配置名称:

<system.serviceModel>
            <bindings>
                <wsHttpBinding>
                    <binding name=”WSHttpBinding_IMyService” />
                </wsHttpBinding>
            </bindings>
            <client>
                 <endpoint address=”http://localhost:8000/MyService.svc”
                                  binding=”wsHttpBinding”
                                  bindingConfiguration=”WSHttpBinding_IMyService”
                                  contract=”MyService.IMyService”
                                  name=”WSHttpBinding_IMyService”>
                 </endpoint>
             </client>
  </system.serviceModel>

通过一些额外的工作,您甚至可以通过了解和使用简单的同步服务接口来异步调用服务方法! (您可以找到通用服务客户端代码,例如here。我有自己的更简单的实现,我将尽快分享。)