ArcDeveloper REST: Windsor Brings the Party That Rocks the Body
Background
In a nutshell, when you have classes that depend on other classes (and, really, what project doesn't have that? Answer: Maintenance nightmare projects) a good pattern to follow is to supply the dependencies as opposed to instantiating them from within the class. The consummate example is:public class ClassA{ private ClassB _classB; public ClassA() { _classB=new ClassB(); //This is pure evil } }The above code violates so many design patterns and principles that I had to have my 7-year old actually type it (he is a TOTAL hacker) b/c I couldn't bring myself to do it. A better way to do it is:
public class ClassA{ private ClassB _classB; public ClassA(ClassB injectedClassB) { _classB=injectedClassB; //This is sunshine and puppy dogs } }That code is an example of constructor injection, b/c the dependency must be provided to the constructor or the class cannot be instantiated. There is also setter injection, where public properties are exposed and the dependencies are suppled there. Both approaches have their pros and cons, and I am of the opinion that, if you are simply using DI in either form, you are WAY ahead of the game. Before I leave the background, I would be remiss if I didn't point you to the Bitter Coder's Wiki, where the best tutorials on Windsor live and party.
Great, So How'd Does the ArcDeveloper Rest Stuff Use Windsor?
Well, the Windsor container can use an external configuration section, say, you the web.config file.<configSections>
<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
</configSections>
<facilities>
<facility
id="logging"
type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging"
loggingApi="log4net"
customLoggerFactory="Castle.Services.Logging.Log4netIntegration.Log4netLogger"
/>
</facilities>
<component id="ags.service" lifestyle="pooled" initialPoolSize="2" maxPoolSize="2"
service="ArcDeveloper.REST.Core.Interfaces.IRESTService, ArcDeveloper.REST.Core"
type="ArcDeveloper.REST.ArcGIS.AGSMapService, ArcDeveloper.REST.ArcGIS">
<parameters>
<name>TestService</name>
<description>Base map</description>
<connectionString>http://65.101.234.201/arcgis/services/gains/gains/MapServer</connectionString>
</parameters>
</component>
<component id="geojson.formatter" lifestyle="transient"
service="ArcDeveloper.REST.Core.Interfaces.IFormatter, ArcDeveloper.REST.Core"
type="ArcDeveloper.REST.Core.Services.GeoJSONFormatter, ArcDeveloper.REST.Core">
<parameters>
<name>geoJSON</name>
</parameters>
</component>
<component id="rest.service" lifestyle="singleton"
service="ArcDeveloper.REST.Core.Interfaces.IRESTServiceManager, ArcDeveloper.REST.Core"
type="ArcDeveloper.REST.Core.RESTServiceManager, ArcDeveloper.REST.Core">
<parameters>
<services>
<list>
<item>${ags.service}</item>
<!-- <item>${other.service}</item>-->
</list>
</services>
<formatters>
<list>
<item>
${geojson.formatter}
</item>
</list>
</formatters>
</parameters>
</component>
<%@ ServiceHost Service="rest.service" Factory="Castle.Facilities.WcfIntegration.WindsorServiceHostFactory, Castle.Facilities.WcfIntegration" %> (GRRR....CopyAsHTML doesn't help me in .svc files)- Instantiate the container at application start up, using the Global.Application_Start method (from our Global.asax.cs file)
protected void Application_Start(object sender, EventArgs e)
{
container = new WindsorContainer(new XmlInterpreter());
WindsorServiceHostFactory.RegisterContainer(container.Kernel);
_log = container[typeof(ILogger)] as ILogger;
_log.Info("Services app started successfully.");
}