Skip navigation

Category Archives: .Net

WebForms is a lie. It’s abstraction wrapped in deception covered in lie sauce presented on a plate full of diversion and sleight of hand. Nothing you do with Webforms has anything to do with the web – you let it do the work for you.

I couldn’t agree more with Rob’s post.

The past few evenings, I’ve tried to come up with something to shield exceptions in WCF. I am aware that there are quite some posts about this topic already, but I thought I’d share my findings/solution anyway. I’ve ran into a few issues with the approaches I found and learned something doing so…

I wanted this to be simple and yet flexible. The following bullets sum up the base requirements:

  • No need to apply FaultContractAttribute to all operations
  • Allow the user to map exceptions to faults (type and content) in a straightforward manner
  • No coupling whatsoever, no imposed library-use, exception or fault types
  • Simple and selective fallback to standard WCF behavior

Test First

Let’s start with a test that illustrates the idea (or skip to the implementation). The scenario is as follows. We have a simple service contract with two operations, one throws a custom ValidationException, the other a NotImplementedException. I have told the exception shielding behavior to shield two types of exceptions:

  • ValidationException: should map to a validation fault (including one simple property, but this could be anything, of course)
  • Exception: should set the ExceptionDetail, basically this comes down to IncludeExceptionDetailInFaults

Here are the types used to test the exception shielding:

[ServiceContract]
[ShieldExceptions	(
	new[] { typeof(ValidationFault), typeof(ExceptionDetail) },
	new[] { typeof(ValidationException), typeof(Exception) })]
public interface ITestService
{
	[OperationContract] void OperationOne();
	[OperationContract] void OperationTwo();
}

public class TestService : ITestService
{
	public void OperationOne()
	{
		throw new ValidationException() { CustomProperty = "OperationOne finds the request invalid." };
	}

	public void OperationTwo()
	{
		throw new System.NotImplementedException();
	}
}

public class ValidationException : Exception
{
	public string CustomProperty { get; set; }
}

[DataContract]
public class ValidationFault
{
	// .ctor maps exception to fault
	public ValidationFault(ValidationException exception)
	{
		FaultProperty = exception.CustomProperty;
	}

	[DataMember]
	public string FaultProperty { get; set; }
}

Notice the use of ShieldExceptions and the fact that there are no FaultContractAttributes on the operations.

And here is one of the tests (I’ve skipped the rest to reduce bloat) to verify the type of exception thrown in the client thread.

[Test]
[ExpectedException(typeof(FaultException<ValidationFault>))]
public void Calling_operation_that_throws_shielded_validation_exception_should_throw_corresponding_fault_exception_on_client()
{
	// Arrange
	var svc = ChannelFactory<ITestService>.CreateChannel(binding, new EndpointAddress(serviceUri));

	// Act
	svc.OperationOne();
}

As the test fixture above illustrates, you simply need to add the attribute ShieldExceptions with a list of exception types you wish to shield. For every exception you need to specify the corresponding fault (this is checked during validation of the behavior). The order in which you specify exception types should be from most specific to the least; being System.Exception. If you don’t specify System.Exception, you’ll get the standard WCF behavior for all exception you didn’t specify.

The mapping of exceptions to faults is simply done by the means of a constructor. The ShieldExceptions behavior will try to create a fault based on the .ctor. First it tries to find the .ctor with the specific exception type, then with a generic exception type and finally it falls back to the default .ctor.

Implementation

There are three parts to this solution: A custom IContractBehavior implementation, a custom IErrorhandler and an IClientMessageInspector.

The ShieldExceptionsAttribute does a few things. It validates if the specified fault and exception types make sense adds a custom error handler to the ChannelDispatcher and sets the required ExceptionShieldingMessageInspector. Besides adding all this behavior the most important thing the ShieldExceptionsAttribute does is updating the service contract with possible faults. If you check out the generated WSDL, you’ll see that all fault information is included.

public class ShieldExceptionsAttribute : Attribute, IContractBehavior
{
	private readonly Type[] knownFaultTypes;
	private readonly Type[] exceptionTypes;

	public ShieldExceptionsAttribute(Type[] knownFaultTypes, Type[] exceptionTypes)
	{
		this.knownFaultTypes = knownFaultTypes;
		this.exceptionTypes = exceptionTypes;
	}

	public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
	{
		foreach (var op in contractDescription.Operations)
		foreach (var knownFaultType in knownFaultTypes)
		{
			// Add fault contract if it is not yet present
			if (!op.Faults.Any(f => f.DetailType == knownFaultType))
				op.Faults.Add(new FaultDescription(knownFaultType.Name) { DetailType = knownFaultType, Name = knownFaultType.Name });
		}
	}

	public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
	{
		clientRuntime.MessageInspectors.Add(new ExceptionShieldingMessageInspector(knownFaultTypes));
	}

	public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
	{
		dispatchRuntime.ChannelDispatcher.ErrorHandlers.Add(new ExceptionShieldingErrorHandler(knownFaultTypes, exceptionTypes));
	}

	public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
	{
		if(knownFaultTypes.Length != exceptionTypes.Length)
			throw new ArgumentException("The ShieldExceptions behavior needs a corresponding exception type for each possible fault to shield.");

		var badType = knownFaultTypes.FirstOrDefault(t => !t.IsDefined(typeof (DataContractAttribute), true));
		if(badType != null)
			throw new ArgumentException(string.Format("The specified fault '{0}' is no data contract. Did you forget to decorate the class with the DataContractAttirbute attribute?", badType));

		var badExceptionType = exceptionTypes.FirstOrDefault(t => t != typeof(Exception) && !t.IsSubclassOf(typeof(Exception)));
		if (badExceptionType != null)
			throw new ArgumentException(string.Format("The specified type '{0}' is not an Exception-derived type.", badExceptionType));
	}
}

Now, every time service operation code throws an exception, the ExceptionShieldingErrorHandler gets called. This handler analyzes the thrown exception and creates the appropriate FaultMessage that can travel back to the client.

public class ExceptionShieldingErrorHandler : IErrorHandler
{
	private readonly Type[] knownFaultTypes;
	private readonly Type[] exceptionTypes;

	public ExceptionShieldingErrorHandler(Type[] knownFaultTypes, Type[] exceptionTypes)
	{
		this.knownFaultTypes = knownFaultTypes;
		this.exceptionTypes = exceptionTypes;
	}

	public bool HandleError(Exception error)
	{
		return true; // session should not be killed, or should it?
	}

	public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
	{
		if (error is FaultException) return;

		var exceptionType = exceptionTypes.FirstOrDefault(t => error.GetType() == t || error.GetType().IsSubclassOf(t));
		if(exceptionType != null)
		{
			var faultType = knownFaultTypes[Array.IndexOf(exceptionTypes, exceptionType)];
			fault = Message.CreateMessage(version, CreateFaultException(faultType, error).CreateMessageFault(), faultType.Name);
		}
	}

	private static FaultException CreateFaultException(Type faultType, Exception exception)
	{
		var ctor = faultType.GetConstructor(new[] { exception.GetType() })   // .ctor with specific exception?
			      ?? faultType.GetConstructor(new[] { typeof(Exception) }); // .ctor with generic exception?

		var detail = ctor != null
			? ctor.Invoke(new[] { exception })
			: faultType.GetConstructor(Type.EmptyTypes).Invoke(null); // fall back to default .ctor

		// Create generic fault exception with detail and reason
		return Activator.CreateInstance(typeof(FaultException<>).MakeGenericType(faultType), detail, "Unhandled exception has been shielded.") as FaultException;
	}
}

The CreateFaultException makes sure the most appropriate .ctor is called. This allows you to map exceptions to faults just by initializing the fault from the constructor.

The final piece of the puzzle is a client message inspector. The fact that I have a IClientMessageInspector, is to work around one of the issues I encountered: When you do not specify a FaultContract attribute on the operation(s) in your ServiceContract, you will always get a non-generic (or should I say generic) FaultException in stead of the expected FaultException<T>, holding the detail. That is, if you use a ChannelFactory to create your proxies, which is something I tend to do whenever I can.

Generating proxies from the WSDL (without re-using types, that is) does not need this message inspection since the code will be based on the WSDL which contains all information.

Without the explicit FaultContractAttribute, there’s only one thing we miss: the client proxy doesn’t know about the fault detail. The reply message will contain it, but the channel will simply ignore it. Using this simple message inspector we can easily ‘fake’ the exact same behavior we have with the FaultContractAttribute: we read the detail ourselves.

public class ExceptionShieldingMessageInspector : IClientMessageInspector
{
	private readonly Type[] knownFaultTypes;

	public ExceptionShieldingMessageInspector(Type[] knownFaultTypes)
	{
		this.knownFaultTypes = knownFaultTypes;
	}

	public object BeforeSendRequest(ref Message request, IClientChannel channel)
	{
		return null; // no correlation required
	}

	public void AfterReceiveReply(ref Message reply, object correlationState)
	{
		if (!reply.IsFault) return;

		var action = reply.Headers.Action;
		var faultType = knownFaultTypes.FirstOrDefault(t => t.Name == action);

		if (faultType != null)
		{
			var detail = ReadFaultDetail(MessageFault.CreateFault(reply, int.MaxValue), faultType);
			var exceptionType = typeof(FaultException<>).MakeGenericType(faultType);
			var faultException = Activator.CreateInstance(exceptionType, detail, "Server exception has been shielded.") as Exception;

			throw faultException;
		}
	}

	private static object ReadFaultDetail(MessageFault reply, Type faultType)
	{
		using (var reader = reply.GetReaderAtDetailContents())
		{
			var serializer = new DataContractSerializer(faultType);
			return serializer.ReadObject(reader);
		}
	}
}

As you might know, I run a web shop written in ASP.Net MVC. The move to ASP.Net MVC is fairly recent (time frame of preview 4), the shop ran for a few years on ‘classic’ ASP.Net (am I glad that’s finally over), but provided basically the same functionality as the ported version now.

There are some improvements though (besides the obvious: a far better implementation). One of the most visible changes is the support for more SEO-friendly urls. Since the shop is available in three languages I decided to finally provide decent localized urls as well. My requirements were as follows:

  • Each domain has a default culture (.be defaults to ‘nl’, .fr to ‘fr’, etc.), but supports all others as well
  • When browsing the site with the default culture no culture url segment is required
  • If the culture url segment specifies the default culture, the request is redirected to a url without culture segment
  • Urls with a culture segment should look like ‘http://domain.com/[culture-name]/[content-url]‘

There are various ways of getting this done, but the most obvious one is a custom ActionFilterAttribute (+ optional controller base class, if you don’t like putting the attribute over and over again). An action filter alone won’t cut it, however. We’ll need to setup appropriate routes first…

Routing

In order to register localized routes as convenient as possible, I’ve created a little helper class with extension methods that provides a ‘MapLocalizedRoute‘ equivalent for each standard ‘MapRoute‘ overload.

/// <summary>
/// Provides extension methods to register localized routes.
/// </summary>
public static class RouteCollectionExtensions
{
	public static void MapLocalizedRoute(this RouteCollection routes, string name, string url)
	{
		MapLocalizedRoute(routes, name, url, null, null);
	}

	public static void MapLocalizedRoute(this RouteCollection routes, string name, string url, object defaults)
	{
		MapLocalizedRoute(routes, name, url, defaults, null);
	}

	public static void MapLocalizedRoute(this RouteCollection routes, string name, string url, string[] namespaces)
	{
		MapLocalizedRoute(routes, name, url, null, null, namespaces);
	}

	public static void MapLocalizedRoute(this RouteCollection routes, string name, string url, object defaults, object constraints)
	{
		MapLocalizedRoute(routes, name, url, defaults, constraints, null);
	}

	public static void MapLocalizedRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
	{
		MapLocalizedRoute(routes, name, url, defaults, null, namespaces);
	}

	public static void MapLocalizedRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
	{
		foreach (var cultureName in Locale.SupportedCultureNames)
		{
			var route = routes.MapRoute(
				string.Format("{0}-{1}", name, cultureName),
				string.Format("{0}/{1}", cultureName, url),
				defaults,
				constraints,
				namespaces);

			route.Defaults.Add(Locale.CultureSegmentName, cultureName);
		}
	}
}

MapLocalizedRoute will simply map a route for every supported culture name (as set in the Locale class). Because the culture name is a literal in the url, we need to add a ‘culture’ value to the default values of the route. Doing so gives you more control over your routing and avoids the possibility of handling unsupported or malformed culture names. With these extension methods we can do the following in our Application_Start:


Locale.DefaultCultureName = "nl";
Locale.SupportedCultureNames = new[] {"nl", "en", "fr"};

// ...

routes.MapLocalizedRoute("about", "about/", new { controller = "Root", action = "About" });
routes.MapLocalizedRoute("terms", "terms/", new { controller = "Root", action = "Terms" });
routes.MapLocalizedRoute("faq", "faq/", new { controller = "Root", action = "Faq" });

// ...

routes.MapLocalizedRoute("brands", "brands/{title}-{brandId}/{pageIndex}",
	new { controller = "Products", action = "Brands", pageIndex = "0" });
routes.MapLocalizedRoute("cat", "{name}-{categoryId}/{pageIndex}",
	new { controller = "Products", action = "Category", pageIndex = "0" });

// map non-localized routes here

In case you’re wondering why default culture routes are not mapped in MapLocalizedRoute and why the listing above mentions that you should map non-localized route after the localized ones. This is simply because we need to add the most common route patterns first.

Localize

Now let’s have a look at the LocalizeAttribute. For every localized url the OnActionExecuting will make sure the CurrentCulture and CurrentUICulture of the current thread are set as requested. If the requested culture is the default one, the filter will redirect the user to the default culture url (without culture segment).

Note that we don’t have to verify if the requested culture name is a supported one; the MapLocalizedRoute will make sure that only the supported languages are mapped.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class LocalizeAttribute : ActionFilterAttribute
{
	private static readonly Regex removeCultureSegmentRegex = new Regex(@"^/[a-zA-Z\-]+", RegexOptions.Compiled);

	public override void OnActionExecuting(ActionExecutingContext filterContext)
	{
		if (!filterContext.RouteData.Values.ContainsKey(Locale.CultureSegmentName))
		{
			SetCurrentCultures(Locale.DefaultCultureName);
			return;
		}

		var culture = filterContext.RouteData.Values[Locale.CultureSegmentName].ToString();

		if (culture == Locale.DefaultCultureName)
		{
			RedirectToDefaultCultureUrl(filterContext);
			return;
		}

		SetCurrentCultures(culture);
	}

	private static void SetCurrentCultures(string cultureName)
	{
		Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName);
		Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(cultureName);
	}

	private static void RedirectToDefaultCultureUrl(RequestContext filterContext)
	{
		filterContext.HttpContext.Response.Redirect(removeCultureSegmentRegex.Replace(filterContext.HttpContext.Request.RawUrl, string.Empty), true);
	}
}

Finally, there just theLocale class that configures the default and supported cultures.

/// <summary>
/// Holds the default and supported culture names.
/// </summary>
public static class Locale
{
	static Locale()
	{
		DefaultCultureName = "en";
		SupportedCultureNames = new[] {"en", "nl", "fr"};
	}

	internal const string CultureSegmentName = "culture";

	public static string DefaultCultureName { get; set;}
	public static string[] SupportedCultureNames { get; set;}
}

In a previous post I wrote something about putting an NHibernate session in your operation context. Guess what? I ended up never using that implementation because shortly after actually putting that behavior in my app, I decided to make it more generic first.

I thought, what will I do with this or that operation of this or that service? I don’t need this kind of context, I need something else here. I was really not into creating a different behavior (and so on) every time something else needed to be scoped. So I thought, why not just configure the type of the context I want?

End Result

Let’s start with the goal. The end result allows you to configure a certain type of context by adding the following behavior extension to the system.ServiceModel section of your configuration file:

<extensions>
	<behaviorExtensions>

		<add name="callContextBehavior" type="typesafe.ServiceModel.CallContextServiceBehaviorExtensionElement, typesafe.ServiceModel, Version=0.2.0.0, Culture=neutral, PublicKeyToken=b7fa8d8d247605f2"/>
	</behaviorExtensions>
</extensions>
<behaviors>
	<serviceBehaviors>
		<behavior name="behavior">
			<callContextBehavior contextType="[ASSEMBLY QUALIFIED NAME OF CONTEXT TYPE]"/>

		</behavior>
	</serviceBehaviors>
</behaviors>

With this configuration I can ensure that every service operation of a certain service will be able to access the specified type of context. All I have to do is add behaviorConfiguration="behavior" to a service configuration element. I could do the same thing on endpoint level as well (if I add the behaviorExtension to an endpointBehavior).

If you don’t like config, you can alternatively go ahead and apply the behavior by the means of a CallContextBehavior attribute which you can apply on either service or operation level. (Doing so also makes unit testing easier to maintain/write.)

[CallContextBehavior(typeof(MyCallContext))]
public bool OperationHasContext()
{
	return CallContext.Current != null;
}

// or

[CallContextBehavior(typeof(MyCallContext))]
public class TestService : ITestService
{
	// now all operations can assert CallContext.Current != null
}

How do we achieve this?

Basically, you’ll need to do the following…

  1. Provide a way to access and create your custom context from your code
  2. initialize and dispose the context when required/appropriate
  3. allow yourself to apply the context (at various levels)

First thing you need is an interface for you context. Well, technically speaking, you don’t, but I decided to do so to make things more explicit and somewhat safer. I have a context interface (an abstract class, actually) that looks like this:

public abstract class CallContext
{
	[ThreadStatic] // who needs OperationContext? ;-)
	private static CallContext callContext;

	/// <summary>
	/// Gets the context of the current operation.
	/// </summary>

	public static CallContext Current
	{
		get { return callContext; }
		internal set { callContext = value;}
	}

	protected internal abstract void Initialize();
	protected internal abstract void Dispose();
}

The static Current property allows you to access the configured context from your service operation code (that’s the main reason I went for an abstract class opposed to an interface). You’ll only have to cast it to your exact type the moment you need to access it (more on this later).

If you want to create a custom context, all you have to do is inherit from CallContext and override its two methods. It goes without saying that the Initialize method is called right before your service call, and the Dispose method right after.

In case you’re wondering why the CallContext class is not IDisposable (while specifying a Dispose method), I did this so I could hide the method from the service implementation code: operations cannot call it. Besides, it didn’t add any value anyway.

The second part consists of an ICallContextInitializer that makes sure the context gets initialized and disposed when we want it, right before and right after our operation executes.

public class CallContextInitializer : ICallContextInitializer
{
	private readonly Type contextType;

	public CallContextInitializer(Type contextType)
	{
		this.contextType = contextType;
	}

	object ICallContextInitializer.BeforeInvoke(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.IClientChannel channel, Message message)
	{
		CallContext.Current = Activator.CreateInstance(contextType) as CallContext;

		if (CallContext.Current == null)
			throw new ConfigurationErrorsException(string.Format("The type '{0}' could not be initialized or is no CallContext derived type.", contextType));

		CallContext.Current.Initialize();

		return null; // we don't need no correlation
	}

	void ICallContextInitializer.AfterInvoke(object state)
	{
		// Dispose the context
		if (CallContext.Current != null)
			CallContext.Current.Dispose();
	}
}

Finally we need to apply the ICallContextInitializer to the service operations with a behavior. The following behavior implements IServiceBehavior, IEndpointBehavior and IOperationBehavior. This allows you to choose the granularity of applying the behavior.

public class CallContextServiceBehavior : Attribute, IServiceBehavior, IEndpointBehavior, IOperationBehavior
{
	private readonly Type contextType;

	public CallContextServiceBehavior(Type type)
	{
		contextType = type;
	}

	void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
	{
		foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
		foreach (var ed in cd.Endpoints)
		foreach (var operation in ed.DispatchRuntime.Operations)
		{
			operation.CallContextInitializers.Add(new CallContextInitializer(contextType));
		}
	}

	void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
	{
		foreach (var operation in endpointDispatcher.DispatchRuntime.Operations)
		{
			operation.CallContextInitializers.Add(new CallContextInitializer(contextType));
		}
	}

	void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
	{
		dispatchOperation.CallContextInitializers.Add(new CallContextInitializer(contextType));
	}

	// remainder of the interfaces have no implementation...
}

To enable applying the behavior through the system.ServiceModel configuration section (as in the first listing above), we need to create the following BehaviorExtensionElement.

public class CallContextBehaviorExtensionElement : BehaviorExtensionElement
{
	private ConfigurationPropertyCollection properties;

	public override Type BehaviorType
	{
		get { return typeof(CallContextBehavior); }
	}

	protected override object CreateBehavior()
	{
		Type type = Type.GetType(ContextType);

		if (type == null)
			throw new ConfigurationErrorsException(string.Format("The type '{0}' could not be initialized.", ContextType));

		return new CallContextBehavior(type);
	}

	protected override ConfigurationPropertyCollection Properties
	{
		get
		{
			if (properties == null)
			{
				properties = new ConfigurationPropertyCollection {new ConfigurationProperty("contextType", typeof (string))};
			}
			return properties;
		}
	}

	[ConfigurationProperty("contextType", IsRequired = true)]
	public string ContextType
	{
		get { return (string)base["contextType"]; }
		set { base["contextType"] = value; }
	}

}

Example

To illustrate how it all fits together: The following listing contains a completely self-contained unit test that illustrates the usage and working of the above solution.

[TestFixture]
public class CallContextBehaviorTests
{
	private const string address = "net.pipe://localhost/TestService";

	private ServiceHost host;
	private ITestService service;

	[TestFixtureSetUp]
	public void SetUp()
	{
		host = new ServiceHost(typeof(TestService));
		host.AddServiceEndpoint(typeof(ITestService), new NetNamedPipeBinding(), address);
		host.Open();

		var factory = new ChannelFactory<ITestService>(new NetNamedPipeBinding(), new EndpointAddress(address));
		service = factory.CreateChannel();
	}

	[TestFixtureTearDown]
	public void TearDown()
	{
		host.Close();
	}

	[Test]
	public void CallContext_is_null_by_default()
	{
		Assert.IsTrue(service.OperationWithoutContext());
	}

	[Test]
	public void CallContext_should_be_available_after_applying_service_attribute()
	{
		Assert.IsTrue(service.OperationWithContext());
	}
}

internal class MyCallContext : CallContext
{
	// any property we like

	public new static MyCallContext Current
	{
		get { return CallContext.Current as MyCallContext; }
	}

	protected override void Initialize() { }
	protected override void Dispose() { }
}

[ServiceContract]
internal interface ITestService
{
	[OperationContract]
	bool OperationWithContext();

	[OperationContract]
	bool OperationWithoutContext();
}

internal class TestService : ITestService
{
	[CallContextBehavior(typeof(MyCallContext))]
	public bool OperationWithContext()
	{
		return MyCallContext.Current != null;
	}

	public bool OperationWithoutContext()
	{
		return MyCallContext.Current == null;
	}
}

Have you ever noticed weird behavior while debugging? Sure you have, but have you ever seen something like this in a C# file?

Debugging a class with a bad file name

Noticed the hex values instead of what you expect? Looks a lot like debugging C++, doesn’t it? Breakpoints don’t seem to be hit neither, you have to step into the code manually.

If this is happening to you, please do check your file name. Chances are that you are debugging a generic class and have the habit of making this clear in the file name, e.g. MyGenericClass`1.cs.

This behavior appears to be a known bug in Visual Studio 2008 (don’t know about 2005). VS is unable to determine the programming language for files that are named with a grave accent…

I can tell you, this has driven me mad for quite a while!

I’ve change my habit into using MyGenericClass`T.cs, not exactly what I want but at least the file name makes clear it’s a generic class and I can still debug! You can find more details on the issue on the MS connect site.

I am currently working on a web application with the following setup: Web server (ASP.Net MVC) talking to App server (WCF). The web app supports localization in three languages. As a result, many of the service operations need to return localized (product names, descriptions, …) information as well – depending on the current user’s profile in the web app.

I wanted to solve this as simple as possible (certainly not by adding a languageCode parameter to each operation, or so). A quick experiment lead me to the following…

public class LocalizationBehavior :
   IClientMessageInspector,   // client endpoint
   IDispatchMessageInspector, // service endpoint
   IEndpointBehavior
{
   private const string headerName = "localizationHeader";
   private const string @namespace = "urn:schemas-jolena-be:localization";

   public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
   {
      clientRuntime.MessageInspectors.Add(this);
   }

   public object BeforeSendRequest(ref Message request, IClientChannel channel)
   {
      request.Headers.Add(MessageHeader.CreateHeader(
         headerName,
         @namespace,
         Thread.CurrentThread.CurrentUICulture.Name));
      return null; // no correlation required
   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
   {
      endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
   }

   public object AfterReceiveRequest(ref Message request,
      IClientChannel channel, InstanceContext instanceContext)
   {
      var cultureName = request.Headers.GetHeader(headerName, @namespace);
      Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(cultureName);
      return null; // no correlation required
   }

   public void AfterReceiveReply(ref Message reply, object correlationState) { }
   public void Validate(ServiceEndpoint endpoint) { }
   public void AddBindingParameters(ServiceEndpoint endpoint,
      BindingParameterCollection bindingParameters) { }
   public void BeforeSendReply(ref Message reply, object correlationState) { }
}

Applying the above behavior to both client and server side endpoints will make sure the CurrentUICulture corresponds to the one of client thread.

What do you think? Makes sense?

About a month ago, I was asked to come up with something to support modules in ASP.NET MVC. Basically, they wanted to be able to deploy a certain module on one machine but not another, be it customer-specific, a different version or variation. All this with the same core/base application and setup.

After some experimenting, I came up with a mechanism where a module consists of one assembly (well there could be more, but only one actually represents the module). This assembly must be present in the bin directory of the ASP.NET MVC application and the corresponding views should reside in the ~/<AssemblyName>/Views/ directory. That’s it, no special base-classes or configuration, just a simple convention.

For some reasons we have changed this principle a bit by introducing some DI/IoC (using Windsor) to make the thing configurable. Instead of just dropping the necessary dll’s in the bin directory, they must be explicitly configured. (the following discusses that version)

The implementation of this is drop-dead simple. When your application starts, just make sure you do something like this:

MvcModule.Initialize(HttpContext.Current.Server.MapPath("~/App_Data/modules.config"));
// Any other (default) route mapping you wish...

The MvcModule.Initialize method will make sure

  • our MvcModuleControllerFactory is configured (more on that in just a sec.)
  • our windsor container is initialized
  • all loaded modules get their routes mapped

Here’s the code of the MvcModule class:

/// <summary>
/// Represents an ASP.Net MVC Module.
/// </summary>

public abstract class MvcModule
{
   private static List<MvcModule> loadedModules;

   private static List<MvcModule> LoadedModules
   {
      get
      {
         if (loadedModules == null)
            LoadModules();
         return loadedModules;
      }
   }

   private static void LoadModules()
   {
      loadedModules = new List<MvcModule>(Container.ResolveAll<MvcModule>());
   }

   /// <summary>
   /// Gets the IoC container for all MVC modules and controllers.
   /// </summary>

   public static WindsorContainer Container { get; private set; }

   /// <summary>
   /// Initiazes the MVC Modules and controllers using an xml configuration file.
   /// </summary>
   /// <param name="xmlFile">The full path of the xml configuration file.</param>
   public static void Initialize(string xmlFile)
   {
      if (string.IsNullOrEmpty(xmlFile)) throw new ArgumentNullException("xmlFile");

      Initialize(new WindsorContainer(xmlFile));
   }

   /// <summary>

   /// Initiazes the MVC Modules and controllers using a windsor container.
   /// </summary>
   /// <param name="container">The container holding module and controller information.</param>
   public static void Initialize(WindsorContainer container)
   {
      if (container == null) throw new ArgumentNullException("container");
      Container = container;
      ControllerBuilder.Current.SetControllerFactory(new ModuleControllerFactory());
      foreach (var module in LoadedModules)
      {
         module.RegisterRoutes(RouteTable.Routes);
      }
   }

   /// <summary>
   /// Gets the friendly name of the module.
   /// </summary>

   public abstract string FriendlyName { get; }

   /// <summary>
   /// Registers the routes for the module controllers.
   /// </summary>
   /// <param name="routes">The RouteCollection which needs to have the module routes registered.</param>
   public abstract void RegisterRoutes(RouteCollection routes);
}

I guess this is self-explanatory. By the way, the non-windsor version did something like this

private static void LoadModules()
{
   loadedModules = new List<MvcModule>();

   foreach (Assembly a in System.Web.Compilation.BuildManager.GetReferencedAssemblies())
   foreach (Type type in a.GetTypes())
   {
      if (!type.Equals(typeof(MvcModule)) && (typeof (MvcModule).IsAssignableFrom(type)))
         loadedModules.Add((MvcModule) Activator.CreateInstance(type));
   }
}

The MvcModuleControllerFactory creates controllers based on the windows container configuration and makes sure our views directory name convention works:

/// <summary>

/// Creates module controllers for ASP.Net MVC requests.
/// </summary>
public class ModuleControllerFactory : IControllerFactory
{
   private static readonly Dictionary<string, string[]> locationFormats = new Dictionary<string, string[]>();

   protected virtual IController CreateController(RequestContext requestContext, string controllerName)
   {
      var ret = (IController)MvcModule.Container.Resolve(controllerName.ToLower() + "controller");// base.CreateController(requestContext, controllerName);
      Debug.Assert(ret != null, string.Format("The controller with name '{0}' could not be resolved from the container.", controllerName));
      SetViewLocationFormats(ret);
      return ret;
   }

   protected virtual void DisposeController(IController controller)
   {
      var disposable = controller as IDisposable;
      if (disposable != null) disposable.Dispose();

      MvcModule.Container.Release(controller);
   }

   IController IControllerFactory.CreateController(RequestContext context, string controllerName)
   {
      return CreateController(context, controllerName);
   }

   void IControllerFactory.DisposeController(IController controller)
   {
      DisposeController(controller);
   }

   private static void SetViewLocationFormats(IController controller)
   {
      var c = controller as Controller;
      if (c != null)
      {
         var assemblyName = controller.GetType().Assembly.GetName().Name;
         ((ViewLocator)((WebFormViewEngine)c.ViewEngine).ViewLocator).ViewLocationFormats = GetViewLocationFormats(assemblyName);
      }
   }

   private static string[] GetViewLocationFormats(string assemblyName)
   {
      if (locationFormats.ContainsKey(assemblyName)) return locationFormats[assemblyName];

      var formats = new string[8];

      // Modules
      formats[0] = "~/" + assemblyName + "/Views/{1}/{0}.aspx";
      formats[1] = "~/" + assemblyName + "/Views/{1}/{0}.ascx";
      formats[2] = "~/" + assemblyName + "/Views/Shared/{0}.aspx";
      formats[3] = "~/" + assemblyName + "/Views/Shared/{0}.ascx";

      // These are the defaults
      formats[4] = "~/Views/{1}/{0}.aspx";
      formats[5] = "~/Views/{1}/{0}.ascx";
      formats[6] = "~/Views/Shared/{0}.aspx";
      formats[7] = "~/Views/Shared/{0}.ascx";

      // cache them
      locationFormats.Add(assemblyName, formats);
      return formats;
   }
}

What do you think, does this make sense?

I am currently involved in a new CSD project where we have just started to discuss some basic architecture and design aspects. We still have A LOT to talk about, but some things are already pretty certain: WCF (no doubt!), NHibernate (many vendors to support), general principles (separation of concerns, etc.),…

One of the first things that come to mind with the above combination (WCF & NHibernate, that is) is data session management (or data context for LINQ, same issue there). In an ASP.Net application you’ll probably go for a request-scoped ISession whose lifetime you manage through an HttpModule or so.

WCF is actually very similar, except that you’ve got more options in terms of instance and concurrency management, to name a few. However, since a per-call model is considered the most valid option in most cases, we can focus on the similar case.

After some experimenting, and going through the (still very few) examples on the subject I came up with the following first attempt to extend WCF:

1. Implement a simple ICallContextInitializer to manage the scope and lifetime of the (potentially needed) NHibernate session:

public class NHibernateContext : ICallContextInitializer
{
    private static readonly ISessionFactory sessionFactory
        = new Configuration().BuildSessionFactory();

    [ThreadStatic] // who needs OperationContext? ;-)
    private static ISession session;

    /// <summary>
    /// Gets the NHibernate session for the current
    /// service operation/thread.
    /// </summary>
    public static ISession Session
    {
        get
        {
            // lazy init (we might not always need it)
            if (session == null)
                session = sessionFactory.OpenSession();
            return session;
        }
    }

    object ICallContextInitializer.BeforeInvoke(
        System.ServiceModel.InstanceContext instanceContext,
        System.ServiceModel.IClientChannel channel,
        System.ServiceModel.Channels.Message message)
    {
        Debug.Assert(session == null);
        return null; // we don't need no correlation
    }

    void ICallContextInitializer.AfterInvoke(object state)
    {
        // Dispose the session if it as created
        if (session != null)
            session.Dispose();
    }
}

I decided to provide lazy initialization of the ISession. This allows you to apply the service behavior (see later) without having to worry about potential overhead; if the operation does not go to the database, no behavior is added. Asserting that the thread-scoped session variable is null, is to make sure the behavior is applied no more than once and the operation is running in ConcurrencyMode.Single. Finally, the AfterInvoke makes sure the session (if any) is disposed of.

2. Create a service behavior that assures the above ICallContextInitializer is added to the service operation(s).

public class NHibernateServiceBehavior : Attribute, IServiceBehavior
{
    public void ApplyDispatchBehavior(
        ServiceDescription serviceDescription,
        ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcher cd in
            serviceHostBase.ChannelDispatchers)
        {
            foreach (EndpointDispatcher ed in cd.Endpoints)
            {
                foreach (DispatchOperation operation in
                    ed.DispatchRuntime.Operations)
                {
                    operation.CallContextInitializers.Add(
                       new NHibernateContext());
                }
            }
        }
    }

    public void AddBindingParameters(
        ServiceDescription serviceDescription,
        ServiceHostBase serviceHostBase,
        System.Collections.ObjectModel.Collection endpoints,
        BindingParameterCollection bindingParameters) { }

    public void Validate(ServiceDescription serviceDescription,
        ServiceHostBase serviceHostBase) { }

}

You might ask yourself why I chose to use a service behavior and not just an operation behavior (since that’s basically what I’m doing). Well, the main reason is that I wanted as much flexibility as available and service behaviors are the only behaviors that allow all configuration options: through attributes, .Net configuration files or explicitly coded.

With the above behavior in place you can simply call and work with your session, probably not straight from your service code, but through a Repository maybe. Just call NHibernateContext.Session and you’re done.

One last (optional) thing to make sure .Net configuration files really are an option for applying our service behavior is a BehaviorExtensionElement:

public class NHibernateServiceBehaviorExtensionElement :
    BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(NHibernateServiceBehavior); }
    }

    protected override object CreateBehavior()
    {
        return new NHibernateServiceBehavior();
    }
}

This allows you to apply the behavior as follows.

<services>
      <service name="[namespace].SomeService" behaviorConfiguration="nhibernateBehaviorCfg" >
      ...
      </service>

   </services>
   <extensions>
      <behaviorExtensions>
         <add name="nhibernateBehavior" type="[namespace].NHibernateExtesionConfigurationElement, <assemblyName>, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </behaviorExtensions>

   </extensions>
   <behaviors>
      <serviceBehaviors>
         <behavior name=" nhibernateBehaviorCfg ">
         <nhibernateBehavior /> ... </behavior>

      </serviceBehaviors>
   </behaviors>
</system.serviceModel>

While COM or scripting is probably not his/her number one development environment, these days, one still has to deal with it from time to time. Recently I had to and ran into a real annoying problem…

During the refactoring of some base classes, I decided to create a generic (an IList<T> implementation, actually) base class for all collections of the system. No big deal, you’ll think. I thought so as well, until I noticed that all (and there’s quite some left) legacy scripting was no longer able to call even the simplest member like Count. The class instance was somehow recognized, but pretty much useless.

Oops, my mistake, I should have thought about this… COM is interface based and knows zip about generics. Of course unit testing didn’t bring my attention to it either. Anyway, I needed to solve it, fast and hopefully without too much rework (certainly not the scripting stuff!). Luckily there’s a pretty simple way to get this done.

First you tell .Net NOT to generate a class interface (by decorating the class with the ClassInterfaceAttribute attribute) for the class.

The second step is to explicitly implement a (non generic) interface that matches the COM/scripting requirements. Here’s an example:

[ClassInterface(ClassInterfaceType.None)]
public class FooCollection : CollectionBase<Foo>, IScriptCollection
{
   // ...
   int IScriptCollection.Count { get { return base.Count; } }
   // ...
}

[System.Runtime.InteropServices.Guid("7C1E3524-7118-427d-9669-E29A9C9DBACE")]
public interface IScriptCollection
{
   // ...
   int Count { get; }
   // ...
}

You can know call Count from COM as much as you like. Of course this is far from ideal if you have many of these (members and/or classes), fortunately, my concrete classes were being generated, so all I had to do was change a code template and regenerate.

It took a bit longer than first announced last November, but this week the source code server is up and running!

Check out Shawn Burke’s post on how to configure VS2008 to make it all work.

Follow

Get every new post delivered to your Inbox.