Интересное поведение приведения интерфейса WCF - PullRequest
0 голосов
/ 20 декабря 2011

Отвечая на другой вопрос, я столкнулся с этой интересной ситуацией, когда 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 ]

3 голосов
/ 20 декабря 2011

Нет противоречий.

      // 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 для контракта на обслуживание как в коде сервиса, так и в коде клиента, ваши ожидания оправдаются.

2 голосов
/ 20 декабря 2011

В MyClient.IService используется тот же метод, что и в MyServer.IService. Фабрика каналов WCF считает, что контракт соответствует указанному URL, и, следовательно, обрабатывает запрос.

Попробуйте изменить имя метода MyClient.IService, и вы увидите, что оно не работает. Пространство имен - это логические разделения, как мы знаем.

Когда вы создаете службу WCF и выставляете wsdl, у него нет ни одного из ваших пространств имен, если только вы не укажете одно из них в своей конфигурации, используя атрибут bindingNamespace в своем элементе конечной точки. Просто попробуйте пример и сгенерируйте прокси из wsdl, чтобы увидеть, что прокси не имеет пространства имен.

Пока IService в вашем пространстве имен MyClient и MyServer совпадает с указанным выше кодом WCF, будет работать

В отношении вашего кода ниже:

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

Вы пытаетесь явным образом привести MySpace.Service к MyClient.IService, где ваша «Служба» не реализует ваш MyClient.IService и является правильной в соответствии с ООП. Поскольку у вас есть весь код в одном файле и он размещен самостоятельно, это может ввести вас в заблуждение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...