Meeting the needs of your business from a distance

Override WCF Client Settings From Custom Config File

by mark shiffer 25. August 2009 14:35

Recently I needed to bring up a client for a WCF service where my assembly was being hosted in an external 3rd party application. Normally, the happy path for WCF is to read the configuration from the hosting application’s config file. In this case, the host did not have one, and I did not want to force it to have one. So, I needed a way to setup the WCF client with my own config file and not the host’s.

There are plenty of ways to configure a WCF client, but I found that the most straight forward solution for my issue was to create my own ChannelFactory<T> that could read a supplied configuration file. I ran across some code on MSDN and modified it slightly and the end-result is below.

   1: using System;
   2: using System.ServiceModel.Configuration;
   3: using System.Reflection;
   4: using System.Security.Cryptography.X509Certificates;
   5: using System.ServiceModel;
   6: using System.ServiceModel.Description;
   7: using System.ServiceModel.Channels;
   8: using System.Configuration;
   9:  
  10: namespace MAS.Interface.Client
  11: {
  12:     public class ManualChannelFactory<T> : ChannelFactory<T>
  13:     {
  14:         string configurationPath;
  15:         Uri overrideEndPoint;
  16:  
  17:         /// <summary>
  18:         /// custom client channel constructor which 
  19:         /// specifies an external configuration file
  20:         /// </summary>
  21:         /// <param name="configurationPath"></param>
  22:         public ManualChannelFactory(string configurationPath)
  23:             : base(typeof(T))
  24:         {
  25:             this.configurationPath = configurationPath;
  26:             base.InitializeEndpoint((string)null, null);
  27:         }
  28:  
  29:         /// <summary>
  30:         /// Initializes a new instance of the <see cref="ManualChannelFactory&lt;T&gt;"/> class.
  31:         /// </summary>
  32:         /// <param name="configurationPath">The configuration path.</param>
  33:         /// <param name="overrideEndPoint">The override end point.</param>
  34:         public ManualChannelFactory(string configurationPath, Uri overrideEndPoint)
  35:             : base(typeof(T))
  36:         {
  37:             this.configurationPath = configurationPath;
  38:             this.overrideEndPoint = overrideEndPoint;
  39:             base.InitializeEndpoint((string)null, null);
  40:         }
  41:  
  42:         /// <summary>
  43:         /// overrides the CreateDescription() method of the channel factory
  44:         /// to apply a new configuration file
  45:         /// </summary>
  46:         /// <returns></returns>
  47:         protected override ServiceEndpoint CreateDescription()
  48:         {
  49:             ServiceEndpoint serviceEndpoint = base.CreateDescription();
  50:  
  51:             ExeConfigurationFileMap executionFileMap = new ExeConfigurationFileMap();
  52:             executionFileMap.ExeConfigFilename = configurationPath;
  53:  
  54:             System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(executionFileMap, ConfigurationUserLevel.None);
  55:             ServiceModelSectionGroup serviceModeGroup = ServiceModelSectionGroup.GetSectionGroup(config);
  56:  
  57:             ChannelEndpointElement selectedEndpoint = null;
  58:  
  59:             foreach (ChannelEndpointElement endpoint in serviceModeGroup.Client.Endpoints)
  60:             {
  61:                 if (endpoint.Contract == serviceEndpoint.Contract.ConfigurationName)
  62:                 {
  63:                     selectedEndpoint = endpoint;
  64:                     break;
  65:                 }
  66:             }
  67:  
  68:             if (selectedEndpoint != null)
  69:             {
  70:                 if (serviceEndpoint.Binding == null)
  71:                 {
  72:                     serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, serviceModeGroup);
  73:                 }
  74:  
  75:                 if (serviceEndpoint.Address == null)
  76:                 {
  77:                     if (overrideEndPoint == null)
  78:                     {
  79:                         serviceEndpoint.Address = new EndpointAddress(selectedEndpoint.Address, GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);
  80:                     }
  81:                     else
  82:                     {
  83:                         serviceEndpoint.Address = new EndpointAddress(overrideEndPoint, GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);
  84:                     }
  85:                 }
  86:  
  87:                 if (serviceEndpoint.Behaviors.Count == 0 && !String.IsNullOrEmpty(selectedEndpoint.BehaviorConfiguration))
  88:                 {
  89:                     AddBehaviors(selectedEndpoint.BehaviorConfiguration, serviceEndpoint, serviceModeGroup);
  90:                 }
  91:  
  92:                 serviceEndpoint.Name = selectedEndpoint.Contract;
  93:             }
  94:  
  95:             return serviceEndpoint;
  96:         }
  97:  
  98:         /// <summary>
  99:         /// Configures the binding for the selected endpoint
 100:         /// </summary>
 101:         /// <param name="bindingName"></param>
 102:         /// <param name="group"></param>
 103:         /// <returns></returns>
 104:         private Binding CreateBinding(string bindingName, ServiceModelSectionGroup group)
 105:         {
 106:             BindingCollectionElement bindingElementCollection = group.Bindings[bindingName];
 107:             if (bindingElementCollection.ConfiguredBindings.Count > 0)
 108:             {
 109:                 IBindingConfigurationElement be = bindingElementCollection.ConfiguredBindings[0];
 110:  
 111:                 Binding binding = GetBinding(be);
 112:                 if (be != null)
 113:                 {
 114:                     be.ApplyConfiguration(binding);
 115:                 }
 116:  
 117:                 return binding;
 118:             }
 119:  
 120:             return null;
 121:         }
 122:  
 123:         /// <summary>
 124:         /// Adds the configured behavior to the selected endpoint
 125:         /// </summary>
 126:         /// <param name="behaviorConfiguration"></param>
 127:         /// <param name="serviceEndpoint"></param>
 128:         /// <param name="group"></param>
 129:         private void AddBehaviors(string behaviorConfiguration, ServiceEndpoint serviceEndpoint, ServiceModelSectionGroup group)
 130:         {
 131:             EndpointBehaviorElement behaviorElement = group.Behaviors.EndpointBehaviors[behaviorConfiguration];
 132:             for (int i = 0; i < behaviorElement.Count; i++)
 133:             {
 134:                 BehaviorExtensionElement behaviorExtension = behaviorElement[i];
 135:                 object extension = behaviorExtension.GetType().InvokeMember("CreateBehavior",
 136:                 BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
 137:                 null, behaviorExtension, null);
 138:                 if (extension != null)
 139:                 {
 140:                     serviceEndpoint.Behaviors.Add((IEndpointBehavior)extension);
 141:                 }
 142:             }
 143:         }
 144:  
 145:         /// <summary>
 146:         /// Gets the endpoint identity from the configuration file
 147:         /// </summary>
 148:         /// <param name="element"></param>
 149:         /// <returns></returns>
 150:         private EndpointIdentity GetIdentity(IdentityElement element)
 151:         {
 152:             EndpointIdentity identity = null;
 153:             PropertyInformationCollection properties = element.ElementInformation.Properties;
 154:             if (properties["userPrincipalName"].ValueOrigin != PropertyValueOrigin.Default)
 155:             {
 156:                 return EndpointIdentity.CreateUpnIdentity(element.UserPrincipalName.Value);
 157:             }
 158:             if (properties["servicePrincipalName"].ValueOrigin != PropertyValueOrigin.Default)
 159:             {
 160:                 return EndpointIdentity.CreateSpnIdentity(element.ServicePrincipalName.Value);
 161:             }
 162:             if (properties["dns"].ValueOrigin != PropertyValueOrigin.Default)
 163:             {
 164:                 return EndpointIdentity.CreateDnsIdentity(element.Dns.Value);
 165:             }
 166:             if (properties["rsa"].ValueOrigin != PropertyValueOrigin.Default)
 167:             {
 168:                 return EndpointIdentity.CreateRsaIdentity(element.Rsa.Value);
 169:             }
 170:             if (properties["certificate"].ValueOrigin != PropertyValueOrigin.Default)
 171:             {
 172:                 X509Certificate2Collection supportingCertificates = new X509Certificate2Collection();
 173:                 supportingCertificates.Import(Convert.FromBase64String(element.Certificate.EncodedValue));
 174:                 if (supportingCertificates.Count == 0)
 175:                 {
 176:                     throw new InvalidOperationException("UnableToLoadCertificateIdentity");
 177:                 }
 178:                 X509Certificate2 primaryCertificate = supportingCertificates[0];
 179:                 supportingCertificates.RemoveAt(0);
 180:                 return EndpointIdentity.CreateX509CertificateIdentity(primaryCertificate, supportingCertificates);
 181:             }
 182:  
 183:             return identity;
 184:         }
 185:  
 186:         /// <summary>
 187:         /// Helper method to create the right binding depending on the configuration element
 188:         /// </summary>
 189:         /// <param name="configurationElement"></param>
 190:         /// <returns></returns>
 191:         private Binding GetBinding(IBindingConfigurationElement configurationElement)
 192:         {
 193:             if (configurationElement is CustomBindingElement)
 194:                 return new CustomBinding();
 195:             else if (configurationElement is BasicHttpBindingElement)
 196:                 return new BasicHttpBinding();
 197:             else if (configurationElement is NetMsmqBindingElement)
 198:                 return new NetMsmqBinding();
 199:             else if (configurationElement is NetNamedPipeBindingElement)
 200:                 return new NetNamedPipeBinding();
 201:             else if (configurationElement is NetPeerTcpBindingElement)
 202:                 return new NetPeerTcpBinding();
 203:             else if (configurationElement is NetTcpBindingElement)
 204:                 return new NetTcpBinding();
 205:             else if (configurationElement is WSDualHttpBindingElement)
 206:                 return new WSDualHttpBinding();
 207:             else if (configurationElement is WSHttpBindingElement)
 208:                 return new WSHttpBinding();
 209:             else if (configurationElement is WSFederationHttpBindingElement)
 210:                 return new WSFederationHttpBinding();
 211:  
 212:             return null;
 213:         }
 214:     }
 215: }

Many thanks to Paraesthesia and MSDN.

Tags:

Issues | Programming

Comments

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading



Copyright © 2001-2010 MS Consulting, Inc. All Rights Reserved.