Blades - What are they and how do the work?

Oct 12, 2010 at 11:49 PM

Hi!

So I've been fiddling with Darren's MVC3 Beta version of MvcTurbine (MT) and I hooked everything up and it works great, but I still have some questions.

Mainly I'd like to know what blades are for and how they work. I experimented a bit and as far as I can see they're used for telling MT about some interface/class and then their Spin method is fired when an instance of that object is needed.

I've got an example scenario here:

Let's say I have an intefrace ITask and I have 2 implementations of ITask: Task and BigTask.

Now I've built a very basic blade TaskerBlade:

class TaskerBlade : Blade, ISupportAutoRegistration
{
     public void AddRegistrations(AutoRegistrationList registrationList)
     {
         registrationList.Add(Registration.Simple<ITask>());
     }

     public override void Spin(MvcTurbine.IRotorContext context)
     {
     }
}

I also have a HomeController which need ITask in the constructor. MT will always inject (if that's the correct term here) the Task implementation. Why is that?

I know that if I add registrations to Ninject's kernel I can control this, but that's not the point. I thought maybe it was something to do with class/file names so I rename the interface IBigTask and corrected at all the necessary location, but I still gor the Task implementation.

 

Thnx,

Goran

Oct 13, 2010 at 1:45 AM

Goran,

I think I can explain what is going on, but the first question I have is... what do you need it to do?  

That said, the blade is actually spun once when the MVC application starts, and never again.  It's often used for logic and setup that would normally be placed in Application_Start or somewhere else in your global.asax.  Spin() gets called once, it will execute your logic, and then that's it.  

If your blade also implements ISupportAutoRegistration, you get another method: AddRegistrations(AutoRegistrationList registrationList).  This gives you a chance to "auto register" specific types.  Usually, this is used to ask Turbine to register all implementations of an interface (like you're doing with ITask).  

Looking at your blade, all it is doing is telling Ninject to register Task and BigTask with ITask.  Then when your HomeController is instantiated, Ninject is making the decision to use Task (not Turbine).  If you make your HomeController dependent on ITask[], you should get both Task and BigTask.

Does that help?  

 

Darren

Oct 13, 2010 at 2:16 AM

Darren I'm trying to figure out what is the simplest and the most transparent (with as few registrations as possible) way for turbine/ninject to find an implementation of an interface and supply it to the controller (or any other object in that matter).

You wrote: "If you make your HomeController dependent on ITask, you should get both Task and BigTask." What exactly do you mean? Because I set up a breakpoint in the HomeController's constructor, but it gets called 4 times, but always with Task.

 

As you probably see, I'm kinda new to this, so if you don't have time for this, there's no rush. And I do think that other newbies could use this kinds of Q&As :)

 

Goran

Oct 13, 2010 at 2:32 AM

Goran,

The simplest way to register an interface is not a Blade, but an implementation of IServiceRegistration.  Here is an example:

    public class BigTaskRegistration : IServiceRegistration  
    {

        public void Register(IServiceLocator locator)

        {

            locator.Register<ITask, BigTask>();

        }

    }

During the application startup, MVC Turbine will find all implementations of IServiceRegistration and run the service locator (your IoC container) through them.  In this case, I'm registering BigTask with ITask.  If you replace your blade with this class, you'll find that your HomeController will get BigTask, not Task.

What I mean about HomeController getting both implementations of ITask:  This is more of a question about IoC in .Net than MVC Turbine, but I can try to help.  Your blade was registering *both* Task and BigTask.  If you ask your IoC container to return *all* ITask, it will give you both.  But if you ask your IoC container to return *one* ITask, it will give you one of the set.  In your case, that is Task.

Your HomeController will be instantiated more than once (which is another issue addressed here http://mvcturbine.codeplex.com/Thread/View.aspx?ThreadId=229825), but your blade will only be instantiated once.  

Does that help?  Keep any questions coming. :)

 

Darren

Coordinator
Oct 13, 2010 at 2:36 AM

Hi Goran,

I hate to use this generic answer, but "It depends" :) -- now to clarify it a little bit...

If you want to use the built-in registration pieces from Turbine, you can create the following class:

public class MyServiceRegistrations : IServiceRegistrator {
     public void Register(IServiceLocator locator) {
            locator.Register<ITask, Task>();
     }
}

This does nothing more than wrap call for Ninject to perform, Bind<ITask>.To<Task>() - the IServiceRegistrator interface is a Turbine specific interface that allows extension (Blade) authors to register components regardless of the underlying DI container. This is very powerful when you're building a re-usable component that will overlap several projects.

The other way, and preferred way, is for you to leverage your IoC container. Again, if you're using Ninject you can do the following:

public class DefaultMvcApplication : TurbineApplication {
    static DefaultMvcApplication() {
            // Initialize the Ninject Kernel
            IKernel kernel = InitializeNinject();

            // Tell the MVC Turbine runtime to use the initialized kernel
            ServiceLocatorManager.SetLocatorProvider(() => new NinjectServiceLocator(kernel));
    }

    static IKernel InitializeNinject() {
            IKernel kernel = new StandardKernel();

            // Add your type registration here
            kernel.Bind<ITask>().To<Task>();

            return kernel;
     }
}
As you can see, you can fully leverage your container of choice and easily pass it to Turbine to use.  Again, it's completely up to you on which path you want to and leverage within your application.

Coordinator
Oct 13, 2010 at 2:47 AM

Hi Goran,

I just wanted to add more info to Darren's awesome response.  :)

The easiest way to think of a Blade is to equate it to an extension (like a jQuery plugin) for cross-cutting concerns.  As Darren mentioned, their sole purpose is to house logic that is specific to a cross-cutting concern. For example, you can create a log4net Blade that deals with the registration, setup, etc. necessary for an application to use log4net.

If you want to see what type of extensions you can build around this Blade concept, I encourage you to checkout out these samples - http://github.com/jglozano/mvcturbine/tree/master/src/Blades/

And keep the questions coming!

Oct 13, 2010 at 10:18 PM

Hey,

Sorry for a little late of a response. I've been playing with MT and then got caught in all these Chile drama :)

Anyhow you guys are great. I get blades now. It's really simple when you think of it :)

I already found both ways to go about registering types and specifying their registration, I just thought there is a more transparent way. Because, especially in the 2nd example, I can't see why wouldn't I just use Ninject.MVC3 (the latest - 0.3 - version supports MVC3 Beta and it's IDependencyResolver) without MT.

But I'm new to this whole DI and SL patterns and maybe my mind isn't really wrapped around this whole idea yet. So I decided to use MT for a little side project I'm starting and I hope I can learn about it through practical use.

I'll of course ask more questions when I get to them :)

 

Thanks for your help,

Goran

Coordinator
Oct 13, 2010 at 10:34 PM

Hi Goran,

No worries, we understand :)

As for what's best for you to use, well that's completely up to you and your comfort. Everything that Turbine does can be achieved with Ninject (with a little work). I say that since Ninject is a DI container, not a composition plugin like Turbine.  So if you're looking for simple DI pieces, Ninject might be the way to go. If you're looking for getting more out of MVC via re-usable components, then Turbine (or similar) is the way to go since it provides the DI + Composition features.

Any ways, thanks for trying out Turbine and again, feel free to ask any questions :)  

Oct 14, 2010 at 3:40 AM

Javier is more polite and objective about tools than I, so he's going to say that Ninject is good and can get the job done and that you should go with what works for you. 

I'm not as polite, so let me tell you my view:  I don't think there is one reason *not* to use MVC Turbine on an ASP.Net MVC app, even if you never want to use the composition features.  Heck, even if you don't want to use an IoC container I'd still say you should go with Turbine.  It's like free money.  You get something for nothing.  Who doesn't want that?

Here's another good sign that MVC Turbine is a good framework:  You hardly ever see it.  Most frameworks force the opinions and viewpoints of their authors down your throat, but Turbine stays behind the scenes.  I've built a handful of MVC apps with it, and during development my focus stays on building real value with the standard MVC components.  I hardly ever notice Turbine doing its work behind-the-scenes, and sometimes I even forget it's there.  

And more reasons:  Even if you don't want to make reusable components today, you might want to in the future.  Maybe you want some of the things that Javier has written, or some of the Turbine plugins that I wrote and published on GitHub?  That little bit of extra oomph that Turbine puts into MVC is what makes it possible for us to share.  Darren, a Unity developer, can make components that will plug into Javier's (a Windsor developer) applications or your MVC application (a Ninject app).  What a strange and wonderful thing, Dot Net developers working together!  Turbine breaks down the walls that would normally keep us apart (notably, IoC containers that don't play together and MVC's static nature).  

Sorry, but seeing Turbine compared to Ninject's controller-factory-in-a-dll MVC integration makes me want to shout out about Turbine's significance.  Go MVC Turbine! :)

 

 

 

 

Oct 14, 2010 at 5:12 AM

Heh, Darren I hope I didn't upset you too much with my last post. If I did, I'm sorry. I wasn't comparing MT and Ninject in a general matter, I was just trying to understand what more MT gives me in that particular situation.

I do see what you mean by reusable code and how MT achieves that. There is a part of you post that got me very curious: "Heck, even if you don't want to use an IoC container I'd still say you should go with Turbine." What features of MT would you use then? Or would you just have it so that if someone else would to extend you code it would be easier and more compatible?

 

There is on more thing. You and Javier both talked about something called a "composition plugin". What does that mean?

I'm not a native english speaker so this may be a stupid question, or I just may have too little knowledge about OO. I've been a C# programmer since it came out I guess, but have been working with PHP at my job for the last 2. I had school to deal with, so OO and C# were kind of on hold - till now. School's behind me and during my PHP era I grew fond of web development and now I'm trying to join it with my favorite programming language. This is why for the pass month or so I've been researching ASP.NET MVC and some aspects that people seem to be talking about when they talk about MVC.

During this era I came across Scott Hanselman and his tutorial Nerd Dinner. He made a repository pattern in it and mentioned DI. That's how I came across MT and you guys.

 

Reading my post through again I figured out that what would I like to know is what features MT provides.

 

Hope I don't get anyone irritated again :)

Goran

Oct 14, 2010 at 3:41 PM

Hi Goran,

Haha, no, I'm not annoyed.  I'm just acting on my unofficial role as MVC Turbine Cheerleader.  If anything, I'd be annoyed at Javier for being so objective about his tool when it is a superior tool. :)

He or I can explain the composition stuff, but I can't until lunch or the evening. Back to work for me.

 

Darren

Oct 14, 2010 at 4:16 PM

Hehe :)

I would appreciate an explanation, but there's no hurry. When you have the time. Or if you have a good link I could read through.

 

Thnx,

Goran

Oct 15, 2010 at 1:40 PM

Goran,

With regards to MVC Turbine (and most frameworks or apps in general), being "composable" means that the app is made up of smaller components, each of which can be swapped or rearranged as necessary.  Instead of your MVC application being one *big* application that does a lot of things, your MVC application is the sum of many *small* applications that each do one thing.

They might seem similar, but the latter is much more maintainable.  Any of those smaller applications can be added, removed, or changed without affecting any of the other smaller applications.  With the former, the different pieces of functionality tend to "melt" together, making it hard to determine what's needed for what and what's safe to edit/add/remove.

MVC Turbine makes composition possible by rooting into the MVC framework and adding hooks that anybody can attach to.  You can inject controllers, views, or other functionality into your application, simply by adding a reference to a dll.  It helps to make MVC follow a more "open-closed" nature by allowing the application to be extended without having to modify it.

I've recorded a number of screencasts showing how to do this-or-that with MVC Turbine.  I'm putting the links below.  While my videos are specific to one situation, there is a common thread between all of them -- I'm adding functionality to my MVC application by adding a reference to a dll.  The code contained in those dlls are "sucked into" my MVC application without any additional work on my part.  Without Turbine, adding this type of functionality would require the copy-paste of dozens of files, turning my application into a big mess.  

I hope that helps, here are the videos:

Adding the Log Reporting Dashboard to your ASP.Net MVC app (with MVC Turbine) http://www.youtube.com/watch?v=Hicjp5MODpI

MvcTurbine.MetadataProvider Demo http://www.youtube.com/watch?v=LHzzBwMNFNM

MvcTurbine.EmbeddedViews blade http://www.youtube.com/watch?v=9D7V65DGQWM

MvcTurbine Routing Demonstration (look at the GoogleSiteMap near the end) http://www.youtube.com/watch?v=9D7V65DGQWM

 

Oct 15, 2010 at 10:07 PM

Oh, now I get it :) Finally I think I got the big picture of this whole thing (or at least most of it).

Now I know why Javier is always talking about auto-wiring.

I think now I really just have to put all this knowledge into practice and I'll probably have some more questions in a while.

 

So thanks to Javier and especially to you Darren for helping me out :)

Bye,

Goran