Showing posts with label DI/IOC. Show all posts
Showing posts with label DI/IOC. Show all posts

Saturday, 6 December 2008

WCF With The Castle Windsor Facility

Towards the end of a rather busy Saturday of coding in the office I decided to take on the exposing of some services at the boundary of a system I am working on. We're using the Castle project's Windsor container for our IOC on all of our new projects and so I figured that it would make sense to do a short spike into the WCF facility that ships with it to see whether this would be worth using going forwards. The short answer is that I think it is.

It proved very simple to get going. I'd recommend anyone looking to use this facility gets the latest version of the source code in the trunk before starting and has a look at the demo project in there as this proved very helpful.

I quickly defined an interface and set it up as a contract (as per normal with WCF), I then created a class that implemented the interface. At this point in the Global.asax.cs I configured my Windsor container mappings like this:


ServiceDebugBehavior returnFaultsAndMex =

                new ServiceDebugBehavior

                    {

                        IncludeExceptionDetailInFaults = true,

                        HttpHelpPageEnabled = true

                    };

            

            ServiceMetadataBehavior metadata =

                new ServiceMetadataBehavior {HttpGetEnabled = true};

 

            container = new WindsorContainer()

                .AddFacility<WcfFacility>()

                .Register(

                          Component.For<INHibernateSessionManager>()

                              .Named("NHibernateSessionManager")

                              .ImplementedBy<NHibernateSessionManager>(),

                          Component.For<IBarRepositoryFactory>()

                              .Named("BarRepositoryFactory")

                              .ImplementedBy<BarRepositoryFactory>()

                              .DependsOn(Property.ForKey("sessionFactoryConfigPath")

                                             .Eq(Path.Combine(

                                                     Path.GetDirectoryName(

                                                         GetType().Assembly.Location),

                                                     "Hibernate.cfg.xml"))),

                          Component.For<BarService>()

                              .Named("BarDomainService")

                              .ImplementedBy<BarService>(),

                          Component.For<IBarEnterpriseService>()

                              .Named("BarEnterpriseService")

                              .ImplementedBy<BarEnterpriseService>());



Next up was the .svc file:


<% @ServiceHost Service="BarEnterpriseService" 

    Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" %>



With a bit of work in the web.config file then, with a press of F5, I can navigate to the svc and get the MEX page:


  <system.serviceModel>

    <services>

      <service name="Foo.Bar.EnterpriseServices.BarEnterpriseService" behaviorConfiguration="ReturnFaultsAndMex">

        <endpoint contract="Foo.Bar.EnterpriseServiceContracts.IBarEnterpriseService"

                          binding="basicHttpBinding"/>

      </service>

    </services>

    <behaviors>

      <serviceBehaviors>

        <behavior name="ReturnFaultsAndMex" >

          <serviceDebug includeExceptionDetailInFaults="true" />

          <serviceMetadata httpGetEnabled="true" />

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>



This is great and very nicely integrates the whole WCF experience into my IOC centric application. I do still have a couple of areas where I have questions. In the global.asax file I included details of two behviours, for error details and to enable the MEX service. This code was lifted from the sample in the Castle trunk. I still needed to add these behaviours explicitly into the web.config though. Present or removed these registrations seem to have no effect, and I find the same to be the case with the demo app.

Sunday, 28 September 2008

Keeping code clean - Decorators for Error Handling?

I read a review a few days ago of the new book by Robert C Martin (Uncle Bob) 'Clean Code'. I'm going to order a copy as soon as I clear a couple of books from my current reading list backlog as it sounds interesting and the Uncle Bob blog on Object Mentor is one that I always enjoy to read. One of the things that stuck in my mind from the review was that the 'Do one thing' principle applies even to error handling.

Hmmm, if you see the example in the review (I don't know if its' from the book) then this is shown as not evaluating the exception and acting according to its' type, but rather just logging it. This has been nagging in my mind since I read it. Its' not that I disagree with the example, using exceptions for control of flow has always struck me as being a thoroughly poor practice in every place I've seen it done. It was more the idea that perhaps I shouldn't even have the try-catch block around my code in the first place. Now I know that the where's and when's of exception handling (let alone the how's and why's - any of Kiplings six honest serving men in fact) are a very contested country and I'm certainly not positing what follows as 'the answer', just an idea.

What struck me was that I could use the decorator pattern to implement my error handling. For example I have an interface:

public interface ICandidateRepository
{
Candidate GetCandidate(Guid candidateId);

Candidate RegisterNewCandidate();

void SaveCandidate(Candidate candidate);

List<Candidate> FindCandidates(ICandidateCriteria criteria);

}

I already have a concrete class that implements this interface and uses NHibernate to perform the functions that are described. Instead of wrapping these calls in try-catch blocks I can create a new concrete class that implements this interface and looks like this:

public class CandidateRepositoryExceptionDecorator : ICandidateRepository
{
private readonly ICandidateRepository _nestedCandidateRepository;
private ILogger _logger;

public ILogger Logger
{
get { return _logger ?? NullLogger.Instance; }
set { _logger = value; }
}

public CandidateRepositoryExceptionDecorator(ICandidateRepository candidateRepository)
{
_nestedCandidateRepository = candidateRepository;
}

public Candidate GetCandidate(Guid candidateId)
{
try
{
return _nestedCandidateRepository.GetCandidate(candidateId);
}
catch (Exception ex)
{
_logger.ErrorFormat(ex, "Exception when calling GetCandidate({0}).", candidateId);
throw;
}
}

// ... etc ...

}

I use my DI framework of choice to get the parameters into the constructor and to organise the nesting of my objects. In my case this is with the Windsor container. The components section is left like this:

<components>
<component id="candidateRepositoryErrorHandler" service="Semeosis.Examinations.Model.Interfaces.ICandidateRepository, Semeosis.Examinations.Model.Interfaces" type="Semeosis.Examinations.Model.Repositories.Decorators.CandidateRepositoryExceptionDecorator, Semeosis.Examinations.Model.Repositories.Decorators" />
<component id="candidateRepository" service="Semeosis.Examinations.Model.Interfaces.ICandidateRepository, Semeosis.Examinations.Model.Interfaces" type="Semeosis.Examinations.Model.Repositories.NHibernate.CandidateRepository, Semeosis.Examinations.Model.Repositories.NHibernate" />
</components>

The order in which the components are listed determines the order in which the container chains the objects. See this post by Oren for more info.

The upshot of this is that when I call:

ICandidateRepository repository = container.Resolve<ICandidateRepository>();

I get an instance of my CandidateRepositoryExceptionDecorator and this contains my CandidateRepository class from my NHibernate repositories project.

Now my concerns are separated and I can keep the functions that deal with the creational and persistence concerns separate from the error handling concerns. If in the future I need to change the way that my exception handling is manager, or I need to perform other actions than just logging when an exception is logged then I can very easily extend this code. Also unit testing this is incredibly trivial using mocking, whilst also reducing the number of tests on the functions that actually 'do the work'. Separation of concerns in one layer helps keep things clean and tidy across many other layers of the onion! I guess that's why TDD can have such a beneficial effect on model design - but the benefits can be two way.