zoukankan      html  css  js  c++  java
  • Unity IoC + WCF + wsHTTPBinding + Certificate Authorization

    Hi,

    I have two applications on IIS 
    for development. First WCF application that contains all the logic and communication with database (we call this Server). And another ASP.NET MVC 3 application that has reference to WCF application (we call this Client).
    I have issue connected with mixing WCF web.config configuration with Unity IoC custom service host and custom behavior.
    When all configuration 
    is done by Unity it creates simple BasicHttpBinding, but my requirement is to make it secure with Certificate Authorization, so I need wsHTTPBinding.

    ------------- Configuring for BasicHttpBinding ------------
    At the beginning look at common Unity implementation 
    for 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 application web.config contains only basic information:None endpoints, none service definition.
    Now imagine that we have SecurityService with definition:

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

    Now I can add service reference to SecurityService to my Client. A 
    this step it generates in client 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>
       
    </basicHttpBinding>

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

    At 
    this point I configure this for Unity:

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

    And 
    in Client application I can use it simply by (I don't mention here constructor injection):

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

    And 
    this all works! But It don't if I want to use wsHTTPBinding ...


    ------------- Configuring for wsHTTPBinding ------------


    To enable wsHTTPBinding I configured it inside web.config of WCF Application. As a remainder 
    for BasicHttpBinding it didn't contained any information concerning binding, endpoin, etc.
    But now for wsHTTPBinding I added:

        
    <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>

    And after adding service reference to Client application it generates:

        
    <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>
       
    </wsHttpBinding>

       
    <endpoint address="http://localhost/wcf-app/SecurityService.svc" behaviorConfiguration="CertBehavior"
        binding
    ="wsHttpBinding" bindingConfiguration="wsHttpEndpoint"
        contract
    ="SecurityServiceReference.ISecurityService" name="wsHttpEndpoint">
        
    <identity>
         
    <certificate encodedValue="myValueCertValue..." />
        
    </identity>
       
    </endpoint>

    I manually added behaviorConfiguration
    ="CertBehavior", that is:

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

    And now when I want to resolve it 
    using Unity:

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

    get always null...
    What 
    is funny when I create simply instance by:

    var client 
    = new SecurityServiceReference.SecurityServiceClient();

    It works fine... So 
    for sure issue is not connected with wrong wsHttpBinding configuration but rather combining Unity + wsHttpBinding from web.config...


    Can any one help me with 
    this issue?
    Daniel
  • 相关阅读:
    实现货币金额中文大写转换的程序
    大数阶乘的计算(三)
    全国15亿人口中选1000个代表有多少种选法?
    DB Query Analyzer 中断SQL语句的执行
    Android_Preference存取数据
    Centos 学习笔记软件包管理
    Centos学习笔记文件搜索命令
    《计算机时代》2011年第12期刊登出《DB Query Analyzer中断SQL语句的执行》
    Centos学习笔记linux用户管理
    Centos学习笔记 linux 常用命令:压缩解压命令
  • 原文地址:https://www.cnblogs.com/goody9807/p/2174958.html
Copyright © 2011-2022 走看看