Castle Windsor and WCF: A Match Made in Heaven
Step Uno: Write a Service
Let us create a simple WCF service. It looks like:[ServiceContract()]
public interface IService1
{
[OperationContract]
string MyOperation1(string myValue);
[OperationContract]
void ThrowError();
}
public class Service1 : IService1
{
private ILogger logger; //Yes, yes, should init to a NullInstance.
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
#region IService1 Members
public string MyOperation1(string myValue)
{
logger.Info("MyOperation1 called with {0}",myValue);
return "Hello: " + myValue;
}
public void ThrowError()
{
throw new Exception("AAAAAAH!");
}
#endregion
}
- I added an ILogger property. This is a dependency.
- There is a method that just ralphs an error. Usually I am not as obvious with my errors, but at least I will be able to debug this one.
Bring in da Noise, Bring in da Windsor
I am going to presume that you, the reader, knows about Windsor and, at least at a high level, how to configure it. Basically, for a web app (we are gonna host our services in IIS) you need to:- Write the configuration files for Windsor, consisting of properties, facilities, and components. Go read the castleproject.org site for some decent examples.
- Register the container at startup.
import System;
import System.Reflection
import System.ServiceModel
import System.ServiceModel.Description from System.ServiceModel
import Castle.Facilities.Logging
import Castle.Facilities.WcfIntegration
import Ruprict.Grok.Castle.WcfIntegration.Core
facility LoggingFacility:
loggingApi = LoggerImplementation.Log4net
configFile = 'log4net.config'
facility WcfFacility
component 'windsor.service', IService1, Service1:
ServiceModel = WcfServiceModel().Hosted() \
.AddEndpoints(WcfEndpoint.BoundTo(BasicHttpBinding()))
component 'error.handler',IServiceBehavior, LogExceptionHandler
component 'metadata.behavior',IServiceBehavior, ServiceMetadataBehavior:
HttpGetEnabled = true
public class Global : HttpApplication, IContainerAccessor
{
private static IWindsorContainer container;
protected void Application_Start(object sender, EventArgs e)
{
container = new WindsorContainer().Install(BinsorScript.FromFile("windsor.boo"));
}
protected void Application_End(object sender, EventArgs e)
{
container.Dispose();
}
#region IContainerAccessor Members
public IWindsorContainer Container
{
get { return container;
}
#endregion
}
<%@ServiceHost Language="C#"
Service="windsor.service" Factory="Castle.Facilities.WcfIntegration.WindsorServiceHostFactory"
%>
- Windsor rocks, and the WcfFacility is all that and a bag of chips.
- You can have web.config <service> section-less WCF services, complete with auto-wired behaviors and dependencies.
- Ayende and Craig are really, really smart.