BehaviorExtensionElement's CreateBehavior is Marked Internal May, 2009
This is really lame. I'm creating a custom service host (That inherits from WebServiceHost) and I want to be able to programmatically add behaviors from configuration. Since the WebServiceHost is zero config there are no service elements to define a behavior config. Now I know I could manually create those service elements with an webHttpBinding and specify the behavior config, but I really do like the zero configuration feature, I just want to be able to define behaviors in config. Unfortunately the BehaviorExtensionElement's CreateBehavior is marked as internal. I'm not sure if M$ will make this public in the future or not but it looks like the only good way to get around it for now is with reflection (Or create a dummy service element with the behavior config, have the runtime load the behaviors and then copy them to your service, boo). I think in this instance reflection on an internal member is safe as that method has to be there in order for the behavior to be created by the runtime. I don't see how it can be changed since that would break custom behaviors. I snagged this simple extension method from the aforementioned thread, it uses reflection to invoke the internal CreateBehavior method.
public static object CreateBehavior(this BehaviorExtensionElement extensionElement) { return extensionElement.GetType(). GetMethod( "CreateBehavior", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic). Invoke(extensionElement, new object[0] { }); }
I also whipped up a few ServiceHost extension methods that add the behaviors (Adapted from some reflected framework code):
public static void LoadBehaviors( this ServiceHost serviceHost, string behaviorConfiguration) { ServiceBehaviorElement serviceBehaviors = GetServiceBehaviorElement(serviceHost, behaviorConfiguration); if (serviceBehaviors != null) { foreach (BehaviorExtensionElement behaviorExtension in serviceBehaviors) { object extension = behaviorExtension.CreateBehavior(); if (extension != null) { Type extensionType = extension.GetType(); if (typeof(IServiceBehavior).IsAssignableFrom(extensionType)) { if (serviceHost.Description.Behaviors.Contains(extensionType)) { serviceHost.Description.Behaviors.Remove(extensionType); } serviceHost.Description.Behaviors.Add((IServiceBehavior)extension); } } } } } public static ServiceBehaviorElement GetServiceBehaviorElement( this ServiceHost serviceHost, string behaviorConfiguration) { BehaviorsSection behaviorsSection = (BehaviorsSection)ConfigurationManager. GetSection("system.serviceModel/behaviors"); foreach (ServiceBehaviorElement behavior in behaviorsSection.ServiceBehaviors) { if (behavior.Name == behaviorConfiguration) return behavior; } return null; }
Then you simply run this on the ServiceHost:
serviceHost.LoadBehaviors("myBehaviorConfig");
Now if your creating your own service host you can override the ApplyConfiguration method and add them there. In the following example I add a check to see if there is a service element for this service. If not then I apply the behaviors, otherwise I skip it and assume that the service element has the desired configuration.
protected override void ApplyConfiguration() { base.ApplyConfiguration(); if (!this.HasServiceElement()) this.LoadBehaviors("myBehaviorConfig"); }The following is the HasServiceElement & supporting GetServiceElement ServiceHost extension methods:
public static bool HasServiceElement(this ServiceHost serviceHost) { return (GetServiceElement(serviceHost) != null); } public static ServiceElement GetServiceElement(this ServiceHost serviceHost) { ServicesSection servicesSection = (ServicesSection)ConfigurationManager. GetSection("system.serviceModel/services"); ServiceElementCollection services = servicesSection.Services; foreach (ServiceElement element in services) { if (element.Name == serviceHost.Description.ConfigurationName) return element; } return null; }