有趣的WCF界面转换行为

时间:2011-12-20 09:46:53

标签: c# .net wcf interface casting

在回答另一个问题时,我碰到了这个有趣的情况,其中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();


    }
  }
}

2 个答案:

答案 0 :(得分:3)

没有不一致。

      // 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类型,则会满足您的期望。

答案 1 :(得分:2)

您的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是正确的。由于您将所有代码都放在一个文件中并且自托管可能会让您感到困惑。

相关问题