Mar272010

HandleError attribute (MVC)

    In ASP.NET MVC you can decorate the action methods and the controllers with filter attributes to control their behavior.  These filters are injected into the pipeline, and depending on their type; they are executed before/after something happens. You can either use the filters that come with the framework, or write your own filters. Even though it is easy to test the functionality of the filters, it may not be easy to test if the controller/action is/are decorated with the filter (You can use reflection).  There are 4 different types of filters that come with the framework:

  • Authorization Filter: These type of filters have very high priority, and run before other types of filters or the action execution.
  • Action Filter: These type of filters have normal priority, and run before and after the action execution, by this way you can do some work before  an action is executed or after an action is executed. A good example could be logging the system activity, or calculating the time that takes to execute the action.
  • Result Filter: These type of filters have  normal priority, and run before and after the action result is executed, by this way, you can manipulate the action results.
  • Exception Filter: These filters are executed if an unhandled exception is thrown.

In this blog posting I will be explaining HandleError attribute which is a type of Exception Filter. You may want to use this filter to catch the exception for either logging the exception to a log file or display a nice error page so the user does not freak out.  If you create a default MVC project using Visual Studio, you will see that the HomeController class is decorated with HandleError filter.

[HandleError]
public class HomeController : Controller


This means whenever there is an exception that is not handled, render the Error view, so when there is an exception the framework will first look at the folder “Views/Home” and check if there is an Error.aspx page (assuming you are using the default WebForms Engine). If it can not find this page, it will check if there is a Error.ascx page, if there is none, then the same search will be applied to Shared folder. Finally if there is an Error.aspx/ascx page found it will be rendered, otherwise, in the production system, IIS will handle error, in the development system you may see the error below (depending on your web.config customErrors setting).

image

Or if you use the HandleError filter, and configure your system right, this may be the screen:

image

Of course you want to the second user friendly error page. Let’s first see what we should be doing to get the simple user friendly user page and then we will look into customizing this error page.

  1. Decorate the controller or the action method with HandleError
  2. Create an Error.aspx or Error.ascx page, and put this page either into the View folder of the controller or Shared folder.
  3. Open your web.config file and change the custom errors definition to customErrors mode=”On”


After this 3 simple steps, you have  an Error page that will be displayed whenever there is an unhandled exception.

HandleErrorAttribute is defined in the HandlErrorAttributed.cs (suprised?) file. It is a relatively simple and short code. If you check the source code, you will see that there are parameters you can customize.  Here are the list of the parameters that you can customize:

  • View: You can define a new View besides the Error to render for the error message. If you don’t specify a View name, default View name is Error
  • Master: You can define a master page for the View that will be rendered. If you don’t specify a master name, that it is empty by default, which means it will use the default master page.
  • ExceptionType: The exception type that you want to handle, by default it is the very generic System.Exception which means catch all the exceptions.

Note that there is another field you can customize however it is not a direct member of this class, but it comes with inheritance. 
Going back to our example, if we want to change error page name to let’s say “UnderMaintenance” , simple change your filter decoration to:

[HandleError(View="UnderMaintenance")]
public class HomeController : Controller


Or if you want to change the master page to Maintenance simply change your filter decoration to:

[HandleError(View="UnderMaintenance", Master="Maintenance")]
public class HomeController : Controller


Now let’s assume you want to redirect the user to different pages for different types of exceptions, then you have to use the ExceptionType property.

  • If the View you are trying to render is not found, then InvalidOperationException will be thrown.
  • If you are trying to connect to SqlServer, and there is an error, then System.Data.SqlClient.SqlException will be thrown

For other types of exception you can check MSDN, but let’s now concentrate on these 2 exceptions, and create 2 different error pages for 2 different types of Exceptions. Here is the right decoration for this goal:

[HandleError(View="Error", ExceptionType=typeof(InvalidOperationException))
[HandleError(View="DatabaseError",ExceptionType=
typeof(System.Data.SqlClient.SqlException)) public class HomeController: Controller


By this declaration we are telling the system that when there is an InvalidOperationException render the Error.aspx/ascx, when there is a SqlException  error, render DatabaseError.aspx/ascx view.

What happens when we add another HandleError that handles the SystemException which is basically all the exceptions, so if our declaration is like below, and assume SqlException is thrown:

[HandleError(ExceptionType=typeof(InvalidOperationException))]
[HandleError(ExceptionType=typeof(System.Data.SqlClient.SqlException))]
[HandleError(ExceptionType = typeof(SystemException))]
 public class HomeController : Controller


The framework will call  the all filters that can catch this type of exception, in this case, framework will call handlerror twice, one for the SqlException, and one for the SystemException.

You can write your own HandleError filter, and apply it to the controller or action. Inside this filter, you have to set the ExceptionHandled flag to true, so that framework won’t throw the yellow dead screen. If there are more than 1 filter that can catch the error message, all of them have to set the ExceptionHandled flag to true, or framework will throw the yellow dead screen.
The default HandleError attribute also creates a model for your view incase you want to get more information about the error, if you change your error page’s model to HandleErrorInfo, then you can get more information from the framework about the error. A simple example for the Error.aspx could be:

<%@ Page ..  Inherits="System.Web.Mvc.ViewPage<HandleErrorInfo>" %>
Sorry for the error, We are working hard on it to fix the problem.
<ul>
    <li>Action: <%=Model.ActionName %></li>
    <li>Controller: <%=Model.ControllerName %></li>
    <li><%=Model.Exception.ToString() %></li>
</ul>

 

Of course in the real work application, you don’t want to display this information to your user, but you can use this information to write a log to your log system.
Hopefully this article help you to understand HandleError attribute.

May the force be with you.



Tags: , , ,

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses

Nov122009

Why Controllers should have a default constructor?

    I am still in the journey of exploring MVC source code.  Yesterday, I wrote about controllers and why they need “Controller” suffix. Today, I will try to find out in the code, why does a controller need a default constructor. First of all, what is default constructor?
You can check wikipedia for its complete definition; but basically a default constructor is a constructor that has no parameters. If there is no other constructors in the code, compiler puts a default constructor for you in the code. You don’t believe me? Here is a simple class:

public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }


This class does not have any type of constructors, so the compiler put a default constructor for us. compile the project, check the assembly with either reflector or ildasm tool. You will see the default constructor in your compiled code (besides some other stuff):

image 
.ctor() is the default constructor that the compiler added for us, when we did not supply any constructor. So what happens when we add a constructor that takes a parameter but no default constructor:

public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public Person(string FirstName)
        {
            this.FirstName = FirstName;
        }
    }

We now have a constructor that takes the FirstName as a parameter, and we don’t have a default constructor. This time if you check the assembly again, you will find:

image

You see that, the constructor .ctor does take 1 parameter, and there is no default constructor for us. This means when you want to create a new instance of Person, you can NOT use parameter less constructor such as: Person p = new Person();  You have to call it with a parameter.
So far, this is basic C#, where is MVC section? Here you are:

When a request comes into the MVC, we saw that the framework finds the controller first. Inside the DefaultControllerFactory (if you downloaded the source code, it is in DefaultControllerFactory.cs line # 83), an instance of the controller is being created to process the request. Here is the code from the controller factory:

 protected internal virtual IController GetControllerInstance
(Type controllerType) { // some code is here... try { return (IController)Activator.CreateInstance(controllerType); } // some other code is here...

Activator.CreateInstance is used to create an instance of the controller. Let’s see MSDN for Activator.CreateInstance:

“CreateInstance(Type)    Creates an instance of the specified type using that type's default constructor.” So Activator.CreateInstance(controllerType) will create an instance of the specified controller using the controller’s default constructor. This is the main reason controllers should have a constructor, as DefaultControllerFactory creates the controller by using its default constructor.  Luckily if we don’t have a default constructor, the framework will throw an exception at runtime when it is trying to generate a new instance (I wish we could have compile time error).  The error you will have is very self explanatory.

image 

The framework is even showing us the exact location that throws the exception. So we need to supply a default constructor if we have defined constructors with parameters.
Why would you have a constructor in your controller that takes parameter if the framework does not call it? For 2 simple reasons:

  1. Unit Testing: You want to unit test your controller, and by supplying some values in the constructor you can swap the dependencies with some other implementations that you have control of.
  2. You want to do inversion of control. Basically if you have a class, and your class depends on some other entities (such as your controller needs a class to communicate with database, or a logger class to log the errors), it shouldn’t be a task of your controller to create an instance of this classes that it depends. The classes  should be instantiated and given to your controller ready to use.

 

Let’s see an example again, assume you have a DatabaseLogger class which derives from ILogger interface and sends the logged message to the database:

public interface ILogger
{
    void SendMessage(string Message);
}

public class DatabaseLogger: ILogger
{
    public void SendMessage(string Message)
   {
      // some code to write the message to the database


Our HomeController needs the DatabaseLogger class to send some messages. One way  of doing this is to put the instantiation inside the default controller such as:

public class HomeController:Controller
{
    private ILogger logger;

    public HomeController():base(new DatabaseLogger())
    {     
    }

    public HomeController(ILogger logger)
    {
        this.logger = logger;
    }
}

There are 2 constructors in this controller. The second one that has a parameter, sets the controller’s dependency to the passed in logger interface. The default constructor is creating an instance of DatabaseLogger and passing this to the second constructor. With this technique here we can unit test our controller as the second constructor gives us the ability to swap the ILogger with an object that we can control.  However, if you look at the default constructor, the controller is creating the class that it has the dependency on. It should be passed the depedency ready to use. In this simple example maybe the benefit is not obvious however think that DatabaseLogger() needs some construction parameters that will setup the database connection string, and maybe to read the database connection string, you have some other dependencies such as a configuration file reader. Now your homecontroller has to supply all these settings to create the DatabaseLogger. This is too much now, this is where you need to use dependency injection such as Castle Windsor, StructureMap, Ninject etc…

This will be another story :)



Tags: ,

E-mail | Permalink | Trackback | Post RSSRSS comment feed 2 Responses

Nov112009

Why Controllers should have a “Controller” Suffix?

   If you are programming with ASP.NET MVC, you know that the controller’s should have a suffix of “Controller” such as “HomeController”. You may also know that this is how DefaultControllerFactory works.
Let’s look into the technical details. I will skip some unrelated facts, but we will check the MVC source code, and modify it a little. Please go to CodePlex and download the MVC source code.
When a request comes into IIS (Microsoft’s web server application), IIS first checks the request, then the MVCRouteHandler is called (assuming this is an MVC request). The MVCRouteHandler creates an instance of  MvcHandler by passing the request context. You can check out the code in the MVCRouteHandler.cs file.

protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
            return new MvcHandler(requestContext);
        }


After creating the instance, ProcessRequest (from MVCHandler) is invoked and HttpContext is passed as the parameter. The ProcessRequest function is below:

 protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
            AddVersionHeader(httpContext);

            // Get the controller type
            string controllerName = RequestContext.RouteData.
GetRequiredString("controller"); // Instantiate the controller and call Execute IControllerFactory factory = ControllerBuilder.
GetControllerFactory(); IController controller = factory.CreateController(RequestContext,
controllerName);
.... some other calls


As you can see, this function calls the GetControllerFactory() method, to get the ControllerFactory. If you haven’t registered a new ControllerFactory, this function returns the DefaultControllerFactory. The next call in ProcessRequest function is CreateController.  So let’s see what is happening in the DefaultControllerFactory’s CreateController function.

public virtual IController CreateController(RequestContext requestContext, 
string controllerName) { if (requestContext == null) { throw new ArgumentNullException("requestContext"); } if (String.IsNullOrEmpty(controllerName)) { throw new ArgumentException(
MvcResources.Common_NullOrEmpty, "controllerName"); } RequestContext = requestContext; Type controllerType = GetControllerType(controllerName); IController controller = GetControllerInstance(controllerType); return controller; }


This function after checking requestContext, and controllerName against null values, calls GetControllerType. Here is what GetControllerType does:

protected internal virtual Type GetControllerType(string controllerName) {
            if (String.IsNullOrEmpty(controllerName)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty,
"controllerName"); } // first search in the current route's namespace collection object routeNamespacesObj; Type match; match = GetControllerTypeWithinNamespaces
(controllerName, nsHash); if (match != null) { return match; } } }


This is not the whole function but a piece of it.

Again after checking some values against null, it is calling the main function which is GetControllerTypeWithinNamespaces.  I am sure you are already bored from one function call to another function call :) however, I will be writing more about the MVC infrastructure, so it is good to show them. So one more time, let’s look at the GetControllerTypeWithinNamespace function.

The first thing this function does is to call: ControllerTypeCache.EnsureInitialized(BuildManager). This will load all the controllers and cache them, so that the next time a controller is needed, the framework doesn’t have to find and load the controllers. This is a simple yet pretty important function.

 public void EnsureInitialized(IBuildManager buildManager) {
     if (_cache == null) {
          lock (_lockObj) {
            if (_cache == null) {
              List<Type> controllerTypes = GetAllControllerTypes(buildManager);
              var groupedByName = controllerTypes.GroupBy(           
      t => t.Name.Substring(0, t.Name.Length - "Controller".Length),
                            StringComparer.OrdinalIgnoreCase);
       _cache = groupedByName.ToDictionary(
                            g => g.Key,
                            g => g.ToLookup(t => t.Namespace ?? 
String.Empty, StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase); } } } }


As you can see this function caches the controllers after loading them. The _cache variable that is used in this function is a Dictionary<string,ILookup<string,type>>. So basically the framework loads the controllers into a cache. The function that loads the controllers is GetAllControllerTypes. It loads all the assemblies, iterating through them by calling a function: IsControllerType. This is why, this needs to be cached, as you don’t want to load all the assemblies and check if they are controllers. So this IsControllerType function is the reason why we have to add suffix “Controller” to our controllers:

 internal static bool IsControllerType(Type t) {
            return
                t != null &&
                t.IsPublic &&
                t.Name.EndsWith("Controller", 
                StringComparison.OrdinalIgnoreCase) &&
                !t.IsAbstract &&
                typeof(IController).IsAssignableFrom(t);
        }


This function is checking if the passed in controller, has a suffix of “Controller” or not. If it does, it returns true, and GetAllControllerTypes adds this controller to the list, and returns the list of controllers.

The call goes back to EnsureInitialized which strips out the Controller suffix, and adds it into the cache. Let’s assume we want our controllers to have suffix of “Volkan” ; what do we need to do?

First you have to change the IsControllerType so that it checks .EndsWith(“Volkan”) not “Controller”. This will let the <controllerName>Volkan controllers to be added to the list. But this is not enough, the next thing we have to do is, go back to EnsureInitialized and change the stripping part from t.Name.Length - "Controller".Length to t.Name.Length - "Volkan".Length .

Finally you have to put the “Volkan” suffix to your controllers, and now this becomes a valid controller:

      public class HomeVolkan : Controller{

 

Enjoy your time debugging the MVC code!



Tags: ,

E-mail | Permalink | Trackback | Post RSSRSS comment feed 1 Responses

Oct262008

MVC Presentation at CodeCamp

oday i was a speaker at the socalcodecamp for the first time. First let me talk about what i think about this codecamp as a listener :).

I saw that the presentation titles do not really match with presentation contents. Usually the titles are too much promising, raising the bar, and ... content is totally different. Another interesting thing is that, i was expecting lots of talks about MVC and Silverlight but didnt find much. It was usually patterns, methodoligies. So hopefully next codecamp will be full of mvc and silverlight :). 

Besides this, the campus was nice, though there was a parking problem as some of the gates were closed, and i think when you host an event that you expect a few hundred people to few thousand people, you should give a map that tells you where the restrooms and restaurants are.

As a speaker, i was very much excited i guess during the presentation, but i think i did good :). I will upload the slides and some of the photos too, this presentation motivates me to come up with a few more presentations for the next codecamp.

 Here is my presentation file in powerpoint format:

Introduction to MVC.pptx (224.09 kb)

 I find this MVC thing really fun to play with, it is simple, easy but requires sometime to learn it.  Once you get the concept, i am sure you will enjoy it.

Especially when you start writing unit tests, not only it gives you more confidence about the stability of your code, but also you start learning how to code loosely coupled  objects. I am a newbie in unit testing, but even myself, when i write the function( i apply TAD sometimes), i think, ok how am i going to do test this, when there is these dependicies, and i start refactoring the code. Anyways :) you will find tens of photos at my facebook profile :)

have fun 

 



Tags: ,

E-mail | Permalink | Trackback | Post RSSRSS comment feed 0 Responses