Thursday, February 26, 2015

Attribute Routing in MVC 5

In the previous blog post, I talked about traditional routing. And as promised, today I am going to talk about the new feature in routing introduced in MVC 5 called Attribute Routing.

Attribute Routing

This is a way to add routes using attributes at the controller or action method level. This is quite simpler as compared to traditional routing as route URLs are kept together with the controller code. Both traditional routes and attribute routes handle complex scenarios and can go hand in hand with each other. Personally, I like it better than traditional routing because it gives me better control.

Let's take a look at an example. In order to use this feature, we will first need to add this code to our RegisterRoutes() method.

public static void RegisterRoutes(RouteCollection routes)
{
     routes.MapMvcAttributeRoutes();
}


This maps the attribute defined routes in the application.
Next, we define the route at the action method.

public class HomeController : Controller
{
        [Route("")]
        [Route("Home")]
        [Route("Home/Index")]
        public ActionResult Index()
        {
            return View();
        }
}


So, this makes the action method accessible by either of the three URLs:
i) /
ii) /Home
iii) /Home/Index

Note that we can define multiple routes simultaneously for the same action method using multiple route attributes. The string passed to the route attribute is called route template. The route template is basically a pattern matching rule that determines whether the route applies to an incoming request.

Parameter in Attribute Route

Next, let's take a look at how to pass some values in our route.

[Route("Student/{id}")]
public ActionResult Details(int id)
{
       //use the id here
}


Upon parsing the request URL, routing places the route parameter value into RouteValueDictionary which can be accessed via RequestContext. The dictionary uses route parameter names as the keys and corresponding subsections of the URL as values in the dictionary.

Controller Level Attribute Route

Similar to action method we can also put attribute route at the controller level itself. If all the action methods have similar route structure then its easier to put it at the controller level. Let's take a look at an example:

[Route("Home/{action}")]
public class HomeController : Controller
{
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About()
        {
            return View();
        }

        public ActionResult Contact()
        {
            return View();
        }

} 


This is equivalent to putting separate routes on each action. So it's lesser effort on our part :)
Similar to action methods, we can also have multiple attribute routes at the controller level too.

Conclusion

Overall, since it's new, attribute routing is a lesser known feature of MVC5. I like this feature a lot as I can look at the routes right on top of my action methods which in turn, is more clear and reduces the guess work.
This gives us control on routing at action level or controller level. Traditional routing is more at application level. Usually a mix and match approach is pretty good depending on the application needs.

For future updates to my weekly blog, please subscribe to the blog using your email id (at the right) and follow me on Twitter. Until then Happy Coding :)


Thursday, February 19, 2015

Routing in MVC5

In old web frameworks like classic ASP, there used to be a direct relationship between the URL requested and the file on disk. For example, when we requested http://www.mysite.com/index.aspx, we used to get the index.aspx file. In contrast, in ASP.NET MVC, URL is generally mapped to an action method in controller class which decides what is supposed to be the response.

Routing

Routing is the mechanism for URL pattern matching to controller action method. Simplistically, it maintains a list of patterns in a table and when a request comes in, it matches those patterns one by one and returns the first successful match. If none of the patterns match, we get 404 Not Found error.

We can add new routes by adding to the static routes property of RouteTable class. Let's take a look at
the default code we find in RouteConfig.cs file.

public static void RegisterRoutes(RouteCollection routes)

        {

            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(

                name: "Default",

                url: "{controller}/{action}/{id}",

                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

            );

        }

In the code above, routes.MapRoute is setting the name of the route to Default. The name is not going to affect the URL mapping, it's just there to uniquely identify the route. The url specifies the pattern to be matched. So, here it says that controller name, action name and id are supposed to be separated by forward slash "/". Then defaults as the names suggests assigns defaults as HomeController and Index action method. The id does not have a default value but it is specified as optional.
So when I run the application for the first time without any controller and action name in URL, I get the response provided by Home Controller's Index Action method.

routes.IgnoreRoute is basically an instruction to routing mechanism to ignore any request that matches this pattern. So the statement will ignore all the requests which have the extension .axd. On such requests normal ASP.NET handling will occur which is dependent on existing HttpHandler mappings.

Considerations for Routing

When routing handles URL requests, it tries to match the URL of the request to a route. Matching a URL request to a route depends on all the following conditions:
  • The route patterns that we have defined or the default route patterns, if any, that are included in our project type.
  • The order in which we added routes to the Routes collection.
  • Default values that we have provided for a route, if any.
  • Constraints that we have provided for a route, if any.
  • Whether we have defined routing to handle requests that match a physical file.

Route Debugger

Debugging routes can be frustrating some times. We might think that this pattern should match but somehow we don't get the expected result. For this purpose, I will highly recommend RouteDebugger. Simply add the Nuget package called RouteDebugger. Once added, we can control the visibility of the table using this entry in web.config file.

<add key="RouteDebugger:Enabled" value="true" />


RouteDebugger



Conclusion

Routing is pretty easy to start with but it takes a long time to master. Routes are also part of the application interface to the user and having proper intuitive routes improve user experience as well as search engine optimization.
I will cover Attribute Routing in my next post. For future updates to my weekly blog, please subscribe to the blog and follow me on Twitter. Until then Happy Coding :)





Thursday, February 12, 2015

Model and View model in MVC 5

Model

Model usually represent the business domain entities. These entities are used to interact with the database and in a simple system, they usually have one to one relationship with database tables.

Battle of Business Logic

This is something that I see most people get wrong in their interviews. When I ask them where to put the business logic, I usually get the answer as Controller. The best practices say that all business logic should be in Model. However, I will not lie, I do some times put business logic in controller itself if it is something small. I don't want to do it the hard way for smaller code, especially if I know that this won't be needed again or if its a test project. However, if its a substantial code I would recommend putting it in Model only.
The major advantage of keeping the business logic in Model is less duplicated code. I won't be writing the same thing again and again in Views or Controller. Secondly, it helps us in isolating the code for testing. Finally, it also helps in making the view and controller easier to read and understand.

ViewModel

ViewModels are classes that are used for interaction with Views. Views which use such viewModels are called strongly typed views. Let's take an example of Student class.

Suppose the Model looks like:
public class Student
{

      int Student Id { get; set; }
      string FirstName { get; set; }
      string LastName { get; set; }

}


In Add.cshtml we can use this
public class StudentViewModel
{

     [Required] 
     string FirstName;

     [Required] 
     string LastName; 

}


Ideally, ViewModel should only have the fields that are required by the specific View. This not only helps to keep the code clean and easy to understand but also prevents attacks like OverPosting which I will explain in a later post.

ViewModels are also useful in the scenario where a single view needs to show data from multiple models. For example, Student Details page might have Student detail as well as Department Detail.
public class StudentDetailViewModel
{
     [Required] 
     string FirstName;

     [Required] 
     string LastName;

     [Required] 
     string DepartmentName; 
}

So when we are filling the ViewModel, we can map the properties which we need to read explicitly from Student and Department model and have complete control on the system. The fields which are supposed to be hidden should be excluded (or encrypted atleast) from the viewModel so that user cannot get access to them by any chance.

Conclusion

Understanding Model and ViewModel is crucial to have a clean code base esp in an MVC application. Separating them not only helps us to make our code easy to understand but also makes it less prone to bugs.

Thursday, February 5, 2015

Why Comments Are Bad


I recently read this book on Clean Code by Robert C Martin and there he talked about comments in our code which kind of got stuck in my head. So I decided to write a blog post to highlight some of the down sides of very frequently used comments in our code.

Comment

Comments are non-executing statements that we write in our code generally in order to explain the code intent or some other information.

Why Comments are bad

Most of the time we write comments because we do not write clean code. Every time we are in the position to write a comment, we should think it through. We should ask ourselves if there is a better way that we can write the code and demonstrate our intentions in the code itself. And every time we succumb to write comments in the code, we should feel guilty and failure that we couldn't write a self-explanatory code.

Let's take a look at an example:
foreach (var student in students)
        {
         //for late enrollment charge extra fee
         if (student.EnrollmentDate>new DateTime(2015,1, 1))
             enrollmentFee = enrollmentFee + 1000;
         } 

Here, the comment is written to specify the special logic for late enrolled students. Instead, it could have been written like this:
foreach(var student in students)
        {
                if (student.IsLateEnrolled())
                    enrollmentFee = enrollmentFee + 1000;
        }

Here, we just simply created a method with a name which we were writing in comments anyways as plain text. This is much more clear and easy to maintain as compared to a comment.

I know I am being a little harsh on comments but the main reason behind that is that the comments don't get updated. The older the comment, usually farther it is from its intention. It's very difficult to maintain comments. And bad comments are usually big lies and can be frustrating and are often big time-wasters. They make our code look ugly and cluttered. We should always be ready to put some time and effort to try to avoid comments, if possible.

Let's take a look at some of the bad comments in our code.

Bad Comments

Here, the property d is used to denote Start Date.
public DateTime d { get; set; } // Start Date

Instead, the variable could have been named liked this and then the comment won't be needed
public DateTime StartDate { get; set; }

Lying Comments

Everyone must have seen code similar to this.
//always returns true
        public bool IsAdmin()
        {
            return false;
        }

The comment must have been written a long time ago and since then the code has been updated but the comment hasn't. Imagine if the method definition is complex and comment is a lie, how frustrating can it be.

Noise Comment

These are some comments which are not needed. They are possible breeding grounds of turning into bad comments in future. 
public DateTime StartDate { get; set; } // Start Date

This comment should be removed to avoid unnecessary clutter.

Commented-out Code

Having commented code for possible later use should not be needed. We have very good source control systems these days and we should use their power in case we want to see the old code and revert back. We should not clutter our code base by having commented out code.

//public DateTime StartDate { get; set; } 

Useless Comments

This comment s not really telling me anything why this code is written like this.
public bool IsAdmin()
        {
            //shhhh don't tell this to anyone
            return (LastName == "Smith" || Role == "Admin")
        }

Conclusion

In this blog post, I showed a few places where we see bad comments which we can avoid and improve our code base. Having less cluttered and clean code increases productivity.
The intent of this post is to say that comments should not make up for bad code. We should be ready to apply little time and effort if we can to avoid such comments. However, sometimes comments are necessary and are good to have but those cases are rather few as compared to how liberally we use this feature. I am not saying that we should stop writing comments, I just want to say that we should use them more cautiously. Hope this post will motivate everyone to use comments more judiciously.

For future updates to my weekly blog, please subscribe to the blog and follow me on Twitter. Until then Happy Coding :)