ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI

In this post I’m going to show you how we can easy create our own IControllerFactory for the ASP.Net MVC Framework and use Spring.Net to create our Controllers. I will in this post also use the Spring.Net Dependency Injection support to pass a Repository that should be used by our Controller.

To create a ControllerFactory we need to implement the IControllerFactory interface. This interface has one method, CreateController. This method takes two arguments a RequestContext and the Type of the controller to create. The MVC Framework will locate our Controller and passed in the Type to our IControllerFactory. This is something I don’t like; I want to be responsible to look up my own Controller in my way, not let the MVC Framework locate the type in their way, It will only creates some magic. If we want to change this behavior in the current preview of the MVC Framework we can create our own RouteHandler, but this is out of topic in this post. When we use Spring.Net to get an instance of an object we use a string, so we can use the Name property or the Type passed as an argument to our CreateController method to get the name of the Controller.

Here is the implementation of an IControllerFactory which will use Spring.Net to instantiate a Controller:

public class SpringControllerFactory : IControllerFactory
{
        public IController CreateController(RequestContext context, Type controllerType)
        {
            IResource input = new FileSystemResource(context.HttpContext.Request.MapPath("objects.xml"));
            IObjectFactory factory = new XmlObjectFactory(input);

            return (IController)factory.GetObject(controllerType.Name);
        }
 }

In this code I use the XmlObjectFactory to create objects out from a specified XML file, in this case the "objects.xml" file. Within the objects.xml file we can specify the objects we want to be instantiated when we are using the Spring.Net framework. I will later in this post show the content of the "objects.xml" file. But first we can take a look at the implementation of a Controller.

public class HomeController : Controller
{
        IHomeRepository _homeRepository;

        public HomeController() : this(new HomeRepository()) {}

        public HomeController(IHomeRepository homeRepository)
        {
            this._homeRepository = homeRepository;
        }

        [ControllerAction]
        public void Index()
        {
            CompanyInfo companyInfo = this._homeRepository.GetCompanyInfo();
            RenderView("Index", companyInfo);
        }

        [ControllerAction]
        public void Contact()
        {
            CompanyInfo companyInfo = this._homeRepository.GetContact();
            RenderView("Contact", companyInfo);
        }

        [ControllerAction]
        public void About()
        {
            CompanyInfo companyInfo = this._homeRepository.GetCompanyInfo();
            RenderView("About", companyInfo);
        }
 }

I decided to modify the HomeController created by the "MVC Web Application" template. My modification of the HomeController was to remove the code to fill a CompanyInfo object, and instead put it into a Repository with the name "HomeRepostory".

public class HomeRepository : IHomeRepository
{
        public CompanyInfo GetCompanyInfo()
        {
            CompanyInfo companyInfo = new CompanyInfo();
            companyInfo.CompanyName = "Your company name here";
            return companyInfo;
        }

        public CompanyInfo GetContact()
        {
            CompanyInfo companyInfo = new CompanyInfo();
            companyInfo.CompanyName = "Your company name here";
            companyInfo.AddressLine1 = "Company address Line 1";
            companyInfo.AddressLine2 = "Company address Line 2";
            companyInfo.City = "City";
            companyInfo.State = "State";
            companyInfo.Zip = "00000";
            companyInfo.Email = "
email@yourcompany.com
";
           
            return companyInfo;
        }
 }

The HomeRepository implements an interface with the name IHomeRepository. I made this design decision so I can easy mock my repositories. If we take a look at the HomeController again we can see that I have added a private field with the type IHomeRepository and also created a constructor which will take an IHomeRepository as an argument. The reason to this design is because of testability. For example if I mock the HomeRepository I can in my Test project easy inject the mock object for the Repository to my Controller.

MockHomeRepository mockHomeRepository = new MockHomeRepository();
HomeController homeController = new HomeController(mockRepository);

homeController.About();

Assert.AreEqual(((CompanyInfo)homeController.ViewData).companyInfo, "Your company name here");

By using a constructor which will take our IHomeRepository as an argument, we can also do a Constructor Injection by using the Sprin.Net framework, and that is exactly what I’m going to do in this post.

Now when we have our Controller and Repository we need to setup the “objects.xml” file with our objects and also setup a Constructor Injection. Here is the content of the “objects.xml” file:

<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="
http://www.springframework.net"
                xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="
http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">

  <object id="HomeController" type="MvcApplication.Controllers.HomeController, MvcApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
    <constructor-arg name="homeRepository" ref="HomeRepository"/>
  </object>

  <object id="HomeRepository" type="MvcApplication.Models.Repositories.HomeRepository, MvcApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
 
</objects>

The Object element specifies our objects we want to create with the Spring.Net framework. The id attribute specifies the name of the object and the type specifies the type of our object. When we use the Spring.Net framework’s GetObject method we pass in the name of the object to create, the GetObject method will look for an object with the id attribute set to the name, and instantiate the specified type. By using the <constructor-arg> element we can specify what object that should be passed into our constructor when we create the object. In this case I have specified the HomeRepository object.

When our IControllerFactory now will create our HomeController, Spring.net will create an instance of our Controller and do a constructor injection and pass in the HomeRepository object to the constructor and return our controller.

Now when we are done with all the implementation of our IControllerFactory, Controller and Repository we need to make sure our IControllerFactory should be used. This can be done in the Global.asax’s Application_Start event by using the SetDefaultControllerFactory method:

protected void Application_Start(object sender, EventArgs e)
{
   ControllerBuilder.Current.SetDefaultControllerFactory(
                           typeof(MvcApplication.Models.Infrastructure.SpringControllerFactory));
   ...
}

When we now run our application, our IControllerFactory will be used and all the creating of our Controllers will be handled by the Spring.Net framework.

Published Saturday, November 17, 2007 4:23 PM by Fredrik N
Filed under: ,

Comments

# re: ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net

Saturday, November 17, 2007 12:43 PM by J PHILIP

Thank you for this more advanced example.

I am working on a project that will use this. (Just working on the data access now with the Entity Framework)

I have been trying to keep all and only data access code in a separate assembly  and inject dependencies with Windsor. (No reference from the Core assembly to the Data assembly)

I am not sure if what I am doing is right, but I extracted interfaces from the Designer generated classes and made the Partial Class declaration inherit from theses Interfaces.

Then I have a Data access service injected by the IOC too that provide the Interfaces to the UI or test layer.

I also have a Business service living in the Core assembly injected by the IOC into the Data assembly to apply business rules.

Seems rather complex, it may be the price to pay for flexibility.

# { null != Steve } &raquo; Blog Archive &raquo; ASP.NET MVC Framework and Spring.NET

Pingback from  { null != Steve }  &raquo; Blog Archive   &raquo; ASP.NET MVC Framework and Spring.NET

# re: ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI

Saturday, November 17, 2007 7:54 PM by Evan

I hope the RequestContext class is mockable, since IControllerFactory takes a dependency on it for the CreateController method.

I'm sure at some point in the future, we are going to want to build smart factories and will want to test them.

# Link Listing - November 17, 2007

Sunday, November 18, 2007 1:42 AM by Christopher Steen

ASP.NET Detecting AJAX Requests in MonoRail [Via: Bill Pierce ] ASP.Net MVC Framework - Create your...

# Link Listing - November 17, 2007

Sunday, November 18, 2007 1:43 AM by Christopher Steen

Link Listing - November 17, 2007

# re: ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI

Sunday, November 18, 2007 4:12 AM by Fredrik N

Evan:

The RequestContext has two properties:

HttpContext : IHttpContext

RouteData : RouteData

The RouteData holds information about the Route.

When we want to write a test we use the interfaces shipped with the System.Web.Extensions namesapce. So we will have a dependency to the System.Web.Extensions in our test. Note: We still don't need to use ASP.Net to test our Controllers etc. When we write our test we could easy create an instance of the RequestContext and add the information we need to it, for example:

  IHttpContext httpContext = new MockHttpContext();

  //...

  RouteData routeData = new RouteData();

  routeData.Route = new Route("[contorller]/[action]/[id]", typeof(MockRouteHandler));

  RequestContext context = new RequestContext(httpContext, routeDate);

  IControllerFactory myFactory = new MyControllerFactory();

  IController controller = myFactory.CreateController(context, typeof(ProductController));

Hope that make sence?

# re: ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI

Sunday, November 18, 2007 4:47 AM by Torkel

This is very nice. I hope a CTP is released soon.

What are your feelings about MVC vs WebForms now? Are you starting to see the benefits of this MVC architecture?

# re: ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI

Sunday, November 18, 2007 5:04 AM by Fredrik N

Torkel:

The ASP.Net MVC Framework rocks! ;)

Well they have more to go until it will totally rock. If I want to use the normal Web Form with postback or MVC depends on the project and the needs. But I think I will mostly use the MVC Framework because of its testability etc.

# Enlaces 17 Nov: ASP.NET, ASP.NET AJX, ASP.NET MVC, VS 208, .NET 3.5, IIS7, Silverlight &laquo; Thinking in .NET

Pingback from  Enlaces 17 Nov: ASP.NET, ASP.NET AJX, ASP.NET MVC, VS 208, .NET 3.5, IIS7, Silverlight &laquo; Thinking in .NET

# SpringFramework.NET Introduction.

Sunday, November 18, 2007 10:27 PM by MS MossyBlog

I was about 30% of the way writing the introduction to SpringFramework.NET for newbies, when it occurred

# SpringFramework.NET Introduction.

Sunday, November 18, 2007 10:44 PM by Noticias externas

I was about 30% of the way writing the introduction to SpringFramework.NET for newbies, when it occurred

# MSDN Blog Postings &raquo; SpringFramework.NET Introduction.

Sunday, November 18, 2007 11:49 PM by MSDN Blog Postings » SpringFramework.NET Introduction.

Pingback from  MSDN Blog Postings  &raquo; SpringFramework.NET Introduction.

# re: ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI

Thursday, November 22, 2007 7:24 AM by dancoe

cool, being that the drive is to get mvc tdd, mocking would be a requirement.

# MVC Contrib at Lost In Tangent

Saturday, December 08, 2007 5:46 PM by MVC Contrib at Lost In Tangent

Pingback from  MVC Contrib at  Lost In Tangent

# re: ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI

Monday, December 10, 2007 4:46 PM by Darren Stokes

It seems to me that your CreateController implementation will be creating a new XMLObjectFactory() for each call.  This would recreate your singleton object definitions for each call.  I'm not sure that is what the user would expect.  You probably want to create this only once and cache it.

# ASP.Net MVC Framework - Assign a ViewFactory to a Controller

Wednesday, January 30, 2008 1:28 AM by Fredrik Normén

I have seen several posts about how to assign a ViewFactory to a Controller, most of the case the code

# ASP.Net MVC Framework - Assign a ViewFactory to a Controller

Wednesday, January 30, 2008 1:38 AM by Cornerstones utvecklarblogg

I have seen several posts about how to assign a ViewFactory to a Controller, most of the case the code

# re: ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI

Monday, May 12, 2008 8:43 PM by Steve Goyette

Hi,

This is a great post and has helped tremendously (thank you).

Is there any way to implement Session-Scoped objects?  Right now when I try I get this error: 'session'-scoped objects require SessionState to be enabled.

Of course setting <pages enableSessionState="true"> has no effect.  

Ideas?

# The MVC framework – the MvcHandler, the IControllerFactory and the ControllerBuilder types

Thursday, July 24, 2008 7:20 AM by LA.NET [EN]

As we’ve seen in the previous post , all “MVC routing requests” are handled by the MvcRouteHandler class

# The MVC framework – the MvcHandler, the IControllerFactory and the ControllerBuilder types

Thursday, July 24, 2008 8:24 AM by ASPInsiders

As we’ve seen in the previous post , all “MVC routing requests” are handled by the MvcRouteHandler class

# [翻译]在ASP.NET MVC中使用TDD与依赖注入

Wednesday, September 03, 2008 10:38 PM by 郁闷的翩翩

(代码截图为ASP.NETMVCPreview5版本)

原文地址:haacked.com/.../tdd-and-dependency-inject...

# re: ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI

Wednesday, November 26, 2008 3:07 PM by Ben

Does anyone know how often a asp.net mvc controller constructor is gets called? I assumed they would get created and destroyed with every request, but that does not seem to be the case.

# .net企业级架构实战之7——Spring.net整合Asp.net mvc

Sunday, November 30, 2008 4:56 AM by 莫耶

Leave a Comment

(required) 
(required) 
(optional)
(required)