Apply or customize WCF behaviors at Runtime

BehaviorManager is designed to apply or customize WCF behaviors at runtime.BehaviorManager reads the behaviors configured in the web.config and apply them at Service or Endpoint level. I am reading ServiceModel section from web.config but you can change the code to read from exe.config easily.

What was the business drivers for loading behaviors at runtime? For my requirements, all the WCF services are hosted in IIS and I had to customize the ServiceHost and ServiceHostFactory to take full control over the service/endpoint behaviors and bindings. The end goals is to keep the ServiceModel section bare bone to reduce the pain for developers. Custom Behaviors and Binding are applied in code but the hosting model must include alternative way to apply them in special use case scenario. I will be writing a separate post on ServiceHost and ServiceHostFactory and you will get to see how to connect the dots. For now, let’s see how you can load behaviors from configuration and apply them at runtime to ServiceDescription.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Reflection;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.Web.Configuration;

namespace WCF.Behaviors
{
	/// <summary>
    /// BehaviorManager is designed to apply or customize WCF behaviors at runtime.
    /// BehaviorManager reads the behaviors configured in the web.config and apply them
    /// at Service or Endpoint level.
	/// </summary>
    public class BehaviorManager
	{
		internal static void ApplyServiceBehavior(ServiceDescription description, string behaviorName)
		{
			List<IServiceBehavior> list;
			ServiceBehaviorElement serviceBehaviorElement = LoadServiceBehaviorFromConfiguration(behaviorName);
			if (serviceBehaviorElement == null)
			{
				list = new List<IServiceBehavior>();
			}
			else
			{
				list = CreateBehaviors<IServiceBehavior>(serviceBehaviorElement);
			}

			foreach (IServiceBehavior serviceBehavior in list)
			{
				Type behaviorType = serviceBehavior.GetType();
				if (description.Behaviors.Contains(behaviorType))
				{
					description.Behaviors.Remove(behaviorType);
				}
				description.Behaviors.Add(serviceBehavior);
			}
		}

		internal static void ApplyEndpointBehavior(ServiceEndpoint description, string behaviorName)
		{
			List<IEndpointBehavior> list;
			EndpointBehaviorElement endpointBehaviorElement = LoadEndpointBehaviorFromConfiguration(behaviorName);
			if (endpointBehaviorElement == null)
			{
				list = new List<IEndpointBehavior>();
			}
			else
			{
				list = CreateBehaviors<IEndpointBehavior>(endpointBehaviorElement);
			}

			foreach (IEndpointBehavior behavior in list)
			{
				Type behaviorType = behavior.GetType();
				if (description.Behaviors.Contains(behaviorType))
				{
					description.Behaviors.Remove(behaviorType);
				}
				description.Behaviors.Add(behavior);
			}
		}

		internal static EndpointBehaviorElement LoadEndpointBehaviorFromConfiguration(string behaviorName)
		{
			EndpointBehaviorElement endpointBehaviorElement = null;
			ServiceModelSectionGroup configGroup = ServiceModelSectionGroup.GetSectionGroup(WebConfigurationManager.OpenWebConfiguration("~/"));
			
			if (configGroup.Behaviors.EndpointBehaviors.ContainsKey(behaviorName))
			{
				endpointBehaviorElement=configGroup.Behaviors.EndpointBehaviors[behaviorName];
			}
			
			return endpointBehaviorElement;
		}

		internal static ServiceBehaviorElement LoadServiceBehaviorFromConfiguration(string behaviorName)
		{
			ServiceBehaviorElement serviceBehaviorElement = null;

			ServiceModelSectionGroup configGroup = ServiceModelSectionGroup.GetSectionGroup(WebConfigurationManager.OpenWebConfiguration("~/"));
			
			if (configGroup.Behaviors.ServiceBehaviors.ContainsKey(behaviorName))
			{
				serviceBehaviorElement = configGroup.Behaviors.ServiceBehaviors[behaviorName];
			}

			return serviceBehaviorElement;
		}

		internal static List<T> CreateBehaviors<T>(EndpointBehaviorElement behaviorElement) where T : class
		{
			List<T> list = new List<T>();
			foreach (BehaviorExtensionElement behaviorSection in behaviorElement)
			{
				MethodInfo info = behaviorSection.GetType().GetMethod("CreateBehavior", BindingFlags.NonPublic | BindingFlags.Instance);
				T behavior = info.Invoke(behaviorSection, null) as T;
				if (behavior != null)
				{
					list.Add(behavior);
				}
			}

			return list;
		}

		internal static List<T> CreateBehaviors<T>(ServiceBehaviorElement behaviorElement) where T : class
		{
			List<T> list = new List<T>();
			foreach (BehaviorExtensionElement behaviorSection in behaviorElement)
			{
				MethodInfo info = behaviorSection.GetType().GetMethod("CreateBehavior", BindingFlags.NonPublic | BindingFlags.Instance);
				T behavior = info.Invoke(behaviorSection, null) as T;
				if (behavior != null)
				{
					list.Add(behavior);
				}
			}

			return list;
		}
	}
}

Acknowledgement:
http://weblogs.asp.net/cibrax/archive/2010/05/11/getting-wcf-bindings-and-behaviors-from-any-config-source.aspx

Leave a Reply