public class CustomDuplexChannelFactory<TChannel> : DuplexChannelFactory<TChannel>
{ /// <summary>
/// Gets or sets the configuration path.
/// </summary>
/// <value>The configuration path.</value>
public static string ConfigurationPath { get; set; }
/// <summary>
/// Custom client channel constructor.
/// </summary>
public CustomDuplexChannelFactory(InstanceContext callbackInstance)
: base(callbackInstance)
{ }
/// <summary>
/// Overrides the CreateDescription() method of the channel factory
/// to apply a new configuration file.
/// </summary>
/// <returns></returns>
protected override ServiceEndpoint CreateDescription()
{ ServiceEndpoint serviceEndpoint = base.CreateDescription();
if(ConfigurationPath == null || !File.Exists(ConfigurationPath))
return base.CreateDescription();
ExeConfigurationFileMap executionFileMap = new ExeConfigurationFileMap();
executionFileMap.ExeConfigFilename = ConfigurationPath;
System.Configuration.Configuration config =
ConfigurationManager.OpenMappedExeConfiguration(
executionFileMap, ConfigurationUserLevel.None);
ServiceModelSectionGroup serviceModeGroup =
ServiceModelSectionGroup.GetSectionGroup(config);
ChannelEndpointElement selectedEndpoint = null;
foreach(ChannelEndpointElement endpoint in serviceModeGroup.Client.Endpoints)
{ if(endpoint.Contract == serviceEndpoint.Contract.ConfigurationName)
{ selectedEndpoint = endpoint;
break;
}
}
if(selectedEndpoint != null)
{ if(serviceEndpoint.Binding == null)
{ serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, serviceModeGroup);
}
if(serviceEndpoint.Address == null)
{ serviceEndpoint.Address = new EndpointAddress(selectedEndpoint.Address,
GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);
}
if(serviceEndpoint.Behaviors.Count == 0 &&
!String.IsNullOrEmpty(selectedEndpoint.BehaviorConfiguration))
{ AddBehaviors(selectedEndpoint.BehaviorConfiguration,
serviceEndpoint, serviceModeGroup);
}
serviceEndpoint.Name = selectedEndpoint.Contract;
}
return serviceEndpoint;
}
#region private
/// <summary>
/// Configures the binding for the selected endpoint.
/// </summary>
/// <param name="bindingName"></param>
/// <param name="group"></param>
/// <returns></returns>
private Binding CreateBinding(string bindingName, ServiceModelSectionGroup group)
{ BindingCollectionElement bindingElementCollection = group.Bindings[bindingName];
if(bindingElementCollection.ConfiguredBindings.Count > 0)
{ IBindingConfigurationElement be = bindingElementCollection.ConfiguredBindings[0];
Binding binding = GetBinding(be);
if(be != null)
{ be.ApplyConfiguration(binding);
}
return binding;
}
return null;
}
/// <summary>
/// Adds the configured behavior to the selected endpoint
/// </summary>
/// <param name="behaviorConfiguration"></param>
/// <param name="serviceEndpoint"></param>
/// <param name="group"></param>
private void AddBehaviors(string behaviorConfiguration, ServiceEndpoint serviceEndpoint,
ServiceModelSectionGroup group)
{ EndpointBehaviorElement behaviorElement =
group.Behaviors.EndpointBehaviors[behaviorConfiguration];
for(int i = 0; i < behaviorElement.Count; i++)
{ BehaviorExtensionElement behaviorExtension = behaviorElement[i];
object extension = behaviorExtension.GetType().InvokeMember("CreateBehavior", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, behaviorExtension, null);
if(extension != null)
{ serviceEndpoint.Behaviors.Add((IEndpointBehavior)extension);
}
}
}
/// <summary>
/// Gets the endpoint identity from the configuration file
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
private EndpointIdentity GetIdentity(IdentityElement element)
{ EndpointIdentity identity = null;
PropertyInformationCollection properties = element.ElementInformation.Properties;
if(properties["userPrincipalName"].ValueOrigin != PropertyValueOrigin.Default)
{ return EndpointIdentity.CreateUpnIdentity(element.UserPrincipalName.Value);
}
if(properties["servicePrincipalName"].ValueOrigin != PropertyValueOrigin.Default)
{ return EndpointIdentity.CreateSpnIdentity(element.ServicePrincipalName.Value);
}
if(properties["dns"].ValueOrigin != PropertyValueOrigin.Default)
{ return EndpointIdentity.CreateDnsIdentity(element.Dns.Value);
}
if(properties["rsa"].ValueOrigin != PropertyValueOrigin.Default)
{ return EndpointIdentity.CreateRsaIdentity(element.Rsa.Value);
}
if(properties["certificate"].ValueOrigin != PropertyValueOrigin.Default)
{ X509Certificate2Collection supportingCertificates = new X509Certificate2Collection();
supportingCertificates.Import(Convert.FromBase64String(element.Certificate.EncodedValue));
if(supportingCertificates.Count == 0)
{ throw new InvalidOperationException("UnableToLoadCertificateIdentity"); }
X509Certificate2 primaryCertificate = supportingCertificates[0];
supportingCertificates.RemoveAt(0);
return EndpointIdentity.CreateX509CertificateIdentity(primaryCertificate,
supportingCertificates);
}
return identity;
}
/// <summary>
/// Helper method to create the right binding depending on the configuration element
/// </summary>
/// <param name="configurationElement"></param>
/// <returns></returns>
private Binding GetBinding(IBindingConfigurationElement configurationElement)
{ if(configurationElement is CustomBindingElement)
return new CustomBinding();
else if(configurationElement is BasicHttpBindingElement)
return new BasicHttpBinding();
else if(configurationElement is NetMsmqBindingElement)
return new NetMsmqBinding();
else if(configurationElement is NetNamedPipeBindingElement)
return new NetNamedPipeBinding();
else if(configurationElement is NetPeerTcpBindingElement)
return new NetPeerTcpBinding();
else if(configurationElement is NetTcpBindingElement)
return new NetTcpBinding();
else if(configurationElement is WSDualHttpBindingElement)
return new WSDualHttpBinding();
else if(configurationElement is WSHttpBindingElement)
return new WSHttpBinding();
else if(configurationElement is WSFederationHttpBindingElement)
return new WSFederationHttpBinding();
return null;
}
}