The final ConfigurationSource

A configuration source in OpenRasta is used to define what resources are available, and where (think routing in ASP.NET).

Unfortunately, once you have more than a few endpoints it rapidly becomes unwieldy.

A few of my colleagues started pulling chunks of configuration out into static methods on separate classes, which led towards… the final ConfigurationSource!

	public class ConfigurationSource : IConfigurationSource
	{
		private readonly IEnumerable<IDefineResources> _resourceDefinitions;

		public ConfigurationSource(IDefineResources[] resourceDefinitions)
		{
			_resourceDefinitions = resourceDefinitions;
		}

		public void Configure()
		{
			using (OpenRastaConfiguration.Manual)
			{
				foreach (var resourceDefinition in _resourceDefinitions)
				{
					resourceDefinition.DefineResources();
				}
			}
		}
	}

This allows you to implement IDefineResources:

public interface IDefineResources
{
	void DefineResources();
}

For example:

public class MyResourceDefinitions : IDefineResources
{
	public void DefineResources()
	{
		ResourceSpace.Has.ResourcesOfType<MyResource>()
			.AtUri("some/resource/{id}")
                        .HandledBy<MyHandler>()
			.AsXmlSerializer
			.ForMediaType(MediaType.Xml);
	}
}

And, as long as the container knows about it, your resources will be defined.

This means you can even define resources outside the main project, allowing you to move in the direction of modular, composable applications.

Rewriting operations with OpenRasta

One of the myriad of extension points that OpenRasta offers, is the operation interceptor. There’s a base class, called OperationInterceptor, that makes it convenient to override the method(s) you are interested in and provides a default (null) implementation for the others.

The IOperationInterceptor interface provides three methods:

  • BeforeExecute: returns a boolean, allowing you to stop the pipeline. Useful for validation, for example.
  • RewriteOperation
  • AfterExecute: post-processing, also returns a boolean.

RewriteOperation is particularly interesting. The signature:

Func<IEnumerable<OutputMember>> RewriteOperation(Func<IEnumerable<OutputMember>> operationBuilder);

while a little frightening, reveals the intention. It’s basically a decorator, allowing you to wrap your operation with some other behaviour. Logging, for example, or exception handling.

public class ExceptionHandlerOperationInterceptor : OperationInterceptor
{
	private readonly ILogger _logger;

	public ExceptionHandlerOperationInterceptor(ILogger logger) 
	{
		_logger = logger;
	}

	public override Func<IEnumerable<OutputMember>> RewriteOperation(Func<IEnumerable<OutputMember>> operationBuilder)
	{
		return () => TryExecute(operationBuilder);
	}

	private IEnumerable<OutputMember> TryExecute(Func<IEnumerable<OutputMember>> operationBuilder) 
	{
		try
		{
			return operationBuilder();
		}
		catch (TargetInvocationException ex)
		{
			_logger.WriteException(ex.InnerException);
			return ReturnBadRequest(ex.InnerException);
		}
	}

	private static IEnumerable<OutputMember> ReturnBadRequest(Exception ex) {
		var errors = new List<Error> 
		{ 
			new Error
			{
				Exception = ex,
				Message = ex.Message,
			}
		};

		return new[]
		{
			new OutputMember
			{
				Value = new OperationResult.BadRequest
				{
					ResponseResource = new ErrorResource(),
					Errors = errors
				}
			}
		};
	}
}

Releasing http scoped objects when using OpenRasta with StructureMap

StructureMap isn’t quite as pro-active as Castle Windsor when it comes to releasing (and disposing) of http scoped objects. So it’s generally a good practice to do so explicitly at the end of a web request:

protected void Application_EndRequest(object sender, EventArgs e)
{
    ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}

My first attempt to reproduce this with OpenRasta used a pipeline contributor:

using OpenRasta.Pipeline;
using OpenRasta.Web;
using StructureMap.Pipeline;

namespace OpenRasta.DI.StructureMap.Pipeline.Contributors
{
	public class ReleaseAndDisposeAllHttpScopedObjects : IPipelineContributor
	{
		public void Initialize(IPipeline pipelineRunner)
		{
			pipelineRunner.Notify(ReleaseAndDispose)
				.After<KnownStages.IOperationExecution>()
				.And.Before<KnownStages.IOperationResultInvocation>();
		}

		private static PipelineContinuation ReleaseAndDispose(ICommunicationContext communicationContext)
		{
			HttpContextLifecycle.DisposeAndClearAll();
			return PipelineContinuation.Continue;
		}
	}
}

Thankfully, Seb pointed out that it made more sense to hook into IDependencyResolver.HandleIncomingRequestProcessed():

public void HandleIncomingRequestProcessed()
{
    HttpContextLifecycle.DisposeAndClearAll();
}

Using log4net with OpenRasta

OpenRasta comes with a built in TraceLogger, but if you use log4net in your code then it’s easier to have all your log output going to the same destination. Thanks to ORs excellent pluggable architecture, it’s easy to supply your own implementation of ILogger:

using System;
using log4net;
using OpenRasta;
using OpenRasta.Diagnostics;

namespace Your.Namespace.Here
{
	public class Log4NetLogger : ILogger
	{
		private readonly ILog _log;

		public Log4NetLogger(ILog log)
		{
			_log = log;
		}

		public IDisposable Operation(object source, string name)
		{
			_log.DebugFormat("Entering {0}: {1}", source.GetType().Name, name);
			return new OperationCookie(_log, source);
		}

		public void WriteDebug(string message, params object[] format)
		{
			_log.DebugFormat(message, format);
		}

		public void WriteWarning(string message, params object[] format)
		{
			_log.WarnFormat(message, format);
		}

		public void WriteError(string message, params object[] format)
		{
			_log.ErrorFormat(message, format);
		}

		public void WriteInfo(string message, params object[] format)
		{
			_log.InfoFormat(message, format);
		}

		public void WriteException(Exception e)
		{
			_log.Error("Exception", e);
		}

		private class OperationCookie : IDisposable
		{
			private readonly ILog _log;
			private readonly object _source;

			public OperationCookie(ILog log, object source)
			{
				_log = log;
				_source = source;
			}

			public void Dispose()
			{
				_log.DebugFormat("Exiting {0}".With(_source.GetType().Name));
			}
		}
	}

	public class Log4NetLogger<T> : Log4NetLogger, ILogger<T> where T : ILogSource
	{
		public Log4NetLogger() : base(LogManager.GetLogger(LogSource<T>.Category)) { }
	}
}

This then needs to be supplied to the dependency resolver, for ILogger & ILogger<T> along with an ILog.