wondering why we are so keen on inline code – after all, the convention in Web Forms is to put as much code as possible in the code-behind files. It is easy to be confused – especially as the reason for relying on code-behind files is often to maintain separation of concerns.
The difference arises because ASP.NET MVC and ASP.NET Web Forms have different notions about which concerns should be separated and where the dividing line should be. Web Forms separate declarative markup and procedural logic – the ASPX files contain the markup and the code-behind files contain the logic. By contrast, the MVC framework separates presentation logic and application logic. Controllers and domain models are responsible for application and domain logic and view contain presentation logic. So, inline code in MVC views fits nicely within the MVC architectural framework – the Razor syntax makes it easy to creating maintainable and extensible views that transform domain model entities into user-interface components.
That said - the flexibility of the inline code feature makes it easy to blur the boundaries between the components of your application and let the separation of concerns break down. A degree of discipline is required to keep maintain effective separation of concerns in a way that is consistent with the MVC design pattern. We suggest that as you start out with MVC, you focus on
understanding the features and functions available – as you become more experienced, you’ll develop a feel for the natural division of responsibility between views and the other MVC components.
Importing Namespaces into a View
Razor views are compiled with a set of using statements for commonly-used namespaces, sparing us from having to specify the namespace when we want to use popular classes – you can see the set of namespaces that are imported in Listing 7.
Unfortunately, the list of namespaces doesn’t include those in our project that we are likely to make use of, as shown in Listing 12.
Listing 12. Referring to a class by its fully-qualified name
@{
ViewBag.Title = "Index";
}
Here is some data: @DynamicData.Infrastructure.MyUtility.GetUsefulData()
In this example, we have a class called MyUtility which has a method called
GetUsefulData that we want to invoke from our view. We have referred to the class by its fully qualified name because the namespace that contains the class, DynamicData.Infrastructure, is not one of those which are automatically added to the generated class when the view is compiled.
Typing in all of the namespace elements like this becomes laborious and it makes views harder to read. Fortunately, we are able to add using statements to the generated classes that are produced from views – there are three different techniques, which we describe in the following sections.
Adding an @using tag to a View
The easiest way to import a namespace is to use the @using tag in the Razor view – this works just like a regular C# using statement. Listing 13 provides an illustration.
Listing 13. Adding an @using tag to a view
@using DynamicData.Infrastructure
@{
ViewBag.Title = "Index";
}
Here is some data: @MyUtility.GetUsefulData()
When the view is compiled, the namespace that we have specified is importing using a C# using statement. This allows us to refer to classes, such as MyUtility in the example, without having to qualify the class name with the namespace.
Adding a Namespace to Web.config
An @using tag only affects one view – if we want to import a namespace to all of the views in a project, we can add the namespace to the Views/Web.config file, as shown in Listing 14.
Listing 14. Adding a namespace to the Web.config file
<system.web.webPages.razor>
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="DynamicData.Infrastructure"/>
</namespaces>
</pages>
</system.web.webPages.razor>
Caution This is the Web.config file which is in the Views folder and not the main Web.config file for the project.
Adding a namespace to the Views/Web.config file has the same effect as using an
@using tag, but means we don’t have to import the same namespaces into all of our views.
Understanding Razor HTML String Encoding
There is a kind of attack on web sites called cross-site scripting (XSS). Put simply, the attacker puts malicious scripts into the input elements of an application’s HTML forms in the hope that they will be displayed to another user – this can allow the attacker to take over another user’s account or take actions on their behalf. We show you an example of an XSS attack in Chapter XXX.
Razor helps protect against XSS by automatically encoding the output from any @ tag to make it safe to display – this means that characters which have special meaning in HTML are replaced by their escaped equivalent – for example, the < character is replaced with <.
As a simple example – if we imagine that the GetUsefulData method in our MyUtility class from the earlier listings returns a string which is actually a script. Listing 15 shows our problem class. Imagine that this method returns a string that a user had entered in to a form earlier.
Listing 15. A class which returns a script namespace DynamicData.Infrastructure { public class MyUtility {
public static string GetUsefulData() {
return "<form>Enter your password:<input type=text>
<input type=submit value=\"Log In\"/></form>";
} } }
This is a trivial example – real XSS attacks can be extremely subtle and tend not to change the appearance of the page – but the problem is obvious. If we were to take the output from the GetUsefulData method and inject it into our response, the browser would treat it as part of the regular HTML of the page and the user would be presented with a simple form that we didn’t want to see.
Fortunately, when we use the @ tag to call a method or read a variable, the result is encoded. The encoded HTML that the MVC framework generates for the method result is as follows:
Here is some data: <form>Enter your password:<input type=text><input type=submit value="Log In"/>/form>
You can see how this is rendered in the browser in Figure 3.
Figure 3. Safely encoded HTML
We don’t have to take any explicit steps to ensure that our data is encoded – Razor does it by default. If you want to disable automatic encoding, then there are a couple of options available. The first is to return an instance of MvcHtmlString as the result of the method or property – this type represents an HTML string which doesn’t require any further encoding.
Listing 16 shows how we can apply this to our MyUtility class.
Listing 16. Using the MvcHtmlString class to bypass content encoding using System.Web.Mvc;
namespace DynamicData.Infrastructure { public class MyUtility {
public static MvcHtmlString GetUsefulData() {
return new MvcHtmlString("<form>Enter your password:<input type=text>
<input type=submit value=\"Log In\"/></form>");
} } }
The string value is passed to the MvcHtmlString object as a constructor parameter and will be injected into the response sent to the client as is. You can see the effect of this change in Figure 4.
Figure 4. Bypassing encoding of HTML strings
You can see the problem that raw strings present – we have managed to insert a tiny HTML form into the web page.
Tip You might think that a user would spot an addition to a web page such as the one in Figure 4. If this is the basis of your security policy, then trouble is heading your way. Firstly, real XSS attacks can be very subtle and sophisticated, and typically change the behavior of the page without changing the appearance. Second, you cannot rely on the attentiveness of users to protect your application from XSS attacks – security is our job and not the responsibility of our users, however much we might like it to be otherwise.
It is not always possible to change the classes that generate our data, but we can disable encoding by using the @Html.Raw helper in a view, as shown in Listing 17.
Listing 17. Bypassing HTML encoding in a Razor view
@{
ViewBag.Title = "Index";
}
Here is some data:
@Html.Raw(Model)
Using Dynamically-Typed Views
When we create a strongly-typed view, the generated class that is produced from the view is derived from System.Web.Mvc.WebViewPage<T>, where T is the type of the view model class.
For example, this view:
@model string
@{
ViewBag.Title = "Index";
}
... rest of presentation logic and markup
results in a compiled class that is defined like this:
public class _Page_Views_Home_Index_cshtml : System.Web.Mvc.WebViewPage<string> { ... rest of class
}
The @model type of string is used as the type parameter for the generated class – as we explained earlier, this allows us to use the members of the view model class without having to cast the object, which is neat and convenient and makes unit testing simpler.
If we don’t specify the type of the model, we create a dynamically-typed view. For example, this view doesn’t specify a view model type:
@{
ViewBag.Title = "Index";
}
... rest of presentation logic and markup
The class that is generated from this view is defined like this:
public class _Page_Views_Home_InlineHelper_cshtml : System.Web.Mvc.WebViewPage<dynamic> { ... rest of class
}
Notice that the genetic type parameter for the base class is dynamic. We can still pass view model objects as we would for strongly-typed views, but they are presented to the view as dynamic objects – meaning that dealing with the view object becomes much like dealing with the ViewBag. We can call any member we like on the view model object, but it won’t be evaluated until runtime. The positive aspect of this is that we can pass different view model types from the controller to the view – the downside is that unexpected runtime errors will occur if we pass an object which doesn’t have the members that we call in the view. Listing 18 shows a view that is dynamically-typed. Programmers who use this feature tend to want to work with the flexibility of a dynamic languages such as Ruby – they know the type of the values they are passing from the controller to the to the view.
Listing 18. A dynamically typed Razor view
@{
ViewBag.Title = "Index";
}
Dynamic view model: @Model[0]
Model contents are: @Model
Caution We don’t recommend you use this feature casually – if you can exert any control over the objects that your action methods produce, then you should use a strongly-typed view instead.
Using HTML Helpers
It is frequently the case that we need to generate the same block of HTML repeatedly in a view.
Repeating Duplicating the same HTML elements and Razor tags over and over again is tedious, prone to errors and means that we have to make changes in multiple places. Fortunately, the MVC framework provides a mechanism for solving the problem – HTML helpers. In this section, we’ll show you how to create the two different kinds of HTML helper that are available and demonstrate the built-in helpers that are included with the MVC framework.
Creating an Inline HTML Helper
The most direct way to create a helper is to do so in our view, using the Razor @helper tag.
Listing 19 contains an example.
Listing 19. Creating an inline helper
@{
ViewBag.Title = "InlineHelper";
}
@helper CreateList(string[] items) {
<ul>
@foreach (string item in items) { <li>@item</li>
} </ul>
}
<h4>InlineHelper</h4>
Days of the week: <p/>
@CreateList(ViewBag.Days)
<p />
Fruit I like: <p />
@CreateList(ViewBag.Fruits)
Inline helpers have names and parameters similar to regular C# methods. In the example, we have defined a helper called CreateList, which takes a string array as a parameter.
The body of an inline helper follows the same syntax as the rest of a Razor view – literal strings are regarded as static HTML and statements that require processing by Razor are prefixed with the @ character. The helper in the example mixes static HTML and Razor tags to create an unnumbered list from a string array. The output of this view is shown in Figure 5.
Figure 5. Using an inline helper
We called the helper twice in the view to create a pair of lists – without the helper we would have had to duplicate the HTML and the foreach loop that each list required. Although an inline helper looks like a method, there is no return value – the contents of the helper body are processed and put into the response to the client.
Creating an External Helper Method
Inline helpers are convenient, but they can only be used from the view in which they are declared, and if they involve too much code, they can take over a that view and make it hard to read. The alternative is to create an external HTML helper method, which is expressed as a C#
extension method. Listing 20 provides a demonstration.
Listing 20. Creating an external HTML helper using System.Web.Mvc;
namespace DynamicData.Infrastructure.HtmlHelpers { public static class CustomHtmlHelpers {
public static MvcHtmlString List(this HtmlHelper html, string[] listItems) { TagBuilder tag = new TagBuilder("ul");
foreach (string item in listItems) {
TagBuilder itemTag = new TagBuilder("li");
itemTag.SetInnerText(item);
tag.InnerHtml += itemTag.ToString();
}
return new MvcHtmlString(tag.ToString());
} } }
The first parameter to an external HTML helper method is an HtmlHelper object, annotated with the this keyword (this is what tells the C# compiler that we are defining an extension method). Any other parameters we define will allow us to pass values from the view to the helper – in our case, we are recreating our inline helper, so we have define a string array parameter that will contain the list items to be rendered.
The easiest way to create HTML in a helper method is to use the TagBuilder class, which allows us to build up HTML strings without having to deal with all of the escaping and special characters. The TagBuilder class is part of the System.Web.WebPages assembly, but uses a feature called type forwarding to appear as though it is part of the System.Web.Mvc assembly – both assemblies are added to MVC projects by Visual Studio, so we can use the TagBuilder class easily enough, but it doesn’t appear in the MSDN API documentation.
We create a new TagBuilder instance, passing in the HTML element we want to construct as the constructor parameter. We don’t have to use the angle brackets (< and >) when using the TagBuilder class, which means we can create a UL element, like this:
TagBuilder tag = new TagBuilder("ul");
The most useful members of the TagBuilder class are described in Table 3.
Table 3. Members of the TagBuilder class
Member Description
InnerHtml This property lets you set the contents of the element as an HTML string – the value assigned to this property will not be encoded, which means that is can be used to nest HTML elements.
SetInnerText(string) This method is used to set the text contents of the HTML element – the string parameter is encoded to make it safe to display (see the section on HTML string encoding earlier in the chapter for details)
AddCssClass(string) Adds a CSS class to the HTML element MergeAttribute(string,
string, bool) Adds an attribute to the HTML element – the first parameter is the name of the attribute, the second is the value. The bool parameter specifies if an existing attribute of the same name should be replaced.
The result of an HTML helper method is an MvcHtmlString object, the contents of which are written directly into the response to the client. Remember that the contents of an MvcHtmlString will be passed directly into the response without being encoded, which means that we must take care to ensure that we encode any data that may present a XSS risk. We can do that by using the TagBuilder.SetInnerText method, which will encode a string for us, or do so explicitly by using the Encode method of the HtmlHelper object that we receive as a parameter to our helper method.
Tip In order to use a custom external HTML helper method, we have to import the namespace that contains the class – see the Importing Namespaces into a View section earlier in the chapter for details of how to do this.
Using the Built-In HTML Helpers
The MVC framework includes a selection of built-in HTML helper methods that generate often- required HTML fragments or perform common tasks. We’ve used some of these in previous chapters, but in the following sections we’ll put them in context and introduce the ones that we have yet to encounter.
Tip Using the HTML helpers to generate HTML elements like forms and inputs is not compulsory – if you prefer, you can code them using static HTML tags and populate values using view data or view model object. The HTML that the helpers generate is very clean and there are no special meanings to the attribute values – the helpers are there for convenience, rather than because they create essential or special HTML.
Creating Forms
Two of the most useful (and most commonly used) helpers are Html.BeginForm and
Html.EndForm. These helpers create HTML form tags and generate a valid action attribute for the form that is based on the routing mechanism for our application. Listing 21 shows the use of these helpers.
Listing 21. Using the BeginForm and EndForm helpers
@{Html.BeginForm("Index", "Home");}
@{ Html.EndForm();}
Neither of these helpers returns a value that can be injected into to the output directly, so we have to invoke them inside of a Razor code block, which makes for an ugly syntax. A more elegant approach is to employ a using statement, as shown in Listing 22.
Listing 22. Creating an HTML from with BeginForm and a using statement
@using (Html.BeginForm("Index", "Home")) { }
This is a neat trick that works because the BeginForm method creates an instance of the MvcForm class, which implements the IDisposable interface. When we exit the using block, the .NET framework calls the Dispose method on the MvcForm object, which causes it to emit the closing form tag and spares us from the need to use the EndForm helper.
The HTML generated by both Listing 21 and 22 is the same:
<form action="/" method="post"></form>
The BeginForm helper is overloaded and the different forms allow us to specify how the action attribute of the HTML form element is created. The version we used in both Listing 21 and Listing 22 allows us to specify an action method and a controller – these details are used in conjunction with the routing system to generate an action attribute value. In this case, the Index