WCF и насмешливый - PullRequest
       44

WCF и насмешливый

1 голос
/ 01 ноября 2010

Я неопытный, когда дело доходит до WCF, и я не могу найти безболезненный способ издеваться над сервисами WCF.

Ситуация: клиент и сервер, которые оба имеют доступ к интерфейсу, определяющему сервис, например:

public interface ICustomerService
{
  [OperationContract]
  Customer GetCustomer(int id);
}

Теперь мой первый вопрос, если есть причина, по которой вы не захотитеЯ хочу, чтобы клиент и сервер использовали один и тот же тип интерфейса, который определяет службу в общей библиотеке.Конечно, это просто невозможно, если пользователи сервиса не являются .NET или вы предоставляете его третьим лицам, у которых нет библиотеки, но я делюсь ею, когда она равна возможность не повредит этим другим сценариям, верно?

Во-вторых, если это неплохая идея, как я могу заставить Visual Studio повторно использовать интерфейс службы?Мне удалось заставить его разделить тип Customer, проверив Re-use types, который также определен в общей сборке, но все равно заново генерирует интерфейс.

Но, независимо от этих проблем, как мне сделать клиента насмешливым?Если я пройду через сгенерированные сервисные ссылки VS, я получу конкретный тип для работы, но я не хочу, чтобы мой код когда-либо ссылался на этот тип напрямую, я хотел бы поговорить с интерфейсом.Если я предоставляю сгенерированный клиент как ICustomerService, который работает, у меня нет метода Close, так как интерфейс не определяет его.

Я также подумал о следующем подходе и полностью отказался от автоматически генерируемого клиента и просто написал клиент сам, как это тривиально:

public interface IServiceClient<T>
{
    void Close();
    T Services { get; }
}

public class CustomerServiceClient : ClientBase<ICustomerService>, ICustomerService, IServiceClient<ICustomerService>
{
    public Customer GetCustomer(int id)
    {
        return base.Channel.GetCustomer(id);
    }

    public ICustomerService Services
    {
        get { return this; }
    }
}

Это работает, и я могу выставить его как IServiceClient<ICustomerService> к моему контейнеру IoC, но с оговоркой, что теперь он client.Services.GetCustomer(1) и что я потерял преимущество в том, что легко перегенерировал моего клиента при изменении интерфейса ICustomerService.Это простой код, который нужно добавить, но он все еще может раздражать.

Другая возможность заключается в использовании того факта, что сгенерированный класс имеет значение partial.Это также работает, когда я делаю это:

interface ICloseable
{
  void Close();
}

interface ClientInterface : ICustomerService, ICloseable
{
}

partial class CustomerServiceClient : IClientInterface
{

}

Но это создало фиктивный класс и интерфейс, который не является катастрофой, но не очень красив.

Прежде чем идти по какому-либо маршруту, есть ли что-то очевидное, что я упустил из виду?

Ответы [ 4 ]

2 голосов
/ 03 ноября 2010

Вы пробовали Ninject.Extension.Wcf? Существует пример того, как внедрить службы WCF, а также показано, как их закрывать.

https://github.com/ninject/ninject.extensions.wcf

http://teamcity.codebetter.com/project.html?projectId=project3&tab=projectOverview

0 голосов
/ 01 ноября 2010

Нет, совместное использование интерфейса в одной сборке не повредит вашим перспективам для неуправляемых клиентов.Не беспокойся об этом.

Что касается другого пути - я не работал с фальшивыми фреймворками, но мне интересно, может ли один из них помочь.Тем не менее, вы рассматривали вопрос о продвижении ваших потребностей в тестировании из «модульных тестов» в «интеграционные тесты»?Я тестировал свои службы WCF так, чтобы иметь поддельный клиент, использующий настоящую заглушку клиента WCF, которая в свою очередь использует реальный сервер, а реальный сервер общается с контроллером поддельного сервера.Затем я запускаю как клиентский, так и серверный процесс - в одном процессе с appdomain magic .Этот отдельный процесс выполняется в контексте среды модульного тестирования Visual Studio.Поэтому я запускаю интеграционные тесты, как если бы они были модульными.Очень мило!

0 голосов
/ 01 ноября 2010

Автоматически сгенерированный клиент обычно полезен только для сценариев, когда вы не можете совместно использовать код между клиентом и сервером.Он будет генерировать для вас новые типы.

Правильный способ совместного использования контракта (т. Е. Интерфейс и типы DataContract, которые он использует) состоит в определении этих типов в отдельной сборкекоторый должен быть распространен на сервер и клиент.Затем вы можете сделать реализацию сервера на сервере, а реализацию клиента на клиенте.

Когда у вас есть готовые типы, легко создать свойсобственная реализация клиента, как вы узнали сами.Это обычно то, что я бы сделал.Это также позволяет легко смоделировать и / или внедрить реализацию службы.

Если у вас нет возможности разделить сборку контракта между клиентом и сервером, следующая лучшая вещь - воспользоваться частичнымсгенерированные классы для добавления вашего интерфейса и метода Close.

0 голосов
/ 01 ноября 2010

Если вы используете Windsor в качестве IoC (не уверен насчет Unity), вы можете заставить его ввести Клиент WCF.Это означает, что ваш потребительский код должен беспокоиться только о ICustomerService.

container = new WindsorContainer().AddFacility<WcfFacility>();

container.Register(Component
  .For<ICustomerService>()
  .ActAs(DefaultClientModel
  .On(WcfEndpoint.FromConfiguration("CustomerService")))
  .LifeStyle.Transient);
...