Chapter 24. Spring.NET ASP.NET MVC Infrastructure for ASP.NET MVC 2.0

24.1. Introduction to Spring.NET ASP.NET MVC Infrastructure

The Spring.NET for ASP.NET MVC Infrastructure increases your productivity when you write ASP.NET MVC 2.0 applications by making the full power of the Spring.NET framework available to your MVC projects.

Highlights of the Spring.NET for ASP.NET MVC Infrastructure (also referred to in this document as Spring.Web.Mvc) are:

  • Dependency Injection of Controllers and ActionFilters. ASP.NET MVC 2.0 provides two primary extensbility points for Dependency Injection: Controllers and ActionFilters. Spring.Web.Mvc makes it extremely simple to inject dependencies into either your MVC Controllers or ActionFilters. Simply register your Controllers and ActionFilters with the context using any one of the typical object definition approaches supported by Spring.NET and the Spring.Web.Mvc infrastructure will ensure these objects are assembled correctly when the ASP.NET MVC run-time has need of them.

  • Web object scopes. Just as with the Spring.NET Web Infrastructure for ASP.NET Webforms, Spring.Web.Mvc objects can be defined at the application, session, or request scope. This capability makes it easy to inject, for example, a session scoped shopping cart, into your controllers without any lower level programming.

The Spring.NET distribution ships with a Web.Mvc Quick Start application. The Web.Mvc QuickStart is the best way to see how to integrate Spring.Web.Mvc into your own ASP.NET MVC applications.

24.2. Automatic context loading and hierarchical contexts

24.2.1. Configuration of a ASP.NET MVC Application

Spring.Web.Mvc builds on top of the Spring.NET IoC container. Controllers and ActionFilters that make up a typical Spring.Web.Mvc-enabled application are configured with the same standard Spring.NET XML configuration syntax used for non web objects. To integrate with the ASP.NET MVC runtime you need to make a few modifications to your Web.config file and your Global.asax.

The instantiation and configuration of the Spring.NET IoC container by the Spring.Web.Mvc infrastructure is wholly transparent to application developers, who typically never have to explicitly instantiate and configure an IoC container manually (by, for example, using the new operator in C#). To effect the transparent bootstrapping of the IoC container, you need to modify the primary Application class in the Global.asax so as to derive it from the special SpringMvcApplication class as shown in the following snippet:

    public class MvcApplication : SpringMvcApplication
    {
        
    }

Note that the SpringMvcApplication class is abstract so that developers may only use it indirectly as a superclass of their own global application class in the Global.asax of their ASP.NET MVC applications.

After the Global.asax is modified as indicated above, you also need to define a root application context by adding a Spring.NET configuration section to your Web.config file. The final configuration file should resemble the following; your exact configuration may vary in particulars and the following snippet illustrates only the Spring-specfic entries and excludes the remainder of the content (typically) required by ASP.NET MVC.

<?xml version="1.0" encoding="utf-8"?>
<configuration>

    <configSections>
        <sectionGroup name="spring">
          <section name="context" type="Spring.Context.Support.MvcContextHandler, Spring.Web.Mvc"/>
        </sectionGroup>
    </configSections>

    <spring>
        <context>
            <resource uri="~/Config/Controllers.xml"/>
            <resource uri="~/Config/Filters.xml"/>
            <resource uri="~/Config/Production/Services.xml"/>
            <resource uri="~/Config/Production/Dao.xml"/>
        </context>
    </spring>

</configuration>

Notes about the preceding configuration:

  • Define a custom configuration section handler for the <context> element. If you use Spring.NET for many applications on the same web server, it might be easier to move the whole definition of the Spring.NET section group to your machine.config file.

  • The custom configuration section handler is of the type Spring.Context.Support.MvcContextHandler which in turn instantiates an IoC container of the type Spring.Context.Support.MvcApplicationContext. This ensures that all features provided by Spring.Web.Mvc, such as request and session-scoped object definitions, are handled properly.

  • Within the <spring> element, define a root context element. Next, specify resource locations that contain the object definitions that are used within the web application (such as service or business tier objects) as child elements within the <context> element. Object definition resources can be fully-qualified paths or URLs, or non-qualified, as in the example above. Non-qualified resources are loaded using the default resource type for the context, which for the MvcApplicationContext is the WebResource type.

  • The object definition resources do not have to be the same resource type (for example, all file://, all http://, all assembly://, and so on). This means that you can load some object definitions from resources embedded directly within application assemblies (assembly://) while continuing to load other object definitions from web resources that can be more easily edited.

24.2.2. Customizing the Behavior of the ASP.NET MVC Application Class

The default behavior, settings, ASP.NET MVC start-up related and Spring.NET container-configuration behaviors can be modified and controlled by overriding various methods of the SpringMvcApplication in your own derived instance. The following section describes these overridable methods and their existing behavior provided in the base SpringMvcApplication class. Please note that if you choose to override any of these methods and do not subsequently invoke the base SpringMvcApplication class' implementation of that same method, then you are completely responsible for ensuring that the underlying reponsibilities of that method in the base class are satisfied by your overloaded implementation. Without either ensuring this or invoking the base class implementation within your overridden method, the underlying behavior of the ASP.NET MVC runtime (and its integration with Spring.NET) is unlikley to function as intended.

24.2.2.1. Application_Start(object sender, EventArgs e)

This method is provided by the Microsoft base HttpApplication class and is overridden in the SpringMvcApplication base class to be responsible for invoking the RegisterRoutes() and RegisterAreas() methods. If you choose to override the Application_Start() implementation of the SpringMvcApplication class in your own implementation, ensure that you either call base.Application_Start() or explicitly invoke both the RegisterRoutes() and RegisterAreas() methods within your within your override of this method.

24.2.2.2. ConfigureApplicationContext()

This method is invoked by the SpringMvcApplication class after it has been configured with all of its object definitions and other settings (as detailed in Configuration of a ASP.NET MVC Application) but immediately prior to its being handed off to the ASP.NET MVC infrastructure for its use. Overridding this method provides you with your last possible moment to make any additional modifications to the IApplicationContext before it is put into service for the ASP.NET MVC framework's use. In the SpringMvcApplication base class, this method is a no-op and thus does nothing. It exists only to provide an extensibility point for developers wishing to interact with the IApplicationContext at this point in the application startup/context configuration lifecycle.

24.2.2.3. RegisterSpringControllerFactory()

This method is responsible for registering the SpringControllerFactory with the ASP.NET MVC framework, in effect telling ASP.NET MVC "please use the SpringControllerFactory to create Controllers." This is the manner in which the Spring.NET container is subsequently invoked to satisfy dependencies on Controllers when they are instantiated by ASP.NET MVC in response to an Http Request. Generally, there should be little need for the developer to override this method, but if you do you must ensure that your either invoke the base implementation of RegisterSpringControllerFactory() from within your implementation or that you explicitly register the SpringControllerFactory with the ASP.NET MVC infrastructure yourself from witihin this method (or elsewhere at the appropriate time).

24.2.2.4. RegisterRoutes(RouteCollection routes)

This method is responsible for registering ASP.NET MVC Routes during application startup and is automatically invoked from within the Application_Start() method in the SpringMvcApplication base class. The provided implementation of this method in the SpringMvcApplication class merely registers the same Default route as is present in any new ASP.NET MVC project that Visual Studio creates (e.g., "{controller}/{action}/{id}"). As such it is expected that most developers will override this method and provide their own implementation wherein they will register their own routes. Unless you desire to retain the out-of-the-box Default routing configuration of "{controller}/{action}/{id}" it is not necessary for developers to call the RegisterRoutes() method of the SpringMvcApplication base class from within their own overrides of this method.

24.2.2.5. RegisterAreas()

This method is responsible for registering ASP.NET MVC Areas during application startup and is automatically invoked from within the Application_Start() method in the SpringMvcApplication base class. The provided implementation of this method in the SpringMvcApplication class merely invokes AreaRegistration.RegisterAllAreas() in the ASP.NET MVC framework. As such, it is not common to have to override this method as provided in the SpringMvcApplication base class unless you desire more fine-grained control over registering areas. If you choose to override this method in your own derived class, you are assuming the responsibility of registering all Areas with the ASP.NET MVC runtime.

24.3. Web object scopes

Spring.NET web applications support an additional attribute within object definition elements that allows you to control the scope of an object:

<object id="myObject" type="MyType, MyAssembly" scope="application | session | request"/>

Possible values for the scope attribute are application, session, and request. Application scope is the default, and is used for all objects with an undefined scope attribute. This scope creates a single instance of an object for the duration of the IIS application, so that the objects works exactly like the standard singleton objects in non-web applications. Session scope defines objects so that an instance is created for each HttpSession. This scope is ideal for objects such as user profile, shopping cart, and so on that you want bound to a single user.

Request scope creates one instance per HTTP request. Unlike calls to prototype objects, calls to IApplicationContext.GetObject return the same instance of the request-scoped object during a single HTTP request. This allows you, for example, to inject the same request-scoped object into multiple pages and then use server-side transfer to move from one page to another. As all the pages are executed within the single HTTP request in this case, they share the same instance of the injected object.

Objects can only reference other objects that are in the same or broader scope. This means that application-scoped objects can only reference other application-scoped objects, session-scoped objects can reference both session and application-scoped objects, and request-scoped objects can reference other request-, session-, or application-scoped objects. Also, prototype objects (including all ASP.NET web pages defined within Spring.NET context) can reference singleton objects from any scope, as well as other prototype objects.