Export to Excel in Asp.Net MVC

We can render the data as a HTML table and then give the content type as application/excel. Excel renders HTML content in proper format. To convert the Data collection to HTML i’m making use of Asp.Net GridView here. Though this is not very Asp.Net MVC way of doing it this serves the purpose. you could write your own methods to convert the data to html format instead of the gridview here.
Code Snippet
[HttpGet]
public void GetExcel()
{
            reviewDataContext rdc = new reviewDataContext();
            //Bind the Data to Asp.Net DataGrid - you can still use this in Asp.Net MVC though it 
            //cannot be used in the .aspx View
            System.Web.UI.WebControls.GridView grd = new System.Web.UI.WebControls.GridView();
            grd.DataSource = rdc.Reviews.ToList();
            grd.DataBind();
            Response.ClearContent();
            Response.AddHeader("content-disposition", "attachment;filename=test.xls");
            Response.ContentType = "application/excel";
            StringWriter swr = new StringWriter();
            HtmlTextWriter tw = new HtmlTextWriter(swr);
            grd.RenderControl(tw);
            Response.Write(swr.ToString());
            Response.End();
}

Writing Custom HTML Helpers for ASP.NET MVC

As a web forms developer, I found the transition to MVC to be a bit of a shock at first. Without fully understanding the nature of MVC, I found the lack of a Toolbox filled with server controls to be confusing. However, once it became clear that the goal of MVC was to expose HTML markup and give developers full control over what is rendered to the browser, I quickly embraced the idea.

Transitioning from Web Forms

In MVC development, HTML helpers replace the server control, but the similarities aren’t exactly parallel. Whereas web forms and server controls were intended to bring the workflow of desktop forms to the web, MVC's HTML helpers simply provide a shortcut to writing out raw HTML elements that are frequently used.

The HTML helper, in most cases, is a method that returns a string. When we call a helper in a View using the razor syntax @Html, we are accessing the Html property of the View, which is an instance of the HtmlHelper class.

Writing extensions for the HtmlHelper class will allow us to create our own custom helpers to encapsulate complex HTML markup. Custom helpers also promote the use of reusable code and are unit testable. Custom helpers can be configured by passing values to the constructor, via fluent configuration, strongly typed parameters, or a combination of both, and ultimately return a string.

How to Begin

The first step in writing an HTML helper is finding code within our project that you intend on reusing. For the extent of this article I will be using an alert message as an example. The Alert is a UI element that displays a message which has a default, success, warning, or information style. The Alert element’s markup is simple in construction but gives us an adequate sample for the scope of this article.

1588-Alert-box

With our code targeted, we’ll examine the alert markup and see how we can break it down and construct reusable pieces of content. The alert is made up of a div container, a message, a close button and can have multiple styles applied to it. If we examine the markup, we can see that there are parts of the element that are static, and parts that can be broken down into options that can be set as parameters.

1588-markup-details

1588-parameter-breakdown

In addition to the HTML, the alert will require CSS and JavaScript in order to function. The CSS and JavaScript are beyond the scope of this article but are included in the final example at the end of this article.

Writing a Specification

Personally, once I have my HTML defined, I prefer to start writing a specification before I do anything else. Writing a specification isn’t a necessary step for creating a custom HTML helper, but it gives me a guide to how the HTML helper will function and what the desired syntax will be. A spec will also promote the use of semantic code, which improves discoverability for others that may be using the helper.

Using a text file, I spec out how the helper will function and, since I will be unit testing the code, I’ll save the spec to my test project. There are several parameters that will be required to configure the Alert element: the text to be displayed, the style of the alert, and a close button that can be toggled. I’ll also be giving the Alert a default configuration that will only require that the text parameter be set. In addition to the elements configuration, custom attributes will be configurable through the htmlAttributes parameter as an anonymous object. Each configuration of the Alert helper is written out in the spec so it can be followed during implementation.

//Given the Alert HTML Helper method

//Then Render the HTML

//Default Alert
@Html.Alert(text:"message") [.HideCloseButton()]

<div class="alert-box">
    Message
    <a href="" class="close">×</a>
</div>

//Success Alert

@Html.Alert(text:"message", style:AlertStyle.Success [,hideCloseButton:false ,htmlAttributes:object])

<div class="alert-box success">
    Message
    <a href="" class="close">×</a>
</div>

//Warning Alert

@Html.Alert(text:"message", style:AlertStyle.Warning [,hideCloseButton:false ,htmlAttributes:object])

<div class="alert-box warning">
    Message
    <a href="" class="close">×</a>
</div>

//Info Alert

@Html.Alert(text:"message", style:AlertStyle.Info [,hideCloseButton:false ,htmlAttributes:object])

<div class="alert-box info">
    Message
    <a href="" class="close">×</a>
</div>

 

Unit Testing

ASP.NET MVC is highly regarded for its ability to be unit tested, and custom HTML helpers can be thoroughly tested too. With the right setup, unit testing your custom helper isn’t difficult:

First, we need to create an instance of the HtmlHelper class so our extension method can be tested. Next, the custom method is called, and finally we can check the results against our expectations.

So, before we can write our test, we will need to create an instance of the HtmlHelper class. However, the HtmlHelper class has no default constructor, so a little work must be done up front to get an instance. To create an instance of HtmlHelper, we must specify a context and view data container - for the scope of this article, fakes will do just fine. Since each test will require an instance of HtmlHelper, I’ve created an HtmlHelperFactory class to create the instances.

//Creates an HtmlHelper for unit testing
class HtmlHelperFactory
{
    /// <summary>
    /// Create a new HtmlHelper with a fake context and container
    /// </summary>
    /// <returns>HtmlHelper</returns>
    public static HtmlHelper Create()
    {
        var vc = new ViewContext();
        vc.HttpContext = new FakeHttpContext();
        var html = new HtmlHelper(vc, new FakeViewDataContainer());
        return html;
    }

    private class FakeHttpContext : HttpContextBase
    {
        private readonly Dictionary<object, object> items = new Dictionary<object, object>();

        public override IDictionary Items
        {
        get
            {
                return items;
            }
        }
    }

    private class FakeViewDataContainer : IViewDataContainer
    {
        private ViewDataDictionary viewData = new ViewDataDictionary();
        public ViewDataDictionary ViewData
        {
            get
            {
                return viewData;
            }
            set
            {
                viewData = value;
            }
        }
    }
}

Now that the HtmlHelperFactory is available, getting an instance of HtmlHelper is as simple as calling HtmlHelperFactory.Create().

Using the first spec, I’ll create a unit test for the default alert. In this test, the Alert method will be called, and should return the HTML markup we defined, the message specified, with no additional style, and a visible close button.

First, we arrange our expected output and create an instance of HtmlHelper:

//Spec
//Should render an default alert box
//@Html.Alert(text:"message")
//arrange
string htmlAlert = @"<div class=""alert-box"">message<a class=""close"" href="""">×</a></div>";
var html = HtmlHelperFactory.Create();

At this point, the method has not been defined yet, so we’ll use what has been defined in the spec to guide us:

//act
var result = html.Alert("message").ToHtmlString();

Finally, we check our results with the expected output using Assert.AreEqual:

//assert
Assert.AreEqual(htmlAlert, result, ignoreCase: true);

So now the first unit test is written, but before it can be put to use the Alert method must be created. This test-first approach ensures that the custom Helper we write gives us the result we defined as HTML in our spec and, as each spec is fulfilled, this process will be repeated until all the specs are completed and satisfied.

Basic Implementation

Before creating our implementation, there are a few things we should know about MVC and the HtmlHelper class. The HtmlHelper class provides methods that help you create HTML controls programmatically; all HtmlHelper methods generate HTML and return the result as a string.

We’ll begin by creating a new class and implementing the IHtmlString interface - this provides the ToHtmlString method, which is used by MVC to render the control to the View. Next we override the ToString method of our class; the ToString and ToHtmlString methods will return the same result, which is a common practice for HtmlHelpers.

public class AlertBox : IHtmlString
{
    private readonly string text;

    public AlertBox(string text)
    {
        this.html = html;
        this.text = text;
    }

    //Render HTML
    public override string ToString()
    {
        return "";
    }

    //Return ToString
    public string ToHtmlString()
    {
        return ToString();
    }
}

Now that we have an HtmlHelper class, we need to be able to call it from MVC. We’ll do this by writing an extension method that returns our custom HtmlHelper class:

/// <summary>
/// Generates an Alert message
/// </summary>
public static class AlertHtmlHelper
{
    public static AlertBox Alert(this HtmlHelper html, string text)
    {
        return new AlertBox(text);
    }
}

At this point a complete scaffold of our code is complete, and our unit test should execute but fail to pass.

To finish our basic implementation and pass the unit test, we’ll need to set up our parameters and render the HTML. MVC provides the TagBuilder class for building HTML, which we’ll use to build our render method:

    private string RenderAlert()
    {

        var wrapper = new TagBuilder("div");
        wrapper.AddCssClass("alert-box");

        var closeButton = new TagBuilder("a");
        closeButton.AddCssClass("close");
        closeButton.Attributes.Add("href", "");
        closeButton.InnerHtml = "×";

        wrapper.InnerHtml = text;
        wrapper.InnerHtml += closeButton.ToString();

        return wrapper.ToString();
    }

    //Render HTML
    public override string ToString()
    {
        return RenderAlert();
    }

The HTML helper should now pass the unit test.

With the basic implementation complete, we can easily expand on the HTML helper by adding additional options. Following our spec, we’ll add the option to change the style of the alert; once again, we start with a unit test and then modify our code to complete the test:

[TestMethod]
public void ShouldCreateSuccessAlert()
{
    //Spec
    //Should render a Success alert box
    //@Html.Alert(text:"message", style:AlertStyle.Success)
    //arrange
    string htmlAlert = @"<div class=""alert-box success"">message<a class=""close"" href="""">×</a></div>";
    var html = HtmlHelperFactory.Create();

    //act
    var result = html.Alert("message", AlertStyle.Success).ToHtmlString();

    //assert
    Assert.AreEqual(htmlAlert, result, ignoreCase: true);
}



public class AlertBox : IHtmlString
{

private readonly string text;

private readonly AlertStyle alertStyle;

private readonly bool hideCloseButton;

public AlertBox(HtmlHelper html, string text, AlertStyle style, bool hideCloseButton)
    {
        this.html = html;
        this.text = text;
        this.alertStyle = style;
        this.hideCloseButton = hideCloseButton;
    }

    private string RenderAlert()
    {
        if (alertStyle != AlertStyle.Default)
            wrapper.AddCssClass(alertStyle.ToString().ToLower());
        wrapper.AddCssClass("alert-box");

        //build html
        wrapper.InnerHtml = text;

        //Add close button
        if (!hideCloseButton)
            wrapper.InnerHtml += RenderCloseButton();

        return wrapper.ToString();
    }

    private static TagBuilder RenderCloseButton()
    {
        //<a href="" class="close">x</a>
        var closeButton = new TagBuilder("a");
        closeButton.AddCssClass("close");
        closeButton.Attributes.Add("href", "");
        closeButton.InnerHtml = "×";
        return closeButton;
    }
}

Finally, we’ll make our helper more flexible by giving the end user the ability to define additional HTML attributes. The TagBuilder’s MergeAttributes method adds a specified attribute to the tag being rendered. In addition to the MergeAttributes method, the HtmlHelper AnonymousObjectToHtmlAttributes is used to allow an anonymous object to be used to define additional parameters:

public class AlertBox : IHtmlString
{...
    private object htmlAttributes;

    public AlertBox(string text, AlertStyle style, bool hideCloseButton = false, object htmlAttributes = null)

    private string RenderAlert()
    { ...
        wrapper.MergeAttributes(htmlAttributes != null ? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes) : null);
    ...}
}

The basic implementation is now complete, and the custom helper can be referernced and called in any ASP.NET MVC project. Using the synax outlined in the spec, an Alert can easily be placed anywhere in our project:

@Html.Alert("Message")

 

Fluent Configuration

Next, we'll build upon the basic HTML helper we have created thus far, with the goal of adding a Fluent API configuration to our existing Alert helper. The Fluent API won't add functionality to the helper - instead we will be simplifying the syntax used for setting options on our helper; some refer to this as adding syntactic sugar.

Taking a look at the basic implementation of the Alert helper, we can see that there are several options that can be set when calling the Alert helper:

@Html.Alert(text, alertStyle [Default | Success | Warning | Info], hideCloseButton, htmlAttributes)

Instead of using the constructor as the only manner of setting options on our helper, we will guide the user of our helper through the options. In addition to making options simpler to set, we will also be making our code easier to read. The end result should be a syntax which resembles the spoken intent of its use:

@Html.Alert(text).Success().HideCloseButton()
“Alert success, hide the close button”

Designing a Fluent API requires some planning; again, I prefer to write a specification of how I intend the code to function. Using the specification from earlier I’ll plan out the code and show the expected results.

//Success Alert
@Html.Alert(text:"message").Success() [.HideCloseButton().Attributes(object)] //Fluent

<div class="alert-box success">
    Message
                    <a href="" class="close">×</a>
</div>

For the Alert helper, we’ll be eliminating the need to specify the alert style as an enumerator and instead just call a method that defines the style by name. In this example we’ll use interfaces to chain our methods together so the user is guided through the options. In addition to guiding the user, we can control what options are available as well - for example, when the style is set, only the HideCloseButton and Attributes methods will be available.

To create the API we’ll need to define an interface for setting the style, and a second interface for setting the remaining options. Our Alert helper will implement both interfaces.

The IAlertBox interface outlines three method signatures - Success, Warning, and Info - which will all return the IAlertBoxFluentOptions interface. We will use these methods to set our alert style:

public interface IAlertBox : IAlertBoxFluentOptions
{
    IAlertBoxFluentOptions Success();
    IAlertBoxFluentOptions Warning();
    IAlertBoxFluentOptions Info();
}

The IAlertBoxFluentOptions interface outlines the rest of the options for the Alert. The method signatures HideCloseButton and Attributes also return IAlertBoxFluentOptions, which will prevent the style option from being set again.

public interface IAlertBoxFluentOptions : IHtmlString
{
    IAlertBoxFluentOptions HideCloseButton(bool hideCloseButton = true);
    IAlertBoxFluentOptions Attributes(object htmlAttributes);
}

Now that we have defined our interfaces, we will need to create a class which implements IAlertBoxFluentOptions. Because the class will be returned at the end of the method call, it will also be responsible for rendering HTML and should function as an HTML Helper which implements the IHtmlString interface.

public class AlertBoxFluentOptions : IHtmlString, IAlertBoxFluentOptions
{
    private readonly AlertBox parent;

    public AlertBoxFluentOptions(AlertBox parent)
    {
        this.parent = parent;
    }

    public IAlertBoxFluentOptions HideCloseButton(bool hideCloseButton = true)
    {
        return parent.HideCloseButton(hideCloseButton);
    }

    public IAlertBoxFluentOptions Attributes(object htmlAttributes)
    {
        return parent.Attributes(htmlAttributes);
    }

    public override string ToString()
    {
        return parent.ToString();
    }

    public string ToHtmlString()
    {
        return ToString();
    }
}

The AlertBoxFluentHelper class is essentially extending the functionality of the AlertBox class. The helper needs to be able to call back to the AlertBox we began building to set properties and call the render method, and to accomplish these task we will pass an instance of AlertBox in the constructor of the AlertFluentHelper. Using the AlertBox referenced as “parent”, we can call the parent’s ToString and ToHtmlString methods and return the results.

To complete the Fluent API we need to implement both IAlertBox and IAlertBoxFluentHelperOptions in the AlertBox class. Each method will be responsible for setting the desired value, and returns a new AlertBoxFluentOptions object passing itself to the constructor.

#region FluentAPI

    /// <summary>
    /// Sets the display style to Success
    /// </summary>
    public IAlertBoxFluentOptions Success()
    {
        alertStyle = AlertStyle.Success;
        return new AlertBoxFluentOptions(this);
    }

    /// <summary>
    /// Sets the display style to Warning
    /// </summary>
    /// <returns></returns>
    public IAlertBoxFluentOptions Warning()
    {
        alertStyle = AlertStyle.Warning;
        return new AlertBoxFluentOptions(this);
    }

    /// <summary>
    /// Sets the display style to Info
    /// </summary>
    /// <returns></returns>
    public IAlertBoxFluentOptions Info()
    {
        alertStyle = AlertStyle.Info;
        return new AlertBoxFluentOptions(this);
    }

    /// <summary>
    /// Sets the close button visibility
    /// </summary>
    /// <returns></returns>
    public IAlertBoxFluentOptions HideCloseButton(bool hideCloseButton = true)
    {
        this.hideCloseButton = hideCloseButton;
        return new AlertBoxFluentOptions(this);
    }

    /// <summary>
    /// An object that contains the HTML attributes to set for the element.
    /// </summary>
    /// <param name="htmlAttributes"></param>
    /// <returns></returns>
    public IAlertBoxFluentOptions Attributes(object htmlAttributes)
    {
        this.htmlAttributes = htmlAttributes;
        return new AlertBoxFluentOptions(this);
    }
    #endregion //FluentAPI

The Fluent API is now complete and ready to be used.

1588-fluent-api-set-style

1588-fluent-api-set-attributes

While the code required for creating a Fluent API may seem unnecessary or overly complex for this example, more complex HTML Helpers could greatly benefit from this type of API. Complexity, frequency of use, and the type of end user your HTML Helper is being designed for are all considerations when for including a Fluent API for your project.

Stronly Typed Helpers

Finally we’ll complete our overview of custom HTML Helpers by learning about strongly typed HTML Helpers. If you are already familiar with MVC, then you have probably seen or used strongly typed HTML Helpers. These helpers use the ElementFor convention, meaning the helper has a For suffix to indicate that it is strongly typed.

To create a strongly typed helper we need to understand what makes them different from regular HTML Helpers. Strongly typed helpers are used to pass data from the Model to the helper using expression syntax. The HtmlHelper class is a strongly typed subclass of the HtmlHelper class.

In addition to HtmlHelper<TModel>, we will be using Expression<Func<T,T>> to collect information about the Model. Expression<Func<T,T>>, which is part of LINQ, represents an expression tree of a delegate which accepts a parameter and returns a result. When writing HTML Helpers, the expression will allow the Helper to accept lambda expressions as parameters. All of the hard work of extracting data from the Model via lambda expression has been done for us in MVC; the ModelMetadata.FromLambdaExpression method will return the Model data based on the expression.

Since we already have the basic Alert Html Helper built, we only need to create additional extension methods and allow them to call the Alert helper:

    public static AlertBox AlertFor<TModel, TTextProperty, TStyleProperty>(this HtmlHelper<TModel> html,
        Expression<Func<TModel, TTextProperty>> textExpression,
        Expression<Func<TModel, TStyleProperty>> styleExpression,
        bool hideCloseButton = false,
        object htmlAttributes = null
        )
    {
        var text = (string)ModelMetadata.FromLambdaExpression(textExpression, html.ViewData).Model;
        var alertStyle = (AlertStyle)ModelMetadata.FromLambdaExpression(styleExpression, html.ViewData).Model;

        return new AlertBox(text, alertStyle, hideCloseButton, htmlAttributes);
    }

In usage you get this:

@Html.AlertFor(m => m.AlertBoxText, m => m.AlertBoxStyle)

The strongly typed HTML helpers provide better compile time support and benefit from intellisense. Adding this option to your HTML helper extends its usefulness, and gives the end user more flexibility.

Usage

Once the custom helper is complete simply add a refernce to your project and call your helper from the view.

@using MyHelpers;
@Html.Alert("Message")
@Html.Alert("Message").Success()
@Html.Alert("Message").Warning()
@Html.Alert("Message").Info()

1588-alert-box-usage

Considerations

HTML helpers are intended to save time by making our code more reusable. As a result, when creating HTML Helpers, you should consider how often the HTML is going to be used and how the code will be used in a project. Even though HTML helpers save time, they are also an investment. Choosing when to create one and what level of configuration is needed should be decided on a per project basis.

If your goal is to simplify a project, then a basic HTML helper will due. If you plan to use the code across multiple projects, or to create a suite of tools, then Fluent APIs and strongly typed variations of your helpers will increase the value to the end user.

The Difference Between @Helpers and @Functions

This is another post which was inspired by a recent question in the ASP.NET forums, when someone asked what the difference is between @functions and @helpers in ASP.NET Web Pages. Here, I look at both of these contructs and explain what they are, how they are different, and how each should be used appropriately.

Both @helpers and @functions do share one thing in common - they make code reuse a possibility within Web Pages. They also share another thing in common - they look the same at first glance, which is what might cause a bit of confusion about their roles. However, they are not the same. In essence, a helper is a reusable snippet of Razor sytnax exposed as a method, and is intended for rendering HTML to the browser, whereas a function is static utility method that can be called from anywhere within your Web Pages application. The return type for a helper is always HelperResult, whereas the return type for a function is whatever you want it to be.

A typical example of a helper is to display items in an ordered list. You create a folder called App_Code in the root of your site, if you don't have one already, and add a .cshtml file to it. You can name this file anything you like - but Helpers seems to be appropriate. Within your Helpers.cshtml file, you would add the following code:

@helper OrderedList(IEnumerable<string> items){
<ol>
@foreach(var item in items){
<li>@item</li>
}
</ol>
}

As you can see, this code includes HTML tags and Razor code, just like it would if you were rendering an ordered list within a Web Page. When the code is compiled, OrderedList becomes a static method of non-static class called Helpers - the name of the class is taken from the file name. A sample method call could look like this:

@Helpers.OrderedList(new[] { "Blue", "Red", "Green" })

When this is executed, unencoded HTML is output to the browser. You could implement the same functionality using @functions, and here is an example which does just that. Again, you need to add a .cshtml file to App_Code, and give it a name. In this case. Functions.cshtml is as good as any:

@using System.Web.Mvc;
@using System.Text;
@functions {

public static HtmlString OrderedList(IEnumerable<string> items)
{
var sb = new StringBuilder();
var orderedList = new TagBuilder("ol");
foreach(var item in items){
var listItem = new TagBuilder("li");
listItem.SetInnerText(item);
sb.AppendLine(listItem.ToString(TagRenderMode.Normal));
}
orderedList.InnerHtml = sb.ToString();
return new HtmlString(orderedList.ToString(TagRenderMode.Normal));
}
}

Again, OrderedList becomes a method of a non-static class named after the file (Functions), and calling it in the page is straightforward:

@Functions.OrderedList(new[] { "Blue", "Red", "Green" })

But Oh Lordy! You've had to reference System.Text to create a StringBuilder object and System.Web.Mvc to use the TagBuilder (although you could have rendered the HTML tags as strings yourself), and make sure you returned an object of type HtmlString to ensure that the whole lot doesn't get HTML encoded when it is rendered to the ouput. Functions cannot contain intermixed HTML. Now you can see the attraction of @helpers.


The appropriate use for @functions is when you want to perform an operation on a variable, rather than output some HTML. For example, you might want to validate an incoming DateTime to ensure that it is some time in the past. You wouldn't accept a form submission where someone's date of birth is some time in the future, after all? This is where @functions can be used:

@functions {    
public static bool IsBeforeToday(string value){
DateTime result;
if (DateTime.TryParse(value.ToString(), out result))
{
if (result < DateTime.Now)
{
return true;
}
}
return false;
}
}

This function takes a string as an input, and tests to see if it can be converted to a DateTime successfully. If so, it tests to see if it is before the current date and time. If it passes those tests, it returns true:

@Functions.IsBeforeToday("2010/3/22") @*returns True*@
@Functions.IsBeforeToday("2012/5/6") @*returns False at the time of writing*@

Notice that the return type for both @functions examples have differed - the first is an HtmlString, whereas the second is a bool. The return type for a method compiled from @helpers will always be HelperResult.


One other thing to note - I've emphasised that the class that is compiled as a result of the @functions syntax is non-static. This means that you cannot create extensions methods using @functions.

ASP.NET MVC Controller for Serving Images

Introduction

Working with images in a web application can turn from a simple task to a complexity in need of some serious attention as soon as traffic starts to grow or image assets become too vast to reasonably maintain multiple versions of each (large, medium, thumbnail). A general reference to an image in a HTML img tag does not provide a way to control caching or additional headers like the ETag to help site speed performance, nor does it provide a true way to handle resizing (the use of the width and height attributes on the img tag to resize an image is not viable as the full size image is still delivered to the user agent). In addition, it is tightly coupled to the physical location of the image files in the file system as it is typically referencing a directory structure type source URL.

There are several scenarios in which having more control over image file delivery can be advantageous. By writing some code to return image data from a MVC 3 controller action it is possible to inject a layer of control between the HTTP request and the resulting response for an image. From there the sky's the limit. Image content can easily be resized on the fly. Images can be combined to handle scenarios like watermarking. Physical storage locations of the images can be changed without having to update all img tags in the UI layer. It is even possible to block requests for images outside of a site's domain, thus providing a way to stop "image hijacking" by other sites.

I will walk through creating logic within an ASP.NET MVC 3 application to handle serving up images from specified URL routes. The code will support access to images in their default state, but with control over caching and ETags. From there the code will be extended to support image resizing as well as the application of a watermark prior to image data delivery.

Custom ActionResult and Extension Methods

The return of the default image data will be handled by a custom ActionResult that will inherit from the MVC FilePathResult class and override the WriteFile method to inject some additional response header logic for controlling the cache settings. This cache settings logic is going to be reused by another custom ActionResult later in the article when I cover adding support for image resizing and watermarking. As a result, I want to encapsulate that code into a single method call. I can make use of an extension method to do this. The cache policy for the HTTP response can be set via a property named Cache off of an instance of HttpResponseBase, which happens to be the method parameter of the FilePathResult.WriteFile method. My extension method will be built to work off of an instance of the HttpResponseBase class.

Listing 1: HttpResponseExtensionMethod

using System.Web;
using System.Web.Caching;
namespace ImageControllerInMvc3.Models
{
public static class HttpResponseExtensionMethods
{
public static void SetDefaultImageHeaders(this HttpResponseBase response)
{
response.Cache.SetCacheability(HttpCacheability.Public);
response.Cache.SetExpires(Cache.NoAbsoluteExpiration);
response.Cache.SetLastModifiedFromFileDependencies();
}
}
}



The SetDefaultImageHeaders extension method configures the cache headers to ensure that the response has some optimization for the user agent. This method can be enhanced or tweaked down the road to handle more functionality at the header level.


Since the constructor of the FilePathResult class (the class my custom action result will inherit from) requires the HTTP header content-type value I am going to need a way to pass in the type of image. An example of the string would be "image/png". I can do this by getting the file extension from the image file name requested. However, there is a catch. For jpeg files the string needs to be "image/jpeg" but most jpeg image files tend to have the jpg extension. I can write an extension method to extract the file extension and at the same time convert the return value to "jpeg" if the extension value is "jpg".


Listing 2: FilesystemExtensionMethods.cs

namespace ImageControllerInMvc3.Models
{
public static class FilesystemExtensionMethods
{
public static string FileExtensionForContentType(this string fileName)
{
var pieces = fileName.Split('.');
var extension = pieces.Length > 1 ? pieces[pieces.Length - 1]
: string.Empty;
return (extension.ToLower() == "jpg") ? "jpeg" : extension;
}
}
}



With these extension methods written I can move on to creating a custom class named ImageFileResult with a constructor that takes in the file name and calls the constructor for the FilePathResult class, making use of the FileExtensionForContentType method to inject the contentType value. The logic in the WriteFile method consists of a call to the new extension method and then a call to the base method.


Listing 3: ImageFileResult.cs

using System.Web;
using System.Web.Mvc;
namespace ImageControllerInMvc3.Models
{
public class ImageFileResult : FilePathResult
{
public ImageFileResult(string fileName) :
base(fileName, string.Format("image/{0}",
fileName.FileExtensionForContentType()))
{
}
protected override void WriteFile(HttpResponseBase response)
{
response.SetDefaultImageHeaders();
base.WriteFile(response);
}
}
}



 


Basic Controller Action


I will create a single controller named ImagesController that will handle all of the image functionality. The first action method that I will need to add is one to deliver a requested image file. This method will take in an image file name, validate the file exists, and return an instance of the ImageFileResult class.


Listing 4: ImagesController.cs

using System.Web.Mvc;
using ImageControllerInMvc3.Models;
namespace ImageControllerInMvc3.Controllers
{
public class ImagesController : Controller
{
public ActionResult Render(string file)
{
var fullFilePath = this.getFullFilePath(file);
if this.imageFileNotAvailable(fullFilePath))
return this.instantiate404ErrorResult(file);
return new ImageFileResult(fullFilePath);
}
private string getFullFilePath(string file)
{
return string.Format("{0}/{1}", Server.MapPath("~/Content/Images"), file);
}
private bool imageFileNotAvailable(string fullFilePath)
{
return System.IO.File.Exists(fullFilePath);
}
private HttpNotFoundResult instantiate404ErrorResult(string file)
{
return new HttpNotFoundResult(
string.Format("The file {0} does not exist.", file));
}
}
}



The private method getFullFilePath handles building the full path to the requested file in the file system by using the Server.MapPath method to resolve the location of the /Content/Images directory in the application.



The imageFileNotAvailable method handles checking that the file exists in the file system. This method can also be used to handle a request validation to ensure that only requests from the current application domain are allowed by checking the Request.ServerVariables["HTTP_REFERER"] with a regular expression to verify that it contains the domain name of the site. The instantiate404ErrorResult method creates a standard not found result message that can be reused by each action method that will handle image delivery.


To use the images controller I want the UI layer to be able to reference image files within an img tag as follows:

<img src="/Images/SomeImage.jpg" alt="The Image" />



To support this structure I need to register a new route in the Globals.asax.cs file:

routes.MapRoute(
"RenderImage", "Images/{file}",
new { controller = "Images", action = "Render", file = "" }
);



Now I can have my UI layer make calls to images and pass in the desired dimensions to get a resized image back:

<img alt="The Image" src="/Images/200/200/SomeImage.jpg">



 


Adding Watermark Functionality


To watermark logic will consist of resizing the requested image and then applying a watermark image to it before delivering the image data back to the response stream. I will use a new controller action method named RenderWithResizeAndWatermark that will take in the same parameters as the RenderWithResize method (width, height and file name).

public ActionResult RenderWithResizeAndWatermark(int width, int height, string file)
{
var fullFilePath = this.getFullFilePath(file);
if (this.imageFileNotAvailable(fullFilePath))
return this.instantiate404ErrorResult(file);
var resizeSettings = this.instantiateResizeSettings(width, height);
var resizedImage = ImageBuilder.Current.Build(fullFilePath, resizeSettings);
var watermarkFullFilePath = this.getFullFilePath("Watermark.png");
resizedImage = this.addWatermark(resizedImage,
watermarkFullFilePath, new Point(0, 0));
return new DynamicImageResult(file, resizedImage.ToByteArray());
}



The full path to the watermark file is created and the addWatermark method is used to draw the watermark image on top of the resized image. The return value is set to the resizedImage variable.

private Bitmap addWatermark(Bitmap image, string watermarkFullFilePath, 
Point watermarkLocation)
{
using (var watermark = Image.FromFile(watermarkFullFilePath))
{
var watermarkToUse = watermark;
if (watermark.Width > image.Width || watermark.Height > image.Height)
{
var resizeSettings = this.instantiateResizeSettings(image.Width,
image.Height);
watermarkToUse = ImageBuilder.Current.Build(watermarkFullFilePath,
resizeSettings);
}
using (var graphics = Graphics.FromImage(image))
{
graphics.DrawImage(watermarkToUse, watermarkLocation);
}
}
return image;
}



The watermarkLocation parameter is used to specify the x/y coordinates where the watermark image should be positioned at on the resized image. The code opens the watermark image into an Image object, does a check on the width and height to see if it is larger than the resized image, and resizes the watermark if needed. It then draws the watermark image on top of the resized image starting at the Point location and returns the finished product as a Bitmap object.


There is definitely room for improvement on the watermark positioning and resize logic to better handle cases where the location may result in the watermark being clipped or the ability to keep the watermark at a smaller ratio than the resized image. However, this bit of code illustrates how to get started dynamically combining image data.


The last thing to do is to add the route to support the watermark action method. This route needs to be added after the "RenderImage" route but before the "RenderImageWithResize" route. The final version of the RegisterRoutes method in the Global.asax.cs file:

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"RenderImage", "Images/{file}",
new { controller = "Images", action = "Render", file = "" }
);
routes.MapRoute(
"RenderImageWithResizeAndWatermark", "Images/{width}/{height}/w/{file}",
new { controller = "Images", action = "RenderWithResizeAndWatermark",
width = "", height = "", file = "" }
);
routes.MapRoute(
"RenderImageWithResize", "Images/{width}/{height}/{file}",
new { controller = "Images", action = "RenderWithResize", width = "",
height = "", file = "" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}



Now the UI can reference resized images with watermarks like so:

<img alt="The Image" src="/Images/400/300/w/SomeImage.jpg">



 


Summary


Just a little bit of heavy lifting and I now have more control over my image content within my ASP.NET MVC 3 web application. I was able to remove the file path dependency from my UI, add some caching headers to make user agents happy, do some on the fly resizing and even apply a watermark. All of this can be accomplished at the application level with no need for any special IIS modules, handlers or other server side stuff.

Close window without the prompt message

If you tried to close a window using javascript window.close() method in IE7, and as you may noticed a message will prompt "The Webpage you are viewing is trying to close the window. Do you want to close this window".

Because of the security enhancements in IE7, you can't close a window unless it is opened by a script. so the walkaround will be to let the browser thinks that this page is opened using a script then closing the window. below is the implementation.

1- Create a javascript function which will be called to close the window

<script language=javascript>
function CloseWindow()
{
window.open('','_self','');
window.close();
}
</script>



the code in bold is used to open a window in this case it's not defined into the current window. in this way, we let the browser thinks that the current window is opened using javascript, so when the window.close() is executed it will close it without the message being displayed.

Now you can try it by adding the below HTML code

<a href="" onclick="CloseWindow();">Testing Close Window</a>



Hope this post will help you.

Creating Wizard in ASP.NET MVC only

At times you want to accept user input in your web applications by presenting them with a wizard driven user interface. A wizard driven user interface allows you to logically divide and group pieces of information so that user can fill them up easily in step-by-step manner. While creating a wizard is easy in ASP.NET Web Forms applications, you need to implement it yourself in ASP.NET MVC applications. There are more than one approaches to creating a wizard in ASP.NET MVC and this article shows one of them. In Part 1 of this article you will develop a wizard that stores its data in ASP.NET Session and the wizard works on traditional form submission.

To develop a wizard in ASP.NET MVC you will use the following approach:

  • Each wizard step will have an action method in the controller and a view.
  • The data accepted in each wizard step is stored in a view model class designed for that step.
  • All the action methods for wizard steps will accept three parameters - step's view model object and two string parameters indicating the Next / Previous status.
  • The action methods mentioned above grab the data from view model object and store it in Session till the final step.
  • The action methods return a view for the next step if Next button is clicked. If Previous button is clicked they return a view for the previous step and they return the same view if there are any model validation errors.
  • Model validations are checked only when Next button is clicked.

Now that you have some idea about the approach we will be taking for developing a wizard, let's create a sample application that illustrates how this approach can be implemented. Begin by creating a new ASP.NET MVC application based on Empty template. Then right click on the Models folder and add an ADO.NET Entity Data Model for the Customers table of Northwind database. The following figure shows the Customer model class in the designer.

T_MVCWizard_01_01

As you can see the Customer class has several properties. For the sake of creating the wizard let's group them in three steps as follows:

  • Basic Details : Customer ID, CompanyName
  • Address Details : Address, City, Country, PostalCode
  • Contact Details : ContactName, Phone, Fax

Note that a few properties have been omitted from the wizard just to keep things tidy.

You need to create a view model class for each of the wizard steps outlined above. So, you need to add BasicDetails, AddressDetails and ContactDetails classes to the Models folder. These are simple POCOs as shown below:

public class BasicDetails
{
[Required]
public string CustomerID { get; set; }
[Required]
[StringLength(30)]
public string CompanyName { get; set; }
}
public class AddressDetails
{
[Required]
public string Address { get; set; }
[Required]
public string City { get; set; }
[Required]
public string Country { get; set; }
[Required]
public string PostalCode { get; set; }
}
public class ContactDetails
{
[Required]
public string ContactName { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public string Fax { get; set; }
}

As you can see the three classes namely BasicDetails, AddressDetails and ContactDetails contain only those properties that are relevant to the corresponding wizard step. Additionally, they use data annotations for basic validations. You can add more data annotations as per your requirement. For this example, the above attributes are sufficient.


Now, add HomeController to the Controllers folder. The HomeController contains five methods in all - Index(), GetCustomer(), RemoveCustomer(), BasicDetails(), AddressDetails() and ContactDetails(). The Index() action method and GetCustomers() / RemoveCustomer() helper methods are shown below:

public ActionResult Index()
{
return View("BasicDetails");
}

private Customer GetCustomer()
{
if (Session["customer"] == null)
{
Session["customer"] = new Customer();
}
return (Customer)Session["customer"];
}

private void RemoveCustomer()
{
Session.Remove("customer");
}

The Index() action method simply returns a view that represents the first step of the wizard - BasicDetails. The GetCustomer() helper method does the job of retrieving a Customer object from Session and return it to the caller. The GetCustomer() method first checks whether a Customer object is stored in the Session or not. If Customer object exists that object is returned, otherwise a new Customer object is created and stored in the Session with a key customer. The RemoveCustomer() method simply removes the customer key and associated Customer object from the Session.


Each wizard step has an action method. Since this example has three wizard steps you need to add three action methods. The BasicDetails() action method is shown below:

[HttpPost]
public ActionResult BasicDetails(BasicDetails data, string prevBtn, string nextBtn)
{
if (nextBtn != null)
{
if (ModelState.IsValid)
{
Customer obj = GetCustomer();
obj.CustomerID = data.CustomerID;
obj.CompanyName = data.CompanyName;
return View("AddressDetails");
}
}
return View();
}

The BasicDetails() action method accepts three parameters - BasicDetails object, prevBtn and nextBtn. The BasicDetails view posts the form to BasicDetails action method and hence it is marked with [HttpPost] attribute. The three parameters of BasicDetails() action method are passed in by the default model binding process of ASP.NET MVC. The BasicDetails object contains the values of CustomerID and CompanyName as entered on the BasicDetails view. Inside the BasicDetails() action method you need to know which of the two buttons (Next / Previous) was clicked by the user. That's why the two string parameters prevBtn and nextBtn are used. If prevBtn or nextBtn is not null it indicates it indicates that the button was clicked. The BasicDetails view doesn't have Previous button since it is the first step of the wizard. The BasicDetails() still accepts prevBtn parameter for the sake of consistency with other wizard step methods.


Inside, the code checks the ModelState.IsValid property to determine whether the the model contains valid data. If IsValid returns true GetCustomer() is called to retrieve the Customer object from the Session. The CustomerID and CompanyName properties of the Customer object are set with the corresponding properties of BasicDetails object and AddressDetails view is returned. If there are any model validation errors the BasicDetails view will be returned.


The AddressDetails() method works on the similar lines as that of BasicDetails() and is shown below:

[HttpPost]
public ActionResult AddressDetails(AddressDetails data, string prevBtn, string nextBtn)
{
Customer obj = GetCustomer();
if (prevBtn!=null)
{
BasicDetails bd = new BasicDetails();
bd.CustomerID = obj.CustomerID;
bd.CompanyName = obj.CompanyName;
return View("BasicDetails",bd);
}
if (nextBtn != null)
{
if (ModelState.IsValid)
{
obj.Address = data.Address;
obj.City = data.City;
obj.Country = data.Country;
obj.PostalCode = data.PostalCode;
return View("ContactDetails");
}
}
return View();
}

The AddressDetails view has Previous as well as Next button and posts to AddressDetails() action method. The AddressDetails() method accepts AddressDetails object and prevBtn and nextBtn parameters. If the Previous button was clicked, the code prepares an instance of BasicDetails object and populates its CustomerID and CompanyName properties from the Customer object from Session. The code then returns BasicDetails view with BasicDetails object as its model. This way user is taken to the previous step of the wizard.


Then the code checks whether Next button was clicked. If so, IsValid property of ModelState is checked as before. If there are no model validation errors data from AddressDetails object is stored in the Customer object from the Session. The code then return ContactDetails view.


The ContactDetails() action method does the job of saving the newly added Customer to the database and is shown below:

[HttpPost]
public ActionResult ContactDetails(ContactDetails data, string prevBtn, string nextBtn)
{
Customer obj = GetCustomer();
if (prevBtn != null)
{
AddressDetails ad = new AddressDetails();
ad.Address = obj.Address;
ad.City = obj.City;
ad.Country = obj.Country;
ad.PostalCode = obj.PostalCode;
return View("AddressDetails", ad);
}
if (nextBtn != null)
{
if (ModelState.IsValid)
{
obj.ContactName = data.ContactName;
obj.Phone = data.Phone;
obj.Fax = data.Fax;
NorthwindEntities db = new NorthwindEntities();
db.Customers.Add(obj);
db.SaveChanges();
RemoveCustomer();
return View("Success");
}
}
return View();
}

The ContactDetails view posts to the ContactDetails() action method. The ContactDetails() action method accepts ContactDetails object and prevBtn and nextBtn parameters. As before, it checks whether the Previous button was clicked. If so, a new instance of AddressDetails class is created and is filled with the data from Customer object from the Session. The code then returns AddressView by passing AddressDetails object as its model.


If user clicks on Next button, model is checked for any validation errors using IsValid property. If there are no validation errors properties of Customer object stored in the Session are assigned values of the corresponding ContactDetails object properties. Then a Entity Framework context is instantiated and the Customer object is added to the Customers DbSet. Calling SaveChanges() saves the data to the database. RemoveCustomer() is then called so as to remove the Session object. Finally, Success view is returned from the method.


Next, add four views - BasicDetails, AddressDetails, ContactDetails and Success. The markup of BasicDetails view is shown below:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MVCWizardDemo.Models.BasicDetails>" %>
...
<% using (Html.BeginForm("BasicDetails", "Home", FormMethod.Post)){ %>
<h1>Step 1 : Basic Details</h1>
<%= Html.LabelFor(m=>m.CustomerID) %><br />
<%= Html.TextBoxFor(m=>m.CustomerID) %>
<%= Html.ValidationMessageFor(m=>m.CustomerID) %><br />
<%= Html.LabelFor(m=>m.CompanyName) %><br />
<%= Html.TextBoxFor(m=>m.CompanyName) %>
<%= Html.ValidationMessageFor(m=>m.CompanyName) %>
<br />
<input type="submit" name="nextBtn" value='Next' />
<%}%>
...

As you can see BasicDetails view has its model set to BasicDetails class. The view renders a form using BeginForm() Html helper that posts to BasicDetails() action method of HomeController. Form fields for CustomerID and CompanyName are rendered using LabelFor() and TextBoxFor() helpers. The validation errors are emitted using ValidationMessageFor() helper. Note that the name of the Next button must match the corresponding parameter name of the BasicDetails() action method (nextBtn in this case). The following figure shows the BasicDetails view in action:


T_MVCWizard_01_02


The AddressDetails view is similar to BasicDetails but has Previous button also. The markup of AddressDetails view is shown below:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MVCWizardDemo.Models.AddressDetails>" %>
...
<% using (Html.BeginForm("AddressDetails", "Home", FormMethod.Post)){ %>
<h1>Step 2 : Address Details</h1>
<%= Html.LabelFor(m=>m.Address) %><br />
<%= Html.TextBoxFor(m=>m.Address) %>
<%= Html.ValidationMessageFor(m=>m.Address) %>
<br />
<%= Html.LabelFor(m=>m.City) %><br />
<%= Html.TextBoxFor(m=>m.City) %>
<%= Html.ValidationMessageFor(m=>m.City) %>
<br />
<%= Html.LabelFor(m=>m.Country) %><br />
<%= Html.TextBoxFor(m=>m.Country) %>
<%= Html.ValidationMessageFor(m=>m.Country) %>
<br />
<%= Html.LabelFor(m=>m.PostalCode) %><br />
<%= Html.TextBoxFor(m=>m.PostalCode) %>
<%= Html.ValidationMessageFor(m=>m.PostalCode) %>
<br />
<input type="submit" name="prevBtn" value='Previous' />
<input type="submit" name="nextBtn" value='Next' />
<%}%>
...

AddressDetails view renders fields for Address, City, Country and PostalCode model properties. It also has prevBtn and nextBtn buttons that represent the Previous and Next button respectively. The AddressDetails view posts the form to AddressDetails() action method of HomeController. The following figure shows how AddressDetails view looks like along with validation errors.


T_MVCWizard_01_03


The final wizard step - ContactDetails - consists of form fields for ContactName, Phone and Fax. It has two buttons Previous and Finish. The markup of ContactDetails view is shown below:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<MVCWizardDemo.Models.ContactDetails>" %>
...
<% using (Html.BeginForm("ContactDetails", "Home", FormMethod.Post)){ %>
<h1>Step 3 : Contact Details</h1>
<%= Html.LabelFor(m=>m.ContactName) %><br />
<%= Html.TextBoxFor(m=>m.ContactName) %>
<%= Html.ValidationMessageFor(m=>m.ContactName) %>
<br />
<%= Html.LabelFor(m=>m.Phone) %><br />
<%= Html.TextBoxFor(m=>m.Phone) %>
<%= Html.ValidationMessageFor(m=>m.Phone) %>
<br />
<%= Html.LabelFor(m=>m.Fax) %><br />
<%= Html.TextBoxFor(m=>m.Fax) %>
<%= Html.ValidationMessageFor(m=>m.Fax) %>
<br />
<input type="submit" name="prevBtn" value='Previous' />
<input type="submit" name="nextBtn" value='Finish' />
<%}%>
...

As you can see the ContactDetails view posts to ContactDetails() action method of HomeController. Notice that this time nextBtn has a value of Finish since it is the last step of the wizard. The following figure shows ContactDetails in action:


T_MVCWizard_01_04


Finally, you need to add the Success view that displays a success method and has a link to run the wizard again. The markup of success view is shown below:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
...
<h3>Customer Data Saved Successfully!</h3>
<%= Html.ActionLink("Add Another Customer","Index","Home") %>
...

As you can see the ActionLink() helper renders an action link that points to the Index action method of HomeController. The following figure shows how the Success view looks like:


T_MVCWizard_01_05


That's it! You can now run the wizard and test whether it works as expected. In the second part of this article you will learn to create a wizard using Ajax techniques.

Creating a simple form wizard in ASP.NET MVC

UPDATE: As of jquery.validation version 1.8+ hidden input fields are not validated by default, which means that the wizard form is submitted without client-side validation being performed. The solution is to set the default back to validating everything in the JavaScript section by including the following line; $.validator.setDefaults({ ignore: "" });
I’ve also added a sample project at the bottom of this post.
 

For small MVC sample application I’m fiddling with on my spare time, I wanted to be able to split my form up in smaller parts, much like the ASP.NET Wizard Control that is available to you when you are using Web Forms.

Now, there are quite a few jQuery plugins out there that does this for you (like the Smart Wizard by TechLaboratory), but I wanted to create my own (based on some sample code created by Nadeem Afana) just for fun (and to improve my jQuery skills).

Basically I wanted a pretty simple Wizard, where I break up the input fields in a form in two or more steps, and display a summary at the end. I wanted the users to be able to step through the wizard without filling in required fields (just so they can get a grasp of the amount of info they would need to fill in), but of course they should be stopped when trying to submit it if anything is missing. I also wanted to avoid going to the server to retrieve a partial view for the summary.

The model I will use is pretty straight forward. It contains some fields for the user to fill inn, that I will split up in “Personal Details”, “Address” and “Contact Details”:

public class SimpleWizardFormModel : IValidatableObject
{
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }

[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }

[Display(Name = "Street Address")]
public string Address { get; set; }

[Required]
[Display(Name = "Postal Code")]
public string PostalCode { get; set; }

[Required]
[Display(Name = "City")]
public string City { get; set; }

[Display(Name = "Home Phone")]
public string Phone { get; set; }

[Display(Name = "Mobile Phone")]
public string Mobile { get; set; }

[Display(Name = "I'm at least 18 years old?")]
public bool HasTurned18 { get; set; }

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!HasTurned18)
yield return new ValidationResult("You must be 18 or older.", new[] { "HasTurned18" });
}
}

The view isn’t very complicated either:

@model SimpleWizardFormModel
@section head
{
<style type="text/css">
.wizard-step { display: none; }
.wizard-confirmation { display: none; }
.wizard-nav { }
.wizard-nav input[type="button"] { width: 100px; }
</style>
}
@section script
{
<script type="text/javascript">
//*SNIP*
</script>
}
<h2>Simple Wizard Form</h2>
@using (Html.BeginForm())
{
<fieldset>
<legend></legend>
<div class="wizard-step">
<h4>Personal Details</h4>
<ol>
<li>
@Html.LabelFor(m => m.FirstName)
@Html.TextBoxFor(m => m.FirstName)
@Html.ValidationMessageFor(m => m.FirstName)
</li>
<li>
@Html.LabelFor(m => m.LastName)
@Html.TextBoxFor(m => m.LastName)
@Html.ValidationMessageFor(m => m.LastName)
</li>
<li>
@Html.LabelFor(m => m.HasTurned18)
@Html.CheckBoxFor(m => m.HasTurned18)
@Html.ValidationMessageFor(m => m.HasTurned18)
</li>
</ol>
</div>
<div class="wizard-step">
@**SNIP**@
</div>
<div class="wizard-step wizard-confirmation">
<h4>Confirm</h4>
<div id="field-summary"></div>
<div id="validation-summary">
<span class="message-error">Please correct the following errors;</span>
@Html.ValidationSummary(true)
</div>
</div>
<div class="wizard-nav">
<input type="button" id="wizard-prev" value="<< Previous" />
<input type="button" id="wizard-next" value="Next >>" />
<input type="button" id="wizard-submit" value="Submit" />
</div>
</fieldset>
}

I’ve cut out the javascript as I will get back to that later, as well as a couple of the wizard steps since they are look just like step 1 (just with other input fields). Inside my Layout.cshtml-file I’m importing jquery, jquery.validate, jquery.validate.unobtrusive, and rendering the “head”-section (in the head-tag) and “script”-section (just before body-close-tag) seen above.


The most important “feature” of the view are the divs which have been given the “wizard-step”-class. These contains the various input fields and will become the (as the class name suggests) steps in the wizard that is presented to the user. Initially all these divs are hidden from the user (note the display –> none in the css styles), and the javascript will take care of showing the div that represents the current wizard step to the user.


And now the stuff which actually performs some work, the javascript:

function DisplayStep() {
var selectedStep = null;
var firstInputError = $("input.input-validation-error:first"); // check for any invalid input fields
if (firstInputError.length) {
selectedStep = $(".wizard-confirmation");
if (selectedStep && selectedStep.length) { // the confirmation step should be initialized and selected if it exists present
UpdateConfirmation();
}
else {
selectedStep = firstInputError.closest(".wizard-step"); // the first step with invalid fields should be displayed
}
}
if (!selectedStep || !selectedStep.length) {
selectedStep = $(".wizard-step:first"); // display first step if no step has invalid fields
}

$(".wizard-step:visible").hide(); // hide the step that currently is visible
selectedStep.fadeIn(); // fade in the step that should become visible

// enable/disable the prev/next/submit buttons
if (selectedStep.prev().hasClass("wizard-step")) {
$("#wizard-prev").show();
}
else {
$("#wizard-prev").hide();
}
if (selectedStep.next().hasClass("wizard-step")) {
$("#wizard-submit").hide();
$("#wizard-next").show();
}
else {
$("#wizard-next").hide();
$("#wizard-submit").show();
}
}

The first method in my javascript, called “DisplayStep”, takes care of displaying the correct wizard step (typically this means the first step) when the view is loaded. if the view is loaded after submitting it to the server and server validation errors are found however, it will show the confirmation step if there is one, and if not it will show the first step which contains erroneous input. Once the correct step to show is found, it will decide where this step is located in relation to the other steps and show or hide the “previous”, “next” and “submit” buttons.

function PrevStep() {
var currentStep = $(".wizard-step:visible"); // get current step

if (currentStep.prev().hasClass("wizard-step")) { // is there a previous step?

currentStep.hide().prev().fadeIn(); // hide current step and display previous step

$("#wizard-submit").hide(); // disable wizard-submit button
$("#wizard-next").show(); // enable wizard-next button

if (!currentStep.prev().prev().hasClass("wizard-step")) { // disable wizard-prev button?
$("#wizard-prev").hide();
}
}
}

The “PrevStep” method is pretty straight forward. It just finds the current step, hides it, shows the previous one, and shows/hides the buttons. No validation is performed before navigation to the previous step, but if desired, this could be done just like in the “NextStep” shown below.

function NextStep() {
var currentStep = $(".wizard-step:visible"); // get current step

var validator = $("form").validate(); // get validator
var valid = true;
currentStep.find("input:not(:blank)").each(function () { // ignore empty fields, i.e. allow the user to step through without filling in required fields
if (!validator.element(this)) { // validate every input element inside this step
valid = false;
}
});
if (!valid)
return; // exit if invalid

if (currentStep.next().hasClass("wizard-step")) { // is there a next step?

if (currentStep.next().hasClass("wizard-confirmation")) { // is the next step the confirmation?
UpdateConfirmation();
}

currentStep.hide().next().fadeIn(); // hide current step and display next step

$("#wizard-prev").show(); // enable wizard-prev button

if (!currentStep.next().next().hasClass("wizard-step")) { // disable wizard-next button and enable wizard-submit?
$("#wizard-next").hide();
$("#wizard-submit").show();
}
}
}

The “NextStep” is a little more complicated. In addition to performing pretty much the same tasks as the “PrevStep” (only the opposite), it validates all input fields in the current step, and if there are any errors, you won’t be allowed to go to the next step. It only validates none empty fields however, i.e. the required rule if applicable for a given field isn’t evaluated. This is done because I wanted the user to be able to step through the entire form to see how much needs to be filled in (you can easily change this by changing the part of the script where the input fields are found). If the next step has been given the “wizard-confirmation”-class a call is also made to setup/update the confirmation (the specifics of this function will be explained further down).

function Submit() {
if ($("form").valid()) { // validate all fields, including blank required fields
$("form").submit();
}
else {
DisplayStep(); // validation failed, redisplay correct step
}
}

The last function related to navigation is “Submit”. This function validates the entire form (including required fields), and submits the form if all is good, or calls “DisplayStep” to show the confirmation step (if there is one), or the first step with errors on it (in cases where there are no confirmation step).



function UpdateConfirmation() {
UpdateValidationSummary();
var fieldList = $("<ol/>");
$(".wizard-step:not(.wizard-confirmation)").find("input").each(function () {
var input = this;
var value;
switch (input.type) {
case "hidden":
return;
case "checkbox":
value = input.checked;
break;
default:
value = input.value;
}
var name = $('label[for="' + input.name + '"]').text();
fieldList.append("<li><label>" + name + "</label><span>" + value + "&nbsp;</span></li>");
});
$("#field-summary").children().remove();
$("#field-summary").append(fieldList);
}

function UpdateValidationSummary() {
var validationSummary = $("#validation-summary");
if (!validationSummary.find(".validation-summary-errors").length) { // check if validation errors container already exists, and if not create it
$('<div class="validation-summary-errors"><ul></ul></div>').appendTo(validationSummary);
}
var errorList = $(".validation-summary-errors ul");
errorList.find("li.field-error").remove(); // remove any field errors that might have been added earlier, leaving any server errors intact
$('.field-validation-error').each(function () {
var element = this;
$('<li class="field-error">' + element.innerText + '</li>').appendTo(errorList); // add the current field errors
});
if (errorList.find("li").length) {
$("#validation-summary span").show();
}
else {
$("#validation-summary span").hide();
}
}

The “UpdateConfirmation” function (and the “UpdateValidationSummary”-function called by this function) takes care of setting up / displaying the confirmation step. The “UpdateValidationSummary” function finds all input errors (if any) and adds them to the server validation error list (creating this list if it doesn’t already exist). The “UpdateConfirmation” function, in addition to calling “UpdateValidationSummary”, finds all input fields and associated labels and created a list with them that is displayed to the user.

$(function () {
// attach click handlers to the nav buttons
$("#wizard-prev").click(function () { PrevStep(); });
$("#wizard-next").click(function () { NextStep(); });
$("#wizard-submit").click(function () { Submit(); });

// display the first step (or the confirmation if returned from server with errors)
DisplayStep();
});

Last part of the javascript is where we hook up handlers for the navigation buttons and calls the function to display the first (or correct) step when the view is first loaded.


That was all the code needed, not to bad if I say so myself.


A couple of screens to show how it looks in action (first picture shows one of the steps, while the second picture shows the confirmation step):


wizard1 wizard2


As I said in the beginning, this wizard is pretty basic, but it works pretty good. In the future I might add a navbar that lists all the wizard steps at the top, highlights any steps that contain errors, and allows the user to navigate directly to given step without needing to use the “next” and “prev” buttons.


Download file from OneDrive with name SimpleWizardForm1.zip

Implementing Role Based Menu in ASP.NET MVC

In default template of asp.net mvc 4.0, Layout.cshtml has following code for menu:

<nav>
<ul id="menu">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
</nav>



Which is hard-coded for all users. We’ll create partial view for menu to reduce complexity.


Right click on Shared folder in Views > select Add > click View
Enter Name: _Menu and set “Create as a partial view” option true > click Add
It’ll open blank cshtml page.


Define Menu Items:


In normal asp.net webforms app, Sitemap file is used to define structure. Here we’ll define menu details in partial view.

@{
var menus = new[]
{
new { LinkText="Home", ActionName="Index",ControllerName="Home",Roles="All" },
new { LinkText="About", ActionName="About",ControllerName="Home",Roles="Anonymous" },
new { LinkText="Contact", ActionName="Contact",ControllerName="Home",Roles="Anonymous" },
new { LinkText="Dashboard", ActionName="Index",ControllerName="Dealer",Roles="Dealer" },
new { LinkText="Dashboard", ActionName="Index",ControllerName="Admin",Roles="Administrator" },
new { LinkText="Administration", ActionName="GetUsers",ControllerName="Admin",Roles="Administrator" },
new { LinkText="My Profile", ActionName="GetDealerInfo",ControllerName="Dealer",Roles="Dealer,PublicUser" },
new { LinkText="Products", ActionName="GetProducts",ControllerName="Product",Roles="Dealer,Administrator" },
new { LinkText="Search", ActionName="SearchProducts",ControllerName="Product",Roles="PublicUser,Dealer,Administrator" },
new { LinkText="Purchase History", ActionName="GetHistory",ControllerName="Product",Roles="PublicUser" },
};
}



In above code, An Array of anonymous object having LinkText, ActionName, ControllerName, Roles properties is used.
I’ve given some additional roles which doesn’t belong to user roles like:


All : To display link for both authenticated or anonymous users
Anonymous: To display link for unauthenticated users


Get Role Based Links:


We’ve to get links from above menu structure with following points:
1. If user is not authenticated, Show links having All or Anonymous role.
2. If user is authenticated and has single role, Show links having All or user-role role.
3. If user is authenticated and has multiple roles, show links having All or ANY user-role role.


Note: A user may have multiple roles and in menu structure, a link may have multiple roles.

<ul id="menu">
@if (HttpContext.Current.User.Identity.IsAuthenticated)
{
String[] roles = Roles.GetRolesForUser();
var links = from item in menus
where item.Roles.Split(new String[] { "," }, StringSplitOptions.RemoveEmptyEntries)
.Any(x => roles.Contains(x) || x == "All")
select item;
foreach (var link in links)
{
@: <li> @Html.ActionLink(link.LinkText, link.ActionName,link.ControllerName)</li>
}
}
else{
var links = from item in menus
where item.Roles.Split(new String[]{","},StringSplitOptions.RemoveEmptyEntries)
.Any(x=>new String[]{"All","Anonymous"}.Contains(x))
select item;
foreach ( var link in links){
@: <li> @Html.ActionLink(link.LinkText, link.ActionName, link.ControllerName)</li>
}
}
</ul>



In above code, Linq is used to get links for both authenticated and unauthenticated user in partial view. It will get links and makes ul li structure.


Add Menu:


Now, we have to use this partial view in layout page. If we directly call this, It will be called in each request and the entire logic is executed again and again. So we’ll use session to store HTML string of menu and use session to display menu for further request.


In _Layout.cshtml page, replace nav tag with following structure:

<nav>
@if (Session["MyMenu"] == null){
Session["MyMenu"] = Html.Partial("~/Views/Shared/_Menu.cshtml");
}
@Session["MyMenu"]
</nav>



We’ve to clear session in login and logout actions.


In Login action, clear it just after setting FormsAuthentication cookies:

FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
Session["MyMenu"] = null;



and in LogOff action:

public ActionResult LogOff()
{
FormsAuthentication.SignOut();
Session["MyMenu"] = null;
return RedirectToAction("Index", "Home");
}



Hope, It helps. Share your opinion about how you are implementing role based navigation in ASP.NET MVC.

MVC Forms Authentication and Storing Data in the Cookie

Introduction

Forms authentication is a common feature in many C# MVC .NET web applications. There are a variety of methods for implementing forms authentication in MVC .NET. A key part for each, is the process of storing user specific details that are carried throughout the web application. User details such as Id, Username, Address, and Age may be obtained through various methods, such as by querying the database upon every request or as needed, loading from cache, context, or even loading from Session.

In this tutorial, we'll walk through the steps of implementing forms authentication in C# MVC .NET, specifically with MVC4. We'll use a custom MembershipProvider class, along with a custom Principal object. The Principal will hold our custom user details, encrypted within the forms authentication ticket cookie, and allow us to access this data anywhere within the web application.

Setting up the Web.Config for Forms Authentication

The first step for implementing MVC4 .NET forms authentication is to configure the web.config with the associated tags. We'll need a configuration for the authentication type and another for the membership provider, as shown below.

<authentication mode="Forms">
  <forms loginurl="~/" slidingexpiration="true" timeout="20"></forms>
</authentication>
   
<membership defaultprovider="MyMembershipProvider">
  <providers>
    <clear>
    <add name="MyMembershipProvider" type="MVC4FormsAuth.Web.Providers.MyMembershipProvider">
  </add></clear></providers>
</membership>

In the above configuration, we're setting the forms authentication tag and providing the membership provider details. We've included the name of our custom MembershipProvider, as well as the type property, which combines the assembly and class name. The membership provider class is an important part of forms authentication, as it allows us to easily authenticate a user that is logging in. It also assists us in configuring the HttpContext.User.Identity property.

Logon Types

Before beginning the code setup for C# MVC .NET forms authentication, we'll need some basic types to handle maintaining the user details after logging in.


public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public int Age { get; set; }
}

public class MyPrincipal : IPrincipal
{
public MyPrincipal(IIdentity identity)
{
Identity = identity;
}

public IIdentity Identity
{
get;
private set;
}

public User User { get; set; }

public bool IsInRole(string role)
{
return true;
}
}

The User class will hold details read from the database. We'll store a copy of the User class within the forms authentication ticket, so it's important to omit sensitive information from this class. Any sensitive or frequently-changing data should be read on-demand, when an action is initiated.


The MyPrincipal class is a custom Principal object that will be used with the HttpContext.User.Identity to allow us to load the forms authentication custom user data. We'll be serializing the User class as a JSON string and storing it in the forms authentication ticket.


Logging In


We can create our initial controller method for the Login call with a basic MVC4 .NET controller method, as shown below:


[HttpPost]
public JsonResult Login(Logon logon)
{
string status = "The username or password provided is incorrect.";

// Verify the fields.
if (ModelState.IsValid)
{
// Authenticate the user.
if (UserManager.ValidateUser(logon, Response))
{
// Redirect to the secure area.
if (string.IsNullOrWhiteSpace(logon.RedirectUrl))
{
logon.RedirectUrl = "/";
}

status = "OK";
}
}

return Json(new { RedirectUrl = logon.RedirectUrl, Status = status });
}

In the above controller method, we authenticate the user with our custom membership provider and create the forms authentication ticket. The above method is using an ajax form submission, and therefore, returns a JsonResult string, rather than an actual MVC .NET view.


Validating the User


The login controller calls our ValidateUser helper method, which in turn, calls the custom membership provider to authenticate the user. The .NET membership provider framework will call our custom MyMembershipProvider class and execute our AuthenticateUser() method.


If the membership provider call succeeds, we can create the forms authentication cookie. The membership provider will store the resulting User object within HttpContext.Current.Items. This collection is valid only for the current request, which is just enough time for us to grab it and save it in the cookie. It's important to note that Session is not yet available in this call.


We'll first serialize the returned User object as a JSON string. We'll then create the forms authentication ticket and provide the JSON string as our custom user data. The entire ticket will be encrypted and stored as the C# MVC4 .NET forms authentication cookie, which we can later retrieve and decrypt to access its contents.


public static bool ValidateUser(Logon logon, HttpResponseBase response)
{
bool result = false;

if (Membership.ValidateUser(logon.Username, logon.Password))
{
// Create the authentication ticket with custom user data.
var serializer = new JavaScriptSerializer();
string userData = serializer.Serialize(UserManager.User);

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
logon.Username,
DateTime.Now,
DateTime.Now.AddDays(30),
true,
userData,
FormsAuthentication.FormsCookiePath);

// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);

// Create the cookie.
response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));

result = true;
}

return result;
}

The Custom Membership Provider


As part of the login process, our Controller method has called ValidateUser(), which in turn, calls the custom membership provider's ValidateUser() method. We can define the custom membership provider by inheriting from the MembershipProvider base class. Since we'll only need two of the methods, defined by the base class, we can implement our custom MembershipProvider in C# MVC4 .NET as follows:


public class MyMembershipProvider : MembershipProvider
{
public override bool ValidateUser(string username, string password)
{
// Check if this is a valid user.
User user = UserManager.AuthenticateUser(username, password);
if (user != null)
{
// Store the user temporarily in the context for this request.
HttpContext.Current.Items.Add("User", user);

return true;
}
else
{
return false;
}
}

public override MembershipUser GetUser(string username, bool userIsOnline)
{
if (UserManager.User != null)
{
return new MembershipUser("MyMembershipProvider", username,
UserManager.User.Id, UserManager.User.Username, null,
null, true, false, DateTime.MinValue, DateTime.MinValue,
DateTime.MinValue, DateTime.MinValue, DateTime.MinValue);
}
else
{
return null;
}
}
}

In the above code, we've provided the methods for ValidateUser() and GetUser(). Our ValidateUser method first calls our own user authentication method to check the user's username and password. If the check succeeds, we are returned a User object. We'll need to store this User object in the forms authentication ticket. However, since Session will not be available in the Application_AuthenticateRequest() method, we'll need a way to temporarily store the User object for the current request. We can take advantage of HttpContext.Current.Items for this, as this object holds values for the duration of the request. This will give us enough time to read the User and store it in the forms authentication ticket custom data.


The helper method for actually authenticating the user (ie., calling the database or web service), is shown below:


public static User AuthenticateUser(string username, string password)
{
User user = null;

// Lookup user in database, web service, etc. We'll just generate a fake user for this demo.
if (username == "john" && password == "doe")
{
user = new User { Id = 123, Name = "John Doe", Username = "johndoe", Age = 21 };
}

return user;
}

The AuthenticateUser method would typically call the database or web server to verify the user details. In this example, we simply check against a hard-coded account and return a sample User. The series of calls is finally returned back to the ValidateUser() helper method, where we can continue by encrypting the forms authentication ticket and saving the cookie. The user is now successfully logged in.


Getting the User Data


Once the user is logged in, we'll often need to retrieve his data. For example, we'll probably need to show his name, address, and other information. Some of this data will probably be regularly used throughout the C# MVC4 web application. Since we've stored this data in the forms authentication ticket, we've greatly enhanced our web application by not having to query the database or web service to retrieve these details. Instead, we can query the HttpContext.Current.Items of the current request, which contains our decrypted User object from the forms authentication ticket.


Authenticating the Current Request


To begin, we need to implement the Application_AuthenticateRequest() in the Global.asax.cs file. This method is called on each request in the web application, so you'll want to keep it lightweight, in nature. While this example includes the below code for every request, you could also create a custom MVC4 filter to obtain the data only on specific web application actions. Our AuthenticateRequest call appears as follows:


protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
// Get the forms authentication ticket.
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
var identity = new GenericIdentity(authTicket.Name, "Forms");
var principal = new MyPrincipal(identity);

// Get the custom user data encrypted in the ticket.
string userData = ((FormsIdentity)(Context.User.Identity)).Ticket.UserData;

// Deserialize the json data and set it on the custom principal.
var serializer = new JavaScriptSerializer();
principal.User = (User)serializer.Deserialize(userData, typeof(User));

// Set the context user.
Context.User = principal;
}
}

In the above code, we first check if a forms authentication ticket cookie exists for the currently connected user. If the cookie exists, we read it and attempt to decrypt it. With the decrypted cookie, we create the custom Principal object and provide it with the decrypted user details from the cookie. This will allow us to access the user details from the standard HttpContext.Current.User property in the .NET MVC web application.


Accessing the User Data in the Ticket


Since our AuthenticateRequest method has created the User.Identity and included our custom User data within it, we simply need to cast the Context.User object to our custom User type. We'll then be able to easily access the user details from anywhere within our MVC .NET web application. We can create a helper method for making this more convenient, as shown below:


public static User User
{
get
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// The user is authenticated. Return the user from the forms auth ticket.
return ((MyPrincipal)(HttpContext.Current.User)).User;
}
else if (HttpContext.Current.Items.Contains("User"))
{
// The user is not authenticated, but has successfully logged in.
return (User)HttpContext.Current.Items["User"];
}
else
{
return null;
}
}
}

We'll use the above helper method for logging the user in (as shown above in the ValidateUser helper method), as well as accessing the user's details after he's already logged in.


The above User helper method first checks if the user is already authenticated. If he is, we simply cast the HttpContext.Current.User object to our custom principal object, MyPrincipal, and then return the User property. Remember, this object was created in the AuthenticateRequest() method, as part of the MVC ASP .NET framework.


If the user is not yet logged in, we'll check the HttpContext.Current.Items for the User object. This is stored as part of the custom membership provider (since we don't have access to Session at the time of logging in, we use the HttpContext to store the data temporarily for the current request).


Displaying the User Data


Finally, our framework is complete. The user has been authenticated, logged in, and is now available in our application by accessing the HttpContext.Current.User or our helper User class. We can access the user in the MVC Razor view, as shown below:


@if (User.Identity.IsAuthenticated)
{
You're logged in as @UserManager.User.Username (@UserManager.User.Age)
}
else
{
@Html.Partial("Controls/Login", new Logon());
}

The above MVC Razor view checks if the user is authenticated. If he is, we access the User helper object (obtained via the forms authentication cookie and associated encrypted data). If the user is not yet logged in, we show the login form.


Logging Out


When the user is ready to log out, we'll simply need to abandon the session, sign out of the forms authentication, and clear any remaining forms authentication cookie by allowing it to expire. We can do this with a helper method, as shown below:


public static void Logoff(HttpSessionStateBase session, HttpResponseBase response)
{
// Delete the user details from cache.
session.Abandon();

// Delete the authentication ticket and sign out.
FormsAuthentication.SignOut();

// Clear authentication cookie.
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, "");
cookie.Expires = DateTime.Now.AddYears(-1);
response.Cookies.Add(cookie);
}

The above method may be called from your Logoff controller method.

Difference Between ViewBag and ViewData in MVC

If you’re new to ASP.NET MVC, you might be wondering what these two things are and when to use each one. If you’ve been using MVC and are just new to version 3 of MVC, you are probably wondering what this new ViewBag is for and if it’s different from the ViewData you’ve been using. In the beginning of the Summer, I had the opportunity to explain this difference to the two NimblePros interns when they started working on ASP.NET MVC 3 for the first time. This post should serve as a reference for them, me, and anyone else who is interested in knowing more about these two objects.

ViewBag and ViewData serve the same purpose in allowing developers to pass data from controllers to views. When you put objects in either one, those objects become accessible in the view. This is one way we interact between the view and the controller in ASP.NET MVC. We pass data from the view to the controller by placing it in these objects.

How ViewData Works

ViewData is a dictionary of objects that are accessible using strings as keys. This means that we will write code like this:

In the Controller

public ActionResult Index()
{
var softwareDevelopers = new List<string>
{
"Brendan Enrick",
"Kevin Kuebler",
"Todd Ropog"
};

ViewData["softwareDevelopers"] = softwareDevelopers;

return View();
}


In the View


<ul>
@foreach (var developer in (List<string>)ViewData["softwareDevelopers"])
{
<li>
@developer
</li>
}
</ul>


Notice that when we go to use out object on the view that we have to cast it since the ViewData is storing everything as object. Also, we need to be careful since we’re using magic strings to access these values.


How ViewBag Works


ViewBag uses the dynamic feature that was added in to C# 4. It allows an object to dynamically have properties added to it. The code we write using ViewBag will look like this:


In the Controller


public ActionResult Index()
{
var softwareDevelopers = new List<string>
{
"Brendan Enrick",
"Kevin Kuebler",
"Todd Ropog"
};

ViewBag.softwareDevelopers = softwareDevelopers;

return View();
}


In the View


<ul>
@foreach (var developer in ViewBag.softwareDevelopers)
{
<li>
@developer
</li>
}
</ul>


Notice here that we did not have to cast our object when using the ViewBag. This is because the dynamic we used lets us know the type. Keep in mind that these dynamics are as the name suggest, dynamic, which means that you need to be careful as these are basically magic properties instead of magic strings.


ViewBag and ViewData Under the Hood


So these two things seem to work almost exactly the same. What’s the difference? The difference is only in how you access the data. ViewBag is actually just a wrapper around the ViewData object, and its whole purpose is to let you use dynamics to access the data instead of using magic strings. Some people prefer one style over the other. You can pick whichever you like. In fact, because they’re the same data just with two different ways of accessing it, you can use them interchangeably. (I don’t recommend this, but you can do it.) If you want you are able to put data into the ViewBag and access it from the ViewData or put stuff in the ViewData and access it in the ViewBag.


This is all that the ViewBag property is. It’s just a DynamicViewDataDictionary with the ViewData as its data.



public dynamic ViewBag 
{
get
{
if (_dynamicViewData == null)
{
_dynamicViewData =
new DynamicViewDataDictionary(() => ViewData);
}
return _dynamicViewData;
}
}

Then when we access the dynamic members of the DynamicViewDataDictionary, we are actually just getting this override of the DynamicObject’s TryGetMember. In this method, it’s just using the name of the member we tried to access as the string key for the ViewData dictionary.

 


public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
result = ViewData[binder.Name];
return true;
}

Advertsing

125X125_06

Planet Xamarin

Planet Xamarin

Calendar

<<  September 2017  >>
MonTueWedThuFriSatSun
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

View posts in large calendar

Month List