KiGG Design And Architecture – Part 4 Inside Infrastructure

by mosessaur| 30 January 2010| 3 Comments

Introduction

This is part 4 of this series which I don’t know when it will ends :o). In part 3 I started to to explore the Core of KiGG. In this part we are still inside the core, but we are going further deep to have a look inside the infrastructure.

I’m going to talk about infrastructure for the next couple of posts or maybe more. Because actually it contains the heart of KiGG. For me this is a really interesting topic, it is kind of like a hobby but whereas other people like swimming or playing Poker Online, I like investigating infrastructures. I hope that you find what I write interesting and informative.

Infrastructure Elements

I’m going to explore 2 elements of Infrastructure in this post, Bootstrapper and Background Tasks.

Bootstrapper

Contains declaration of IBootstrapperTask. Infrastructure for all tasks that should be executed upon application start. Examples of this are creating default users for KiGG implemented with CreateDefaultUsers. Also starting all background tasks/services such as twitter messaging service –Background tasks will be discussed below-

Listing 1: IBootstrapperTask
  1. public interface IBootstrapperTask
  2. {
  3.     void Execute();
  4. }
Listing 2:StartBackgroundTasks
  1. public class StartBackgroundTasks : IBootstrapperTask
  2. {
  3.     private readonly IBackgroundTask[] _tasks;
  4.  
  5.     public StartBackgroundTasks(IBackgroundTask[] tasks)
  6.     {
  7.         Check.Argument.IsNotEmpty(tasks, "tasks");
  8.  
  9.         _tasks = tasks;
  10.     }
  11.  
  12.     public void Execute()
  13.     {
  14.         _tasks.ForEach(t => t.Start());
  15.     }
  16. }

In Listing 2 StartBackgroundTasks it implements Execute method declared in IBootstrapperTask interface. It just invokes Start method of all background tasks -will be discussed next- passed in the constructor of this class.

Listing 3: Controller Factory
  1. public class RegisterControllerFactory : IBootstrapperTask
  2. {
  3.     private readonly IControllerFactory _controllerFactory;
  4.  
  5.     public RegisterControllerFactory(IControllerFactory controllerFactory)
  6.     {
  7.         Check.Argument.IsNotNull(controllerFactory, "controllerFactory");
  8.  
  9.         _controllerFactory = controllerFactory;
  10.     }
  11.  
  12.     public void Execute()
  13.     {
  14.         ControllerBuilder.Current.SetControllerFactory(_controllerFactory);
  15.     }
  16. }

Listing 3 shows one useful implementation of IBootstrapperTask, its RegisterControllerFactory bootstrapper task. This class registers the desired ASP.NET MVC controller factory. It worth to mention that all bootstrapper tasks are invoked during application start in ASP.NET MVC. This way controller factory will be registered in correct time. Same thing for routes, there is RegisterRoutes bootstrapper task that is responsible for registering routes for ASP.NET MVC application.

Note: Background tasks are passed to StartBackgroundTasks bootstrapper task constructor through dependency injection.

Background Tasks

Contains declaration of IBackgroundTask and its base implementation BaseBackgroundTask. Background tasks could be something like background email service responsible for sending notification emails for subscribed comments and sending twitter messages for new or published stories.

Listing 4: IBackgroundTask
  1. public interface IBackgroundTask
  2. {
  3.     bool IsRunning
  4.     {
  5.         get;
  6.     }
  7.  
  8.     void Start();
  9.  
  10.     void Stop();
  11. }


Listing 5: BaseBackgroundTask
  1. public abstract class BaseBackgroundTask : IBackgroundTask
  2. {
  3.     private readonly IEventAggregator _eventAggregator;
  4.  
  5.     protected BaseBackgroundTask(IEventAggregator eventAggregator)
  6.     {
  7.         Check.Argument.IsNotNull(eventAggregator, "eventAggregator");
  8.  
  9.         _eventAggregator = eventAggregator;
  10.     }
  11.  
  12.     public bool IsRunning
  13.     {
  14.         get;
  15.         private set;
  16.     }
  17.  
  18.     protected internal IEventAggregator EventAggregator
  19.     {
  20.         [DebuggerStepThrough]
  21.         get
  22.         {
  23.             return _eventAggregator;
  24.         }
  25.     }
  26.  
  27.     public void Start()
  28.     {
  29.         OnStart();
  30.         IsRunning = true;
  31.     }
  32.  
  33.     public void Stop()
  34.     {
  35.         OnStop();
  36.         IsRunning = false;
  37.     }
  38.  
  39.     protected abstract void OnStart();
  40.  
  41.     protected abstract void OnStop();
  42.  
  43.     protected internal SubscriptionToken Subscribe<TEvent, TEventArgs>(Action<TEventArgs> action)
  44.         where TEvent : BaseEvent<TEventArgs> where TEventArgs : class
  45.     {
  46.         return _eventAggregator.GetEvent<TEvent>().Subscribe(action, true);
  47.     }
  48.  
  49.     protected internal void Unsubscribe<TEvent>(SubscriptionToken token)
  50.         where TEvent : BaseEvent
  51.     {
  52.         _eventAggregator.GetEvent<TEvent>().Unsubscribe(token);
  53.     }
  54. }

IBackgroundTask Interface has 2 methods Start & Stop. In base class BaseBackgroundTask, those 2 methods are implemented and are not overridable. However there are 2 abstract methods that you can implement OnStart & OnStop. And example of this implementation can be found in the next lists for SendMail class which implements BaseBackgroundTask.

Note: BaseBackgroundTask uses IEventAggregator –which applies Event Aggregator pattern- Rashid has a cool a post about it. I’m not going to cover event aggregator in infrastructure posts because Rashid already did long time ago. Please refer to his post.

Listing 6: SendMail
  1. public class SendMail : BaseBackgroundTask
  2. {
  3.     private readonly IEmailSender _emailSender;
  4.  
  5.     private SubscriptionToken _commentSubmitToken;
  6.     private SubscriptionToken _commentMarkAsOffendedToken;
  7.     private SubscriptionToken _commentSpamToken;
  8.     private SubscriptionToken _storyApproveToken;
  9.     private SubscriptionToken _storyDeleteToken;
  10.     private SubscriptionToken _storyMarkAsSpamToken;
  11.     private SubscriptionToken _storySpamToken;
  12.     private SubscriptionToken _storyPublishToken;
  13.     private SubscriptionToken _possibleStorySpamToken;
  14.     private SubscriptionToken _possibleCommentSpamToken;
  15.  
  16.     public SendMail(IEventAggregator eventAggregator, IEmailSender emailSender) : base(eventAggregator)
  17.     {
  18.         Check.Argument.IsNotNull(emailSender, "emailSender");
  19.  
  20.         _emailSender = emailSender;
  21.     }
  22.  
  23.     protected override void OnStart()
  24.     {
  25.         if (!IsRunning)
  26.         {
  27.             _commentSubmitToken = Subscribe<CommentSubmitEvent, CommentSubmitEventArgs>(CommentSubmitted);
  28.             _commentMarkAsOffendedToken = Subscribe<CommentMarkAsOffendedEvent, CommentMarkAsOffendedEventArgs>(CommentMarkedAsOffended);
  29.             _commentSpamToken = Subscribe<CommentSpamEvent, CommentSpamEventArgs>(CommentSpammed);
  30.             _storyApproveToken = Subscribe<StoryApproveEvent, StoryApproveEventArgs>(StoryApproved);
  31.             _storyDeleteToken = Subscribe<StoryDeleteEvent, StoryDeleteEventArgs>(StoryDeleted);
  32.             _storyMarkAsSpamToken = Subscribe<StoryMarkAsSpamEvent, StoryMarkAsSpamEventArgs>(StoryMarkedAsSpam);
  33.             _storySpamToken = Subscribe<StorySpamEvent, StorySpamEventArgs>(StorySpammed);
  34.             _storyPublishToken = Subscribe<StoryPublishEvent, StoryPublishEventArgs>(StoryPublished);
  35.             _possibleStorySpamToken = Subscribe<PossibleSpamStoryEvent, PossibleSpamStoryEventArgs>(PossibleSpamStoryDetected);
  36.             _possibleCommentSpamToken = Subscribe<PossibleSpamCommentEvent, PossibleSpamCommentEventArgs>(PossibleSpamCommentDetected);
  37.         }
  38.     }
  39.  
  40.     protected override void OnStop()
  41.     {
  42.         if (IsRunning)
  43.         {
  44.             Unsubscribe<CommentSubmitEvent>(_commentSubmitToken);
  45.             Unsubscribe<CommentMarkAsOffendedEvent>(_commentMarkAsOffendedToken);
  46.             Unsubscribe<CommentSpamEvent>(_commentSpamToken);
  47.             Unsubscribe<StoryApproveEvent>(_storyApproveToken);
  48.             Unsubscribe<StoryDeleteEvent>(_storyDeleteToken);
  49.             Unsubscribe<StoryMarkAsSpamEvent>(_storyMarkAsSpamToken);
  50.             Unsubscribe<StorySpamEvent>(_storySpamToken);
  51.             Unsubscribe<StoryPublishEvent>(_storyPublishToken);
  52.             Unsubscribe<PossibleSpamStoryEvent>(_possibleStorySpamToken);
  53.             Unsubscribe<PossibleSpamCommentEvent>(_possibleCommentSpamToken);
  54.         }
  55.     }
  56.  
  57.     internal void CommentSubmitted(CommentSubmitEventArgs eventArgs)
  58.     {
  59.         _emailSender.SendComment(eventArgs.DetailUrl, eventArgs.Comment, eventArgs.Comment.ForStory.Subscribers);
  60.     }
  61.  
  62.     internal void CommentMarkedAsOffended(CommentMarkAsOffendedEventArgs eventArgs)
  63.     {
  64.         _emailSender.NotifyCommentAsOffended(eventArgs.DetailUrl, eventArgs.Comment, eventArgs.User);
  65.     }
  66.  
  67.     internal void CommentSpammed(CommentSpamEventArgs eventArgs)
  68.     {
  69.         _emailSender.NotifyConfirmSpamComment(eventArgs.DetailUrl, eventArgs.Comment, eventArgs.User);
  70.     }
  71.  
  72.     internal void StoryApproved(StoryApproveEventArgs eventArgs)
  73.     {
  74.         _emailSender.NotifyStoryApprove(eventArgs.DetailUrl, eventArgs.Story, eventArgs.User);
  75.     }
  76.  
  77.     internal void StoryDeleted(StoryDeleteEventArgs eventArgs)
  78.     {
  79.         _emailSender.NotifyStoryDelete(eventArgs.Story, eventArgs.User);
  80.     }
  81.  
  82.     internal void StoryMarkedAsSpam(StoryMarkAsSpamEventArgs eventArgs)
  83.     {
  84.         _emailSender.NotifyStoryMarkedAsSpam(eventArgs.DetailUrl, eventArgs.Story, eventArgs.User);
  85.     }
  86.  
  87.     internal void StorySpammed(StorySpamEventArgs eventArgs)
  88.     {
  89.         _emailSender.NotifyConfirmSpamStory(eventArgs.DetailUrl, eventArgs.Story, eventArgs.User);
  90.     }
  91.  
  92.     internal void StoryPublished(StoryPublishEventArgs eventArgs)
  93.     {
  94.         _emailSender.NotifyPublishedStories(eventArgs.Timestamp, eventArgs.PublishedStories);
  95.     }
  96.  
  97.     internal void PossibleSpamStoryDetected(PossibleSpamStoryEventArgs eventArgs)
  98.     {
  99.         _emailSender.NotifySpamStory(eventArgs.DetailUrl, eventArgs.Story, eventArgs.Source);
  100.     }
  101.  
  102.     internal void PossibleSpamCommentDetected(PossibleSpamCommentEventArgs eventArgs)
  103.     {
  104.         _emailSender.NotifySpamComment(eventArgs.DetailUrl, eventArgs.Comment, eventArgs.Source);
  105.     }
  106. }

Listing 5 shows one implementation of background tasks which is SendMail. This background task simply listens -subscribes- to few events. The subscription is done on its OnStart method implementation. When one of those events fire (published) the corresponding event handler method will be executed in the background.

All background tasks are loaded using dependency injection and are configurable using unity configuration (the default) or your preferred IoC framework configuration.

Also all background tasks should be loaded once in memory. Using unity they are configured to with singleton lifetime manager “ContainerControlledLifetimeManager”.

Conclusion

This was a short quick post to discuss 2 elements of KiGG infrastructure. We talked about Bootstapper tasks which should provide a clean way provide set of operations that should be done upon application start. This should cover registering routes for ASP.NET MVC and registering controller factory as shown in this post.
There is also background tasks such as SendMail background task that should run as background service that listens to few events and do some action when one of these events fires.

In next post we will have a look inside other KiGG infrastructure elements, so stay tuned if you are interested.

Comments (3) -

Marwan
Marwan Tunisia on 1/29/2010 2:19 AM Thanks Mohamed,
This is the best part in the serie ;)
Muhammad Mosa
Muhammad Mosa Egypt on 1/29/2010 5:32 PM Thank you Marwan. I really hope that next parts that will cover infrastructure will be as good as this one.
Happy that you liked it brother
ThangChung
ThangChung Vietnam on 2/28/2010 4:16 PM I love Background Tasks. It's very cool. Muhammad Mosa, As far as I know, KiGG followed with DDD. But in Backgound Task, it's implemented with Event Aggregator pattern. So maybe it is DDDD for fire and forget pattern, Is it?

Pingbacks and trackbacks (2)+

Comments are closed