【问题标题】:Interesting WCF interface casting behaviour有趣的 WCF 接口转换行为
【发布时间】:2012-01-24 07:15:55
【问题描述】:

在回答另一个问题时,我遇到了一个有趣的情况 WCF 很乐意使用不同数量的成员和来自不同命名空间的接口,而普通的 .net 运行时不能。

谁能解释一下 WCF 是如何做到这一点的,以及如何配置/强制 WCF 表现得与正常的 .net 运行时相同。请注意,我知道我应该只有一个界面,等等等等等等。

这是工作代码

using System;
using System.Runtime.Serialization;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;

namespace MyClient
{
  [ServiceContract]
  public interface IService
  {
    [OperationContract]
    string Method(string dd);
    [OperationContract]
    string Method2(string dd);
  }
}

namespace MyServer
{
  [ServiceContract]
  public interface IService
  {
    [OperationContract]
    string Method(string dd);
  }
}

namespace MySpace
{
  public class Service : MyServer.IService
  {
    public string Method(string dd)
    {
      dd = dd + " String from Server.";
      return dd;
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      string Url = "http://localhost:8000/";
      Binding binding = new BasicHttpBinding();
      ServiceHost host = new ServiceHost(typeof(Service));
      host.AddServiceEndpoint(typeof(MyServer.IService), binding, Url);
      host.AddDefaultEndpoints();
      host.Open();

      // Following line gives error as it should do. 
      //MyClient.IService iservice = (MyClient.IService)new MySpace.Service(); 

      // but WCF is happy to do it ;)
      ChannelFactory<MyClient.IService> fac = new ChannelFactory<MyClient.IService>(binding);
      fac.Open();
      MyClient.IService proxy = fac.CreateChannel(new EndpointAddress(Url));


      string d = proxy.Method("String from client.");
      fac.Close();
      host.Close();
      Console.WriteLine("Result after calling \n " + d);

      Console.ReadLine();


    }
  }
}

【问题讨论】:

    标签: c# .net wcf interface casting


    【解决方案1】:

    您的 MyClient.IService 具有与 MyServer.IService 相同的方法,WCF 的通道工厂认为合同在公开的 url 上匹配,因此处理请求。

    尝试更改您的 MyClient.IService 方法名称,您会发现它失败了。正如我们所知,命名空间是逻辑分隔符。

    当您创建 WCF 服务并公开 wsdl 时,它没有任何命名空间,除非您使用端点元素中的 bindingNamespace 属性在配置中指定一个。只需尝试一个示例并从 wsdl 生成一个代理,以查看该代理没有任何命名空间。

    只要 MyClient 和 MyServer 命名空间中的 IService 与上面的 WCF 代码匹配,就可以工作

    关于您的以下代码:

    MyClient.IService iservice = (MyClient.IService)new MySpace.Service();       
    

    您正在尝试将 MySpace.Service 显式转换为 MyClient.IService ,其中您的“服务”没有实现您的 MyClient.IService 并且根据 OOP 是正确的。由于您将所有代码都放在一个文件中并且是自托管的,因此您可能会感到困惑。

    【讨论】:

    • Rajesh ,我理解您对命名空间的看法。我仍然无法理解代理类如何能够将具有一种方法的接口转换为具有两种方法的接口?
    • 你在哪里将一个方法的接口转换为两个方法的接口?
    • 我的脑海中可能有太多 Remoting 和 OOPS,如果您看到我在创建绑定 EndPoint 时使用 MyServer.IService,然后从客户端我在我的脑海中询问接口 MyClient.IService 应该抛出异常说没有从任何端点公开这样的接口
    • 如前所述,暴露的端点不会考虑您的命名空间,除非您在托管之前创建端点时指定它。在您的代码中,您使用的是 MyClient.IService ,它具有与 MyServer.IService 具有相同签名和名称的方法,因此您的代码可以工作。
    【解决方案2】:

    没有矛盾。

          // Following line gives error, as it should do, because the .NET types 
          // MyClient.IService and MySpace.Service are not related.   
          MyClient.IService iservice = (MyClient.IService)new MySpace.Service();   // ERROR !!
    
          // Likewise, a WCF client proxy defined using MyService.IService as the contract
          // cannot be cast to the unrelated .NET type MyClient.IService
          ChannelFactory<MyService.IService> fac1 = new ChannelFactory<MyService.IService>(binding); 
          fac1.Open(); 
          MyClient.IService proxy = (MyClient.IService)fac1.CreateChannel(new EndpointAddress(Url));  // ERROR !!
    
          // but the service can be consumed by any WCF client proxy for which the contract 
          // matches the defined service contract (i.e. they both expect the same XML infoset 
          // in the request and response messages). There is no dependency between the .NET type 
          // used in the client code and the .NET type used to implement the service. 
          ChannelFactory<MyClient.IService> fac = new ChannelFactory<MyClient.IService>(binding); 
          fac.Open(); 
          // Next line does not error because the ChannelFactory instance is explicitly 
          // specialised to return a MyClient.IService so the .NET type is the same... there is no cast
          MyClient.IService proxy = fac.CreateChannel(new EndpointAddress(Url)); 
          // NOTE: Thus far we have not done anything with the service in this case.
          // If we call Method() it should succeed, since the contract matches. If we call
          // Method2() the channel will fault as there is no matching operation contract in the service.
    

    .NET 类型系统与 WCF 的服务/操作/消息/数据契约概念完全不同。同样,否则您将永远无法为您自己编写的 WCF 服务编写 WCF 客户端。

    但是,如中间示例所示,如果您在服务和客户端代码中为服务合同重用 .NET 类型,您的期望将会得到满足。

    【讨论】:

    • 克里斯,你能解释一下吗“// 但是该服务可以被任何 WCF 客户端代理使用,其合同//与定义的服务合同相匹配(即它们都期望相同的 XML 信息集 // 在请求和响应消息)。”
    • 合约如何以及为什么匹配两者具有不同的方法集?
    • 我应该说“合同与定义的操作合同相匹配”。服务器堆栈对客户端堆栈如何构造其请求消息一无所知 - 因此不知道客户端已使用包含额外方法的接口来构造其客户端通道运行时。服务看到的只是“方法”操作的请求信息集,在其服务合同下是有效的,因此它会愉快地响应。
    猜你喜欢
    • 2016-12-04
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    • 2013-08-25
    • 2017-02-07
    • 2010-11-26
    • 1970-01-01
    相关资源
    最近更新 更多