2011-09-08 93 views
12

我已經在做的其他問題經過一番研究以下內容:使用Unity依賴注入與WCF服務

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(); 

我的問題存在於控制檯主機邏輯。由於第一個參數需要一個構造函數字符串而不是一個Type,CreateServiceHost調用有一個語法錯誤。我不明白,因爲它接受Type參數。除此之外,我不明白我應該將IFakeDAL映射到具體的類。我可以在app.config文件中做到這一點,還是應該在其他地方註冊?

回答

7

ServiceHostFactory用於託管在IIS中。在自主託管中,您應該直接使用派生的ServiceHostHere你有完整的例子,包括Unity配置。

+0

謝謝。它看起來是一個很好的例子。我可能會想到這一點。 :) – Elim99

1

CreateServiceHost method預計Uri實例的數組,所以嘗試這個:

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

可以接口映射到XML或代碼類型,但是我建議你的代碼,因爲XML具有太高的維護開銷。

Main方法是一個很好的Composition Root,但如果你想在這個級別上配置的容器,你需要從Main方法將它傳遞給MyServiceHostFactory - 這是完全正常的,當你在一個控制檯託管服務應用程序,但如果要在IIS中託管它,則不起作用,其中MyServiceHostFactoryshould be the Composition Root, since IIS requires a default constructor

+0

+1以評論組成根應該在哪裏。順便說一句,愛書馬克。 –

3

我在我的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(); 
+0

所以你映射到你的配置文件中的具體類? – Elim99

+0

你介意在配置文件中顯示你的服務配置嗎? – Elim99