【问题标题】:Why does refactoring a server interface break the client proxy contract?为什么重构服务器接口会破坏客户端代理合约?
【发布时间】:2016-11-25 03:32:51
【问题描述】:

我有一个现有的 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 必须忍受的事情(所以我们需要重新生成任何现有客户端的代理)?

【问题讨论】:

  • 尝试查看代理重新生成前后自动生成的代码中的内容。
  • 合约接口

标签: c# .net wcf


【解决方案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。我有自己的,更简单的实现,我会尽快分享。)

【讨论】:

  • 考虑添加评论反对投票(用于论证)
  • 你是在暗示一个答案,但没有直接回答这个问题。请展示如何“基于您的服务合同的客户端代理代码”
  • 这不是一个问题,它被多次讨论过,但我已经在答案中添加了这个。
猜你喜欢
  • 2021-11-15
  • 1970-01-01
  • 1970-01-01
  • 2012-09-15
  • 2011-03-06
  • 1970-01-01
  • 2013-12-04
  • 1970-01-01
  • 2021-05-27
相关资源
最近更新 更多