Access to MonoRail service instances

May 6, 2008 at 10:18 PMAndre Loker

In my current MonoRail based project - which is in fact my first MonoRail project - I needed access to some of the services provided by the MonoRail container, for example, IEmailTemplateService and IEmailSender. Furthermore the MonoRail app had Windsor Integration enabled, so I wanted them to be injected into the client component by the Windsor IoC container. Unfortunately, the services are not registered as components at the Windsor container.

Luckily, I was pointed at the solution (e.g. here and here) by the kind users of the Castle Project Users mailing list. The key is to let your HttpApplication class implement IMonoRailContainerEvents, which will provide you with a IMonoRailContainer instance as soon as it is created and again when it is initialized.

   1: // Implements IContainerAccessor to notify MonoRail that we provide our own IWindsorContainer
   2: // Implements IMonoRailContainerEvents to be notified when the container was created
   3: public class Global : HttpApplication, IContainerAccessor,  IMonoRailContainerEvents {
   4:     private static Container container;
   5:  
   6:     #region IContainerAccessor Members
   7:     public IWindsorContainer WebContainer {
   8:         get { return container; }
   9:     }
  10:     #endregion
  11:  
  12:     #region IMonoRailContainerEvents Members
  13:     public void Initialized(IMonoRailContainer mr){
  14:         // here we register the services as components
  15:         container.Register(
  16:             Component.For<IEmailTemplateService>().Instance(mr.EmailTemplateService),
  17:             Component.For<IEmailSender>().Instance(mr.EmailSender)
  18:             // additional services here...
  19:         );
  20:     }
  21:  
  22:     public void Created(IMonoRailContainer mr){
  23:         // ignore..
  24:     }
  25:     #endregion
  26:  
  27:     protected void Application_Start(object sender, EventArgs e) {
  28:         // create container
  29:         container = new WebContainer();
  30:         container.Init();
  31:     }
  32: }

The important part is the fact that we implement IMonoRailContainerEvents. In the Initialized method, we can than access the service instances of the MonoRail container. The WebContainer class is a class derived from WindsorContainer that handles the Windsor integration for MonoRail.

   1: public class WebContainer : WindsorContainer {
   2:     public WebContainer()
   3:         : base(new XmlInterpreter(new ConfigResource())) {
   4:     }
   5:  
   6:     public void Init() {
   7:         AddFacility("rails", new MonoRailFacility());
   8:     }
   9: }

Simple like that. With all these pieces of code set up, I can now have the services be injected into my components, for example:

   1: public class DefaultMailService : IMailService {
   2:     private const string defaultFrom = "my application <mail@localhost>";
   3:     private const string defaultMailLayout = "Mail.vm";
   4:  
   5:     #region dependencies - Injected by Windsor
   6:     public IEmailTemplateService Templates { get; set; }
   7:     public IEmailSender Sender { get; set; }
   8:     #endregion
   9:  
  10:     #region IMailService Members
  11:     public void SendActivationMail(string name, string email, string ticket) {
  12:         log.InfoFormat("Sending activation mail to {0}", email);
  13:         var msg = Templates.RenderMailMessage("Activate", defaultMailLayout, new {name, ticket});
  14:         msg.To = email;
  15:         msg.From = defaultFrom;
  16:         Sender.Send(msg);
  17:     }
  18:     #endregion
  19: }

Thanks to the guys from the Castle mailing list.

Posted in: Castle | Snippets

Tags: , , , ,

Pingbacks and trackbacks (1)+