2011-08-31 49 views
1

我在開發IIS上有兩個應用程序。第一個WCF應用程序,包含所有與數據庫的邏輯和通信(我們稱之爲服務器)。另一個引用WCF應用程序的ASP.NET MVC 3應用程序(我們稱之爲客戶端)。Unity IoC + WCF + wsHTTPBinding +證書授權

我有問題與混合WCF web.config配置與Unity IoC定製服務主機和自定義行爲相關聯。

當所有配置由Unity完成時,它會創建簡單的BasicHttpBinding,但我的要求是使用證書授權來保護它,所以我需要wsHTTPBinding。

-------------配置basicHttpBinding的------------

在開始的時候看看常見的統一實施WCF:

internal class UnityInstanceProvider : IInstanceProvider 
{ 
    private readonly IUnityContainer container; 
    private readonly Type contractType; 

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

    #region IInstanceProvider Members 

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

internal class UnityServiceBehavior : IServiceBehavior 
{ 
    private readonly IUnityContainer container; 

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

    #region IServiceBehavior Members 

    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") 
       { 
        endpointDispatcher.DispatchRuntime.InstanceProvider = new UnityInstanceProvider(container, serviceDescription.ServiceType); 



       } 
      } 
     } 
    } 

    #endregion 
} 

public class UnityServiceHost : ServiceHost 
{ 
    private readonly IUnityContainer container; 

    public UnityServiceHost(
     [NotNull] IUnityContainer container, 
     [NotNull] Type serviceType, 
     Uri[] baseAddresses) 
     : base(serviceType, baseAddresses) 
    { 
     this.container = container; 
    } 

    protected override void OnOpening() 
    { 
     base.OnOpening(); 
     if (Description.Behaviors.Find<UnityServiceBehavior>() == null) 
     { 
      Description.Behaviors.Add(new UnityServiceBehavior(container)); 
     } 
    } 
} 

public class UnityServiceHostFactory : ServiceHostFactory 
{ 
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) 
    { 
     IUnityContainer container = new UnityContainer(); 
     UnityContainerConfigurator.Configure(container); 
     return new UnityServiceHost(container, serviceType, baseAddresses); 
    } 
} 

WCF應用程序web.config僅包含基本信息: 無端點,無服務定義。

現在,假設我們有SecurityService與定義:

<%@ ServiceHost Language="C#" Debug="true" 
Service="myNamespace.SecurityService" 
Factory="myNamespace.UnityServiceHostFactory" %> 

現在,我可以添加服務引用SecurityService到我的客戶。 一個該步驟中,生成客戶端的web.config:

<basicHttpBinding> 
<binding name="BasicHttpBinding_ISecurityService" closeTimeout="00:01:00" 
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" 
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" 
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" 
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" 
useDefaultWebProxy="true"> 
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
    maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
<security mode="None"> 
    <transport clientCredentialType="None" proxyCredentialType="None" 
    realm="" /> 
    <message clientCredentialType="UserName" algorithmSuite="Default" /> 
</security> 
</binding> 

<endpoint address="http://localhost/wcf-app/SecurityService.svc" 
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISecurityService" 
contract="SecurityServiceReference.ISecurityService" name="BasicHttpBinding_ISecurityService" /> 

在這一點上我這個配置對於​​統一:

container.RegisterType<SecurityServiceClient>(new InjectionConstructor()); 

而在客戶端應用程序,我可以用它(我在這裏不提及構造注入):

var securityService = DependencyResolver.Current.GetService<SecurityServiceClient>(); 

而這一切都有效!但是這不,如果我想使用的WSHttpBinding ...

-------------配置的WSHttpBinding ------------

爲了啓用wsHTTPBinding,我在WCF應用程序的web.config中配置了它。作爲BasicHttpBinding的其餘部分,它沒有包含關於綁定,終止等的任何信息。

但現在我的wsHttpBinding說:

<bindings> 
    <wsHttpBinding> 
    <binding name="wsHttpEndpointBinding"> 
     <security> 
     <message clientCredentialType="Certificate" /> 
     </security> 
    </binding> 
    </wsHttpBinding> 
</bindings> 

<services> 
    <service behaviorConfiguration="ServiceBehavior" name="myNamespace.SecurityService"> 
    <endpoint address="" binding="wsHttpBinding" 
     bindingConfiguration="wsHttpEndpointBinding" 
     name="wsHttpEndpoint" contract="myNamespace.ISecurityService"> 
    </endpoint> 
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> 
    </service> 
</services> 

<behaviors> 
    <serviceBehaviors> 
    <behavior name="ServiceBehavior"> 
     <serviceMetadata httpGetEnabled="true" /> 
     <serviceDebug includeExceptionDetailInFaults="false" /> 
     <serviceCredentials> 
     <serviceCertificate findValue="CN=myClientCert" /> 
     </serviceCredentials> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 

並添加服務參考客戶端應用程序後,它會產生:

<wsHttpBinding> 
<binding name="wsHttpEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00" 
receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" 
transactionFlow="false" hostNameComparisonMode="StrongWildcard" 
maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" 
textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false"> 
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
    maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
<reliableSession ordered="true" inactivityTimeout="00:10:00" 
    enabled="false" /> 
<security mode="Message"> 
    <transport clientCredentialType="Windows" proxyCredentialType="None" 
    realm="" /> 
    <message clientCredentialType="Certificate" negotiateServiceCredential="true" 
    algorithmSuite="Default" /> 
</security> 
</binding> 

我手動添加behaviorConfiguration = 「CertBehavior」,那就是:

<behaviors> 
<endpointBehaviors> 
    <behavior name="CertBehavior"> 
    <clientCredentials> 
     <clientCertificate findValue="CN=myClientCert"/> 
    </clientCredentials> 
    </behavior> 
</endpointBehaviors> 

,現在當我想用團結來解決它:

var securityService = DependencyResolver.Current.GetService<SecurityServiceClient>(); 

我總是得到空...

什麼是有趣的,當我創建簡單實例:

var client = new SecurityServiceReference.SecurityServiceClient(); 

它工作正常...所以肯定問題不是用錯的wsHttpBinding配置連接,而是從web.config中結合團結+的wsHttpBinding ...

任何一個可以幫助我解決這個問題?

丹尼爾

+0

它看起來更像是你自己的代碼中的問題。如果Unity無法創建實例,並且它嘗試創建它調用構造函數的實例,則Unity會觸發異常 - 這種調用不會導致「null」。 –

回答

0

好吧,

我想通了。

首先是拉迪斯拉夫你是對的,它應該顯示異常。 UnityDependencyResolver只是簡單地捕捉它。

internal class UnityDependencyResolver : IDependencyResolver 
{ 
    private readonly IUnityContainer container; 

    public UnityDependencyResolver([NotNull] IUnityContainer container) 
    { 
     this.container = container; 
    } 

    #region IDependencyResolver Members 

    public object GetService(Type serviceType) 
    { 
     try 
     { 
      return container.Resolve(serviceType); 
     } 
     catch 
     { 
      return null; 
     } 
    } 

    public IEnumerable<object> GetServices(Type serviceType) 
    { 
     try 
     { 
      return container.ResolveAll(serviceType); 
     } 
     catch 
     { 
      return new List<object>(); 
     } 
    } 

更重要的是,我不得不明確的一套證書位置證書:

<serviceCertificate findValue="CN=myClientCert" 
          storeName="My" 
          x509FindType="FindBySubjectDistinguishedName" 
          storeLocation="LocalMachine" 
          /> 

<clientCertificate findValue="CN=myClientCert" storeName="My" 
          x509FindType="FindBySubjectDistinguishedName" 
          storeLocation="LocalMachine" 
          /> 

不正常工作。