Внедрение данных в службу WCF - PullRequest
20 голосов
/ 11 января 2010

У меня есть службы WCF, структурированные как предложено Мигелем Кастро . Это означает, что я настроил все вручную, и у меня есть консольное приложение, в котором размещаются мои службы, использующие объекты ServiceHost .

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

Ответы [ 4 ]

32 голосов
/ 11 января 2010

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

В качестве примера я недавно написал тот, который использует Castle Windsor для подключения зависимостей для реализации сервиса. Реализация CreateServiceHost просто делает это:

return new WindsorServiceHost(this.container, serviceType, baseAddresses);

где this.container - это настроенный IWindsorContainer.

WindsorServiceHost выглядит так:

public class WindsorServiceHost : ServiceHost
{
    public WindsorServiceHost(IWindsorContainer container, Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        foreach (var cd in this.ImplementedContracts.Values)
        {
            cd.Behaviors.Add(new WindsorInstanceProvider(container));
        }
    }
}

и WindsorInstanceProvider выглядит следующим образом:

public class WindsorInstanceProvider : IInstanceProvider, IContractBehavior
{
    private readonly IWindsorContainer container;

    public WindsorInstanceProvider(IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        this.container = container;
    }

    #region IInstanceProvider Members

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        return this.GetInstance(instanceContext);
    }

    public object GetInstance(InstanceContext instanceContext)
    {
        var serviceType = instanceContext.Host.Description.ServiceType;
        return this.container.Resolve(serviceType);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        this.container.Release(instance);
    }

    #endregion

    #region IContractBehavior Members

    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
    {
        dispatchRuntime.InstanceProvider = this;
    }

    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
    {
    }

    #endregion
}

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

Вы можете следовать той же идиоме кодирования, чтобы внедрить Dependency Injection с другим DI-контейнером или с помощью DI Бедного.

Вот более старая запись этой идиомы, в которой используется DI Бедного.

5 голосов
/ 12 января 2010

Если вы использовали Castle Windsor, у него есть отличная возможность интеграции с WCF, которая позволяет вам это делать, и намного проще.

1 голос
/ 12 января 2010

вы настраивали сервис как Singleton? я обнаружил, что реализация IInstanceProvider может быть проблематичной при использовании контейнера DI для создания экземпляров службы.

0 голосов
/ 06 июля 2013

Статья Размещение макета в качестве службы WCF содержит статический метод, который будет генерировать хост службы WCF на основе объекта, который передается в метод с одной конечной точкой.

Метод был также опубликован в ответе для Рекомендуемые шаблоны для модульного тестирования веб-сервисов .

Пример использования вызывает NSubstitute, но могут использоваться и другие насмешливые фреймворки.

...