Magical ASP.NET MVC4 Journey – Overview: Routing and Controllers

This post was originally published on Oct-09-2013

Before we jump into the wonderful world of ASP.NET MVC 4, I wanted to do a brief introduction to some underlying table stakes that often get missed and are critical to truly understand the underpinning and behavior of the MVC framework. In this post we will discuss how incoming requests are routed to appropriate handlers (controllers, actions) and an overview of how controllers work using Actions and Routes. In future posts, we will examine other components such as models, view engines, and various techniques in cross-cutting concerns such as logging, error handling, security, deployment, and testing.

Routing Rules

Routing rules are used to deliver incoming request from the web to the controller. The routing engine is a core part of ASP.NET (not necessarily MVC). It’s goal is to examine a url and figure out where to send it for processing. Once a route is defined, it will typically describe a map which contains

  1. A friendly name (e.g. Default)
  2. A pattern (e.g.{controller}/{action}/{id})
    Other variables that one can use include {resource}, {pathInfo}, literal (e.g. .axd) and wildcards (e.g. {*pathInfo})
  3. A set of default values given for the key, defaults: …
    g. defaults: new {controller = “Home”, action = “Index”, id = urlParameter.Optional} which says, when no path is specified, the default path is http://sitename/Home/Index

This is all defined in a class called RouteConfig.cs which is located in the App_Start folder by default. This information is then provided by a standard data structure called the RouteData.

Creating a new Route
Let’s say you want your customer to come and search for an order for the hardware category or the software category. So, you’d expect them to go to something like http://site/order/category
Let us examine how we could create a route for this.

Note: Be sure that you put the route in the RouteConfig in the right order as the MVC ASP.NET engine will use the first match and the default route is very broad.
routes.MapRoute(“Order”, “order/{name}”, new { controller = “Order”; action = “Search”, name = “*” });
This will translate into: when a user navigates to http://site/order, consider the default action to be “Search” and the default name parameter to be “*”, therefore this will translate into http://site/order/Search/*

Adding a parameter to an action will cause the MVC framework to look for that parameter in the route definition and map that parameter to the value being passed in the route. So for instance, if we called the Get operation http://site/order/search/myorder and we wire our Search action method in the order controller as such,

public ActionResult Search( string name)
{
return Content(“You searched for: “ + Server.HtmlEncode(name));
}

This is exposed within the Global.asax.cs file in your project.

 

Controller Actions

Controller Actions are public method on the controllers. They have the ability to respond to an incoming HTTP request from the web.

Output of Actions

Actions will generally return an ActionResult. Here are some of the types of ActionResult.

Name What creates it? What does it do?
ContentResult Content Returns a string literal. Does not use the MVC framework to validate or parse or even generate HTML.
EmptyResult N/A No response
FileContentResult / FilePathResult / FileStreamResult File Returns the content of a file
HttpUnauthorizedResult N/A Returns an HTTP 403 StatusCode
JavaScriptResult JavaScript Returns a script to execute
JsonResult Json Returns data in JSON format
RedirectResult Redirect Redirects the client to a new Url
RedirectToRouteResult RedirectToRoute or RedirectToAction methods Redirects to another action or another Controller’s action
ViewResult / PartialViewResult View or PartialView Response is the responsibility of the View engine (e.g. Razor)

 

ActionName and AcceptVerbs

You can alias the name of your action method with another ActionName and additionally adorn it with an ActionVerb specifying the Http Verb this Action supports such as a Get or a POST Http request.

e.g. [ActionName(“MyAlias”)]
[“HttpPost”]
public ActionResult MyAction…..

ActionFilter Attributes

Action Filters apply pre and post processing logic to ActionResult(s). These are typically behavior you want to apply to actions across multiple controllers but do not want to duplicate that code within each individual controller. Here are some examples.

Name Description
OutputCache Cache the output of the controller
ValidateInput Turn off request validation and allow dangerous input
Authorize Restrict an action to authorized users or roles
ValidateAntiForgeryToken Prevent cross-site-script request forgeries
HandleError Specifies a view to render for any unhandled exceptions.

 

Note: Action Filters can also be applied at a controller level to apply to all actions within that controller. Additionally, you can also apply Global Filters that get registered at application startup (our friend Global.asax.cs is a good place to start) through,
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
which will in turn point to the implementation which should also be placed in the App_Start folder. Here you would use,
filters.Add(new SomethingAttribute());

You can also build your own custom ActionFilters to apply custom pre/post processing logic. Here is how.

Go to the Filters folders, and add a class. Let’s say we wish a tracing attribute called TraceAttribute. Ensure that this class is derived from the ActionFilterAttribute interface.

public Class TraceAttribute : ActionFilterAttribute{…}

override OnActionExecuting and/or OnActionExecuted and/or OnResultExecuting and/or OnResultExecuted methods to add your functionality!

 

 

Magical ASP.NET MVC4 Journey – Views, Partial Views and related

In this module we will discuss how to create ASP.NET MVC Views that leverages the Razor View Engine. Here, we shall discuss the Razor syntax, how to transition between .NET code and HTML markup, we’ll also discuss HTML Helpers. Security considerations will also be discussed such as how to use HTML Encoding and how to avoid cross site scripting. Finally we will also discuss the topic of Partial Views

VIEWS – The Razor View Engine

Depending on the .NET Language that you use Razor views will typically end with a .cshtml or .vbhtml file extension. In this post, we will be using the C# syntax as we work with Razor views.

In our case, a Razor View will look like a cross between HTML markup and C# code. For a view to be meaningful, you will need consumable content to be displayed (other than the content to display graphics, style and other effects). You will provide this content using a Model object or a collection of Model objects which contain that data that needs to get displayed in the user interface.

The easiest way to add a view is to right-click on a Controller’s Action property that you want to generate a view for and then click on, “Add View”. You can optionally then strongly type the model that you wish the view to consume and choose the Razor engine. In addition, you can “seed” the look of your user interface by picking from one of the scaffolding options available to present your data in the most appropriate format (e.g. List, Details, etc.). Keep in mind that this is just generating the starter code that you can get started as the scaffolding engine will examine your model and pick the most appropriate properties to scaffold. Additionally it may use markup that may not be suitable to the standards used within your organization. For instance, it may pick an HTML Table to present the List scaffolding where you may wish to instead use Cascading Style Sheets to accomplish this.

The ‘at’ (@) sign!

When you begin your view syntax with an ‘at’ sign, you indicate that what follows will be C# code. You can, of course mix this with literal text and HTML markup, for instance

Thank you for being one of our <b>top</b> customers. You have placed @Model.Count() orders with us!

This will evaluate to: Thank you for being one of our top customers. You have placed 341 orders with us!

Notice how the HTML markup to bold the word top is used and how @Model.Count() represented C# code that evaluated the Count() method of the Model object to produce the number 341.

As you can see, this is quite powerful as you can access a lot of information using C# code here and the temptation may be to do logic and calculations here, including business logic. From a design perspective you should not be writing any C# code other than to pull data out of your model for display, invoke HTML helpers which we shall see soon, input validation and display logic (e.g. make the item bold using a CSS class/style if orders are over 100).

Another thing to note is that the Razor engine is very good at implicit code expression that is, being able to tell where your C# code ends and when HTML markup or literal data start. For instance (disclaimer: you should never do business logic or calculations in your view.) let’s say you want to display the average order subtotal for customers. As you loop through your Customers Model enumerated collection, you may display something like:

Average order subtotal for @Model.Name: @Model.SubtotalSum / @Model.OrderCount

What the Razor engine will interpret here is: Average order subtotal for Joe Doe: 6000 / 100

In order for you to make the Razor engine interpret the divide operation explicitly as the continuation of the C# code, you will need to put the entire operation within parenthesis like this:

Average order subtotal for @Model.Name: @(Model.SubtotalSum / Model.OrderCount)

which will evaluate to: Average order subtotal for Joe Doe: 60

Now, brilliant as you are, you may be asking, Aref, what if I need to actually display the ‘at’ sign such as display a Twitter handle (e.g. @multistringed)? The short answer is that you will need to escape the ‘at’ sign with another ‘at’ sign like this: My Twitter handle is: @@multistringed

Code Blocks

Now, if you wanted to evaluate C# code for non-display purposes (you should really limit doing this, by the way), say for instance to change what is in the ViewBag or to manipulate objects and collections available to the view, you can do this within a code block. Note that Razor will execute the content within the code block as pure code and will not attempt to render it. To insert your C# code within a code block, simply put it with the curly braces followed by the ‘at’ sign, @{ YOUR CODE GOES HERE}. For instance, you could do this:

@{
var friendlyName = Model.WhatWasIThinkingWhenINamedThis;
}
Hello, @friendlyName !

There are some exceptions to this behavior such as the @foreach loop where Razor

@foreach (var item in Model) {
Razor will continue to render what is within this block here…
}

@: or the Literal text indicator

There may be times when you are trying to show literal text where Razor is expecting C# syntax or HTML markup, for instance, again in a @foreach loop

@foreach (var item in Model){
Here is my literal text
<tr>…</tr>
}

Razor will complain about the above as it expects, “Here is my literal text” to be C# code or HTML markup. The way to tell Razor to treat this as a literal text is to escape it with @: as such

@foreach (var item in Model){
@:Here is my literal text
<tr>…</tr>
}

Layouts! Layouts! Layouts!

Every web application has some common UI structure, such as a header containing navigation links, a footer containing some disclaimer, privacy, information and perhaps a navigation or information block on the left or right columns of every page.

Here is where the Razor layout views come to the rescue. Layout views, apart from the HTML markup such as <!DOCTYPE html… </html> section will include 2 special methods called @RenderSection() and @RenderBody()

You may have done this in the past using Master pages and similar methods.

So, for instance, let’s say you wish to include you site’s main navigation in a header and some static footer element in the bottom that you wish to display on every web page that gets rendered. You would create a layout template (one is provided in the project template under the Views\Shared folder called _Layout.cshtml). In this you can include the mail <html>….</html> tags together with the Razor syntax (html markup, C# code, literal strings, etc.) to produce the navigation header and the static footer. Additionally, you will include within the _Layout.cshtml a placeholder called @RenderBody() where individual views will place their view specific content into.

Additionally you can also put mandatory or optional placeholders for additional content using the @RenderSection() directive as such

@RenderSection(“nameOfSection”, required: false)

@RenderBody()

This will allow your individual views to place optional content into the “nameOfSection” section and place it’s main content into the body styled with the “body” CSS class. In your individual view, you will use the following syntax to use this optional section:

@section nameOfSection{
Your section specific content goes here!
}

To make all this wire up correctly, there is a special _ViewStart.cshtml file in the root of the Views folders which defines the default layout that all your views will use using a Layout property. You can override this for specific folders by putting a _ViewStart.cshtml within that child View folder such as within the Views\Order folder structure.

Also note that the @RenderBody() is a required section by default.

HTML Helpers

HTML Helpers are a nifty way to replace blocks of HTML code with an HTML Helper. HTML helpers provide support for  inputs, validation messages, labels, links and other types of HTML markup.

Helper Description
LabelFor Creates a label for a data element in a model using the label metadata described for that data element in the model. This also generates accessibility friendly HTML.
EditorFor This does the same as the LabelFor with added smarts to examine the data member’s property type and create an appropriate input type (e.g. Text input type for a property of type String). This generates an HTML <input> tag. By default, the EditorFor will use the same name attribute on the <input name=”Quantity”… that matches the model data element property name model.Quantity in this case.
ValidationMessageFor  
ValidationSummary  
ActionLink Link to an action on the current or another controller.
BeginForm Writes out an HTML <Form> tag with an action to go to the same url that the view came from and a HTTP verb of post.
HiddenFor This will generate an input type of hidden for that data element, so you are passing that data value as a post parameter in the form but not letting the user view or edit that value on the UI.

 

When you post back a form to a controller action that handles that HttpPost operation, You can examine the model being passed back to the action using the TryUpdateModel() method. The TryUpdateModel method will try to do a model binding. Which is basically MVC will try to move all HTML posted form input into appropriate model properties. If it cannot or if it fails for any reason, such as validation errors, it will return false in which case we can choose not to persist those values into the underlying data store.

if(TryUpdateModel(Order))
// save to database, etc.
else
// handle failure such as returning the model to the view to have the user fix the problem.

Custom HTML Helpers

There are also ways to build custom HTML helpers if you find yourself repeating chunks of HTML code across many views or partial views. Instead of repeating, I will link you to a good place on how to do this at the asp.net site: http://www.asp.net/mvc/tutorials/older-versions/views/creating-custom-html-helpers-cs

This also simplifies your views.

Partial Views

Partial views allow you to put HTML and C# code in files that you can re-use across other views in your project.

Let’s say, you have a shopping cart view that you have implemented within an HTML Div element to let your customers view their shopping cart from various different views (pages) in your application. You want this display to be consistent but not to duplicate this code in all your views.

To do this, cut the piece of code including the DIV from your view and create (add) a new view. A good naming convention is to start this view name with an underscore like _ShoppingCart.cshtml; make sure that you check the “Create as a partial view” check-box in the add view dialog box and save this view to the Views\Shared folder so that it is available from any content view in your application. Now add the content you had cut earlier for the shopping cart and paste that into this partial view and save it.

Now in your content view (the page where you want to show the partial view), you will use another Html Helper called Partial to show the shopping cart as such,

@html.Partial(“_ShoppingCart”, modelThePartialViewNeedsToRender)

Sometimes you want to render something that may not be part of the model available to the content view (parent). This could be a view that spans all pages in your application such as the _ShoppingCart in our example above. In that all the shopping cart specific data model information may not be available to the parent view to pass through the Partial Html Helper method. To accomplish this scenario, you will want to another Html Helper method, the Action helper method. This will set up a sub request inside the main MVC request. This way, the sub request can call a totally different controller action that builds its own model that is necessary for the partial view and pass that model to the partial view by returning a partial view!

So, in the controller, you would implement an action like this,

public class PartialViewResult ShoppingCartAction()
{
// create the model
return PartialView(“_ShoppingCart”, model);
}

Note: above that the Action returns the type PartialViewResult (which derives from an ActionResult) and the return from the action calls the PartialView.

Then, from the parent View from where you wish to display the shopping cart partial view, you would call the Action helper like this,

@html.Action(“ActionName”, “ControllerName”)

Note: If you don’t want the Action you defined earlier for the partial view to be called for anything other than a partial view (e.g. the user browsing directly to that action), you will have to adorn the action with an attribute, [ChildActionOnly] as shown below:

[ChildActionOnly]
public class PartialViewResult ShoppingCartAction()
{
// create the model
return PartialView(“_ShoppingCart”, model);
}

 

In the next phase of our journey, we will begin to examine the wonderful life of data and models. Happy coding until then.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s