Click here to Skip to main content
15,886,788 members
Articles / Programming Languages / C#
Article

Extensible point in ASP.NET MVC: ControllerFactory Class to Handle Controller Instantiation

Rate me:
Please Sign up or sign in to vote.
3.00/5 (2 votes)
23 Jul 2014CPOL5 min read 10.4K   3  
This is Extensible point in ASP.NET MVC article series. In this series, we will discuss various Extensible points of MVC framework.

Introduction

This is the first article of Extensible point of ASP.NET MVC architecture series. In this series, I would like to describe various extensible points of ASP.NET MVC framework. We know that MVC framework is very popular in Microsoft’s web technology which gives the real idea of separation of concern. MVC framework is built to keep in mind that every software component will be bits and pieces and they will be highly de-coupled. So there is full flexibility to attach and detach those components. Similarly, those bits and pieces are highly extensible. For example, if developer thinks that some default setting of some module or component does not work for here, she always use extension and re-define it on her own to give it proper shape. Some of the extensible points of ASP.NET are in routing, in time of controller creation, in time of view creation and many more.

In this article, I am planning to talk about the extensibility in time of controller creation, how we can write and inject our own logic in time of controller initialization, with example. So let’s start to understand the controller creation mechanism.

IControllerFactory Interface

This interface is on top of controller initialization mechanism. It is located in System.Web.Mvc namespace in class library. It contains three methods. The CreateController method is responsible for creating an instance of controller which takes two arguments, the first one is request context which carries all the information of current HTTP request including user’s context like whether user is authenticated or not or the username. The second argument is plant string type which takes controller name. It will take the controller name in which current HTTP request wants to hit.

C#
namespace System.Web.Mvc
{
    // Summary:
    //     Defines the methods that are required for a controller factory.
    public interface IControllerFactory
    {
        // Summary:
        //     Creates the specified controller by using the specified request context.
        //
        // Parameters:
        //   requestContext:
        //     The request context.
        //
        //   controllerName:
        //     The name of the controller.
        //
        // Returns:
        //     The controller.
        IController CreateController(RequestContext requestContext, string controllerName);
        //
        // Summary:
        //     Gets the controller's session behavior.
        //
        // Parameters:
        //   requestContext:
        //     The request context.
        //
        //   controllerName:
        //     The name of the controller whose session behavior you want to get.
        //
        // Returns:
        //     The controller's session behavior.
        SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
        //
        // Summary:
        //     Releases the specified controller.
        //
        // Parameters:
        //   controller:
        //     The controller.
        void ReleaseController(IController controller);
    }
}

The second method is GetControllerSessionBehavior() and the method sets the session behavior of the environment. The third method is ReleaseController(). As the name suggests, the purpose of the method is to dispose the controller instance after its use. The interface is implemented in ControllerFactory class of MVC framework’s library. Now, if our application demands more control over the controller instantiation mechanism and wants to implement those methods in our way, the door is always open for us. We can implement those methods in our own Factory class and inject the class in execution pipeline.

Implement Our Own Controller Factory from IController

Now, we will implement IControllerFactory interface in our own way. In this example, we have created our own class called “MyControllerFactory” and implemented IControllerFactory. The aim of the implementation is very simple; just we want to activate one controller. Let’s understand the CreateController method. We are taking the controller location in assembly from Web.config file, because we will use the process called reflection, then we are invoking the CreateInstance() method of Activator class , the method is taking the controller type means type of the controller class End of Day.

C#
public class MyControllerFactory : IControllerFactory
    {
        public IController CreateController
        (System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            string controllerType = string.Empty;
            IController controller = null;

            // Read Controller Class & Assembly Name from Web.Config
            controllerType = ConfigurationManager.AppSettings[controllerName];

            if (controllerType == null)
                throw new ConfigurationErrorsException
                ("Assembly not configured for controller " + controllerName);
            // Create Controller Instance
            controller = Activator.CreateInstance(Type.GetType(controllerType)) as IController;
            return controller;

        }
        public void ReleaseController(IController controller)
        {
            //This is a sample implementation
            //If pooling is used to write code to return the object to pool
            if (controller is IDisposable)
            {
                (controller as IDisposable).Dispose();
            }
            controller = null;
        }
        public SessionStateBehavior GetControllerSessionBehavior
        (RequestContext requestContext, string controllerName)
        {
            return SessionStateBehavior.Default;
        }
    }

The ReleaseController() function is implemented to dispose the controller instance as we said earlier and here is the implementation. We are keeping SessionStateBehaviour property as default. There are other few options, which are beyond our scope. Now, we will define the controller’s location in the assembly in web.config file. Just make one entry in web.config file. The value part is nothing, but the name of the controller along with namespace.

XML
<add key="Home" value="Authentication.Controllers.HomeController" />

The next point is the registration of our controller factory class. We have to register the class to inject our execution logic in MVC pipeline. Just add the below line in Application_Start() event of Global.asax page.

C#
ControllerBuilder.Current.SetControllerFactory
(typeof(Authentication.Controllers.MyControllerFactory));

Fine, we are almost done, now just define the below controller in application. Once you run the application and want to reach the Home controller, you will see the execution flow has passed through our custom controller factory class. Here is the implementation of Home controller.

C#
public class HomeController : Controller
      {
       public ActionResult Index()
       {
           return View();
       }
   }

Inject Dependency from Controller Factory

Ok, we have seen the injection of custom login in time of controller creation, now we will implement few real time scenarios where we can implement and use the custom controller factory. Let’s think about dependency in controller. If there is dependency in controller and if we use constructor injection to resolve the dependency by passing as an argument of constructor, then we may need to control factory class. We know that one of the default criteria of controller class is parameter less constructor, but in our below example we are resolving the Home controller dependency through constructor injection and for that we need to pass the dependent object in time to Home controller instantiation. To solve this issue, we will implement our own controller factory and will inject in execution pipeline. Have a look at the below code.

C#
public class LogService
    {
        public void CallLog()
        {
            //LOG activity goes here
        }
    }

    public class HomeController : Controller
    {
        LogService log = null;
        public HomeController(LogService _serviceTemp)
        {
            log = _serviceTemp;
        }

        public ActionResult Index()
        {

            return View();
        }
    }

In code, we are seeing that the Home controller is dependent on LogService object and we have to pass the instance of LogService class. So, let’s modify the CreateController() method of MyControllerFactory class like below:

C#
 public IController CreateController
(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            string controllerType = string.Empty;
            IController controller ;

            // Read Controller Class & Assembly Name from Web.Config.
            controllerType = ConfigurationManager.AppSettings[controllerName];

            //If not defined in web.config
            if (controllerType == null)
                throw new ConfigurationErrorsException("Controller not found " + controllerName);

            // Create Controller Instance using Activator class and inject reference of dependent object
            controller = Activator.CreateInstance
            (Type.GetType(controllerType),new HomeController(new LogService())) as IController;
            return controller;
        }

We are seeing that the LogService object is passing as an argument of HomeController() constructor and once we want to reach to Home controller, we will see that the dependent object has populated within constructor of Home controller.

Image 1

Though the example is just to show the workflow, in reality we should use IoC container to resolve the dependency. Here I am talking about Dependency injection in MVC controller.

Check Authentication in Controller Factory

This is another real time situation where we can implement our own controller factory. The basic aim of the controller factory is to check whether the current HTTP request is authenticated request or not? If the request is authenticated request, then it will be redirected to appropriate controller and if the request is not authenticated then it will redirect to Notauthenticated controller. Here is the simple implementation.

C#
public IController CreateController
(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            string controllerType = string.Empty;
            IController controller ;

            // Read Controller Class & Assembly Name from Web.Config.
            controllerType = ConfigurationManager.AppSettings[controllerName];

            //If not defined in web.config
            if (controllerType == null)
                throw new ConfigurationErrorsException("Controller not found " + controllerName);

            if(requestContext.HttpContext.User.Identity.IsAuthenticated)
                controller = Activator.CreateInstance(Type.GetType(controllerType)) as IController;
            else
                controller = Activator.CreateInstance(typeof(NotAuthenticatedController)) as IController;
            return controller;
        }

Image 2

And here is the final output.

Image 3

As the checking is performed in root level of controller creation, it’s very useful to such logic which needs to perform for each and every controller like Dependency injection or security checking, if all controllers or a group of controllers demands that.

Border Line

I hope you have understood the concept of controller initialization using custom controller factory class. In our next article, we will discuss another extensible point of MVC framework.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer DELL International
India India
I am software developer from INDIA. Beside my day to day development work, i like to learn new technologies to update myself. I am passionate blogger and author in various technical community including dotnetfunda.com , c-sharpcorner.com and codeproject. My area of interest is modern web technology in Microsoft stack. Visit to my personal blog here.

http://ctrlcvprogrammer.blogspot.in/

Comments and Discussions

 
-- There are no messages in this forum --