Использование Unity Dependency Injection со службами WCF - PullRequest
12 голосов
/ 09 сентября 2011

У меня есть следующее после некоторых исследований по другим вопросам:

MyServiceHost:

public class MyServiceHost : ServiceHost
{
    public MyServiceHost(IUnityContainer 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 DependencyInjectionInstanceProvider(container));
        }
    }
}

DependencyInjectionInstanceProvider:

public class DependencyInjectionInstanceProvider : IInstanceProvider, IContractBehavior 
{     
    private readonly IUnityContainer container;      
    public DependencyInjectionInstanceProvider(IUnityContainer 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.Teardown(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 

} 

MyServiceHostFactory:

    public class MyServiceHostFactory : ServiceHostFactory
{
    private readonly IUnityContainer container;     
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) 
    { 
        return new MyServiceHost(this.container, serviceType, baseAddresses); 
    }
}

Служба электронной почты с попыткой инъекции в конструктор:

public class EmailValidator : IEmailValidator
{
    private IFakeDAL fakeDAL;

    public EmailValidator(IFakeDAL fakeDAL)
    {
        this.fakeDAL = fakeDAL;
    }

    public bool ValidateAddress(string emailAddress)
    {
        Console.WriteLine("Validating: {0}", emailAddress);

        string pattern = @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@(([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})$";
        return Regex.IsMatch(emailAddress, pattern);
    }
}

Мой консольный хост для запуска службы:

static void Main(string[] args)
    {
        Type serviceType = typeof(EmailValidator);
        Uri serviceUri = new Uri("http://localhost:8080/");

        MyServiceHostFactory shf = new MyServiceHostFactory();
        ServiceHost host = shf.CreateServiceHost(serviceType, serviceUri);
        //ServiceHost host = new ServiceHost(serviceType, serviceUri);
        host.Open();

Моя проблема заключается в логике хоста консоли. Вызов CreateServiceHost имеет синтаксическую ошибку из-за того, что первый аргумент ожидает строку конструктора, а не тип. Что я не понимаю, так как он принимает параметр типа. В дополнение к этому я не понимаю, где я должен отображать IFakeDAL для конкретного класса. Могу ли я сделать это в файле app.config или зарегистрировать это где-нибудь еще?

Ответы [ 3 ]

7 голосов
/ 09 сентября 2011

ServiceHostFactory для хостинга в IIS.При самостоятельном хостинге вы должны использовать ваш производный ServiceHost напрямую. Здесь у вас есть целый пример, включая конфигурацию Unity.

3 голосов
/ 09 сентября 2011

Я использую следующие классы в моей службе Windows, чтобы создавать службы WCF и внедрять в нее зависимости с помощью Unity.

UnityInstanceProvider:

internal class UnityInstanceProvider : IInstanceProvider {

    private readonly IUnityContainer container;
    private readonly Type contractType;

    public UnityInstanceProvider(IUnityContainer container, Type contractType) {
        this.container = container;
        this.contractType = contractType;
    }

    public object GetInstance(InstanceContext instanceContext) {
        return GetInstance(instanceContext, null);
    }

    public object GetInstance(InstanceContext instanceContext, Message message) {
        return container.Resolve(contractType);
    }

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

UnityServiceBehavior:

public class UnityServiceBehavior : IServiceBehavior {

    private readonly IUnityContainer container;

    public UnityServiceBehavior(IUnityContainer container) {
        this.container = container;
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {
        foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers) {
            foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints) {
                if (endpointDispatcher.ContractName != "IMetadataExchange") {
                    string contractName = endpointDispatcher.ContractName;
                    ServiceEndpoint serviceEndpoint = serviceDescription.Endpoints.FirstOrDefault(e => e.Contract.Name == contractName);
                    endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(this.container, serviceEndpoint.Contract.ContractType);
                }
            }
        }
    }
}

UnityServiceHost:

public class UnityServiceHost : ServiceHost {

    private IUnityContainer unityContainer;

    public UnityServiceHost(IUnityContainer unityContainer, Type serviceType)
        : base(serviceType) {
        this.unityContainer = unityContainer;
    }

    protected override void OnOpening() {
        base.OnOpening();

        if (this.Description.Behaviors.Find<UnityServiceBehavior>() == null) {
            this.Description.Behaviors.Add(new UnityServiceBehavior(this.unityContainer));
        }
    }
}

С помощью этих классов вы можете делать следующее (Настройка служб выполняется в .config):

UnityContainer container = new UnityContainer();
UnityServiceHost serviceHost = new UnityServiceHost(container, typeof("Type of Service to host"));
serviceHost.Open();
1 голос
/ 09 сентября 2011

Метод CreateServiceHost ожидает массив Uri экземпляров, поэтому попробуйте вместо этого:

ServiceHost host = shf.CreateServiceHost(serviceType, new[] { serviceUri });

Вы можете сопоставить интерфейсы с типами в XML или коде, но яЯ рекомендую код, поскольку XML имеет слишком большие накладные расходы на обслуживание.

Метод Main является отличным Корнем компоновки , но если вы хотите настроить контейнер на этом уровне, вы 'Вам нужно будет передать его из метода Main в MyServiceHostFactory - это прекрасно, когда вы размещаете сервис в консольном приложении, но не будет работать, если вы хотите разместить его в IIS, где MyServiceHostFactory должен быть корнем композиции, поскольку IIS требует конструктор по умолчанию .

...