6. ASP.NET MVC4 State Management

About this Tutorial

Objectives

Delegates will learn to develop web applications using C# 4.0. After completing this course, delegates will be able to:

  • Use Visual Studio 2012 effectively
  • Create commercial ASP.NET Web Applications
  • Develop user interfaces using Master Pages, Site Navigation and Themes

Audience

This course has been designed primarily for programmers new to the .Net development platform. Delegates experience solely in Windows application development or earlier versions of ASP.Net will also find the content beneficial.

Prerequisites

No previous experience in ASP.NET programming is required. But any experience you do have in programming will help. Also no experience in visual studio is required. But again any experience you do have with programming development environments will be a valuable.

Download Solutions

HTML tutorial


Overview

Estimated Time – 2 hours

Not what you are looking? Try the next tutorial – ASP.NET MVC4 Using Ajax and jQuery

In this tutorial we will enhance the film application you last worked on in the “Implementing Navigation in ASP.NET MVC4” lab.

Managing state is an important feature of any web application. It allows data to be retained both on a page and shared between pages. This means our application pages can “remember” the data it works with. We will explore:

  • Passing hidden fields between pages.
  • Managing session state.

We will also see some important MVC techniques:

  • Having multiple forms on the same page.
  • Browser redirection.

The application is based on our FilmsRUsOnline tutorial and will let us order films and check out.
The application will consist of :

  • Controller for managing order-related requests – OrderController
  • Views for displaying order-related details – Index.cshtml, Checkout.cshtml, Done.cshtml, _Summary.cshtml
  • View model for conveying order-related details – OrderIndexViewModel.cs
  • Domain model for order-processing business rules – Order.cs

FInalBuild

Lab 1: Important Structural Components

Lab 1: Important Structural Components

 

  1. We are going to have an Order entity class:

    • Keeps a list of all the items in the order.
    • Provides methods to add/remove/clear items in the order.
    • Calculates the total cost of the order.
  2. We also have an Item entity class:

    • Identify a particular film.
    • Keeps a count of the number of times the user has added the film to the order.
  3. The Order Class; in the Order class we have two important methods AddItem(Film film, int quantity) and RemoveItem(Film film). AddItem() will add the film to the order, if the object is currently not in the order. Or it will increment the quantity of that item, if it is in the order. RemoveItem() will remove the film from the current order no matter what quantity you have of the film.

    public class Order
    {
     private List items = new List();
     public IList Items { get { return items.AsReadOnly(); } }
     public void AddItem(Film film, int quantity)
     {
      var item = items.FirstOrDefault(x => x.Film.FilmID == film.FilmID);
      if (item == null)
       items.Add(new Item { Film = film, Quantity = quantity });
      else
       item.Quantity += quantity;
     }
     public void RemoveItem(Film film)
     {
      items.RemoveAll(x => x.Film.FilmID == film.FilmID);
     }
     public void Clear()
     {
      items.Clear();
     }
     public decimal TotalCost()
     {
      return items.Sum(x => x.Film.RentalPrice * x.Quantity);
     }
    }
  4. View code file.
  5.  

  6. The Item class; this contains the properties of Film and Quantity of which Film is, amazingly, of type Film. Quantity is expressed as an integer.

    public class Item
    {
     public Film Film { get; set; }
     public int Quantity { get; set; }
    }
  7. View code file.
  8.  

  9. The domain model Order performs business operation such as Add and Remove; these can be triggered from the UI and hence the _FilmSummary.cshtml can be extended with an “Add to Order” button.

    @model Domain.Entities.Film
    <div class="item">
     <h4>@Model.Title</h4>
     <p>Blurb: @Model.Blurb</p>
     @using (Html.BeginForm("AddToOrder", "Order")) {
       @Html.HiddenFor(x => x.FilmID)
       @Html.Hidden("returnUrl", Request.Url.PathAndQuery)
       <input type="submit" value="+ Add to order" />
     }
     <p>Rental price: @Model.RentalPrice.ToString("c")</p>
    </div>
  10. View code file.
  11. addtoorder

  12. It makes good sense to have separate controller that is dedicated to handling order-related requests, hence the controller OrderController. A good approach to manage per-user order details is for controllers to obtain the information they need via parameters, using external agents. In this case we use _FilmSummary.cshtml.

    public class OrderController : Controller
    {
     ...
     public RedirectToRouteResult AddToOrder(Order order, int filmID, string returnUrl)
    {
     ...
    }
     ...
    }
  13. View code file.

Lab 2: Custom Model Bindings

Lab 2: Custom Model Bindings

ASP.NET MVC has default model bindings system. This makes it easy for our views to work directly with data. This system:

The model binding mechanism is powerful and extensible:

  • We can define a custom binding, to supply action methods with additional objects.
  • Specifically, we’ll define a custom model binding for action methods of OrderController.

We’ll get an order object from our current session or create a new one and supply it to the action method.

  1. This is the Custom model binder – This has been placed in the folder Plumbing and is called OrderModelBinder.

    public class OrderModelBinder : IModelBinder
    {
     private const string orderSessionKey = "_order";
     public object BindModel(ControllerContext controllerContext,
     ModelBindingContext bindingContext)
     {
       // Return the order from Session (or create it if it doesn't exist).
       Order order = (Order) controllerContext.HttpContext.Session[orderSessionKey];
       if (order == null)
       {
        order = new Order();
        controllerContext.HttpContext.Session[orderSessionKey] = order;
       }
      return order;
     }
    }
  2. View code file.
  3.  

  4. ASP.NET MVC must know about the custom model binder, and when to use it – add the following to Global.asax.cs. This will tell MVC to use custom model binder whenever an action method needs an Order object.

    public class MvcApplication : System.Web.HttpApplication
    {
     ...
     protected void Application_Start()
     {
      ...
      // Tell ASP.NET MVC to use our controller factory.
      ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
          // Tell ASP.NET MVC to use our model binder.
          ModelBinders.Binders.Add(typeof(Order), new OrderModelBinder());
     }
    }
  5. View code file.

Lab 3: Implementing Controllers and Views

Lab 3: Implementing Controllers and Views

Checkout

  1. The OrderController class has an AddToOrder() action method
  2. The parameters used:

    • An order object supplied by our custom binder
    • Film ID supplied as HTTP input parameter
    • Return address so we know what URL to go back to
  3. The return value:

    • A RedirectToRouteResult object
    • This causes an HTTP 302 redirection, telling the browser to issue another HTTP request immediately to go to a specified URL
  4. Here is the full implementation of AddToOrder()

    public class OrderController : Controller
    {
     private IFilmsRepository filmsRepository;
     public OrderController(IFilmsRepository filmsRepository)
     {
      this.filmsRepository = filmsRepository;
     }
     public RedirectToRouteResult AddToOrder(Order order, int filmID, string returnUrl)
     {
      Film film = filmsRepository.Films.FirstOrDefault(x => x.FilmID == filmID);
      order.AddItem(film, 1);
      return RedirectToAction("Index", new { returnUrl });
     }
     ...
    }
  5. View code file.
  6.  

  7. Now to create an action method that removes a film from the order – RemoveFromOrder().

    public class OrderController : Controller
    {
     ...
     public RedirectToRouteResult RemoveFromOrder(Order order, int filmID, string returnUrl)
     {
      Film film = filmsRepository.Films
         .FirstOrDefault(x => x.FilmID == filmID);
         order.RemoveItem(film);
         return RedirectToAction("Index", new { returnUrl });
     }
     ...
    }
  8. View code file.
  9.  

  10. Both AddToOrder() and RemoveFromOrder() cause a browser-redirect to the Index() action method hence this needs to be implemented in OrderController.

    public class OrderController : Controller
    {
     ...
     public ViewResult Index(Order order, string returnUrl)
     {
      return View(new OrderIndexViewModel {
       Order = order,
       ReturnUrl = returnUrl
      });
     }
     ...
    }
  11. View code file.
  12.  

  13. The Purpose of Index() is to display the order – passes a new view-model object into the view.

    public class OrderIndexViewModel
    {
     public Order Order { get; set; }
     public string ReturnUrl { get; set; }
    }
  14. View code file.
  15.  

  16. Here is the default view for the Index() action method – displays the items in order and also displays a hyper-link to return to their previous URL.

    @foreach (var item in Model.Order.Items) {
        ...@item.Quantity
        ...@item.Film.Title
        ...@item.Film.RentalPrice.ToString("c")
        ...@((item.Quantity * item.Film.RentalPrice).ToString("c"))
        @using (Html.BeginForm("RemoveFromOrder", "Order")) {
          @Html.Hidden("FilmId", item.Film.FilmID)
          @Html.HiddenFor(x => x.ReturnUrl)
          <input type="submit" value="Remove" />
        }
    }
    ...@Model.Order.TotalCost().ToString("c")
    ...<a href="@Model.ReturnUrl">Continue browsing</a>
    ...@Html.ActionLink("Go to checkout", "Checkout")
  17. View code file.
  18. Finished

Lab 4: Accessing State Directly

Lab 4: Accessing State Directly

Each client to the website creates a separate session for their visit. Session state is server-side storage for a particular client.

  • The classic example of session state is a per-client shopping cart.
  • The shopping cart is retained in storage across multiple post-backs.
  • A controller action method can get data directly from the session state and pass it to view to be rendered.

Session state is a name-value collection.

  • Accessed via HttpContext.Session in an action method.
  • It’s an instance of HttpSessionState.

Session state remains allocated until:

  • The session time-out occurs, usually twenty minutes.
  • The code explicitly abandons the session.
  • The web application itself is restarted.
  1. You can add any kind of object to session, as follows:

    public ActionResult SomeActionMethod()
    {
     HttpContext.Session["Cart"] = new List();
     HttpContext.Session["NumVisits"] = 1;
     HttpContext.Session["LastVisit"] = DateTime.Now;
    }
  2. To access an item in session state you can use its key, as follows:

    List cart = (List) HttpContext.Session["Cart"];
    if (cart != null)
     ...
  3. You can remove an item; both key and value from session state by its key as follows:

    HttpContext.Session.Remove("Cart");
    // Or all
    HttpContext.Session.RemoveAll();
  4. It is also possible to abandon session state as follows:

    HttpContext.Session.Abandon();
  5. Session State is highly configurable, this is from web.config. For full details see https://msdn.microsoft.com/en-us/library/h6bb9cz9(v=VS.100).aspx.

    <sessionState
    mode="[Off | InProc | StateServer | SQLServer | Custom]"
    timeout="number of minutes"
    cookieName="session identifier cookie name"
    cookieless="[true | false | AutoDetect | UseCookies | UseUri | UseDeviceProfile]"
    regenerateExpiredSessionId="[True |False]"
    sessionIDManagerType="session manager type"
    sqlConnectionString="sql connection string"
    sqlCommandTimeout="number of seconds"
    allowCustomSqlDatabase="[True | False]"
    useHostingIdentity="[True | False]"
    stateConnectionString="tcpip=server:port"
    stateNetworkTimeout="number of seconds"
    customProvider="custom provider name"
    compressionEnabled="[True | False]"
    sqlConnectionRetryInterval="number of seconds">
    <providers>...</providers>
    </sessionState>

Application State

All clients to a website may want to share data with each other. Application state provides global server-side storage for all clients.

  • Accessible by all clients.
  • Accessible by all pages in the web application.

Application state is a name-value collection.

  • Accessed via HttpContext.Application in an action method.
  • It’s an instance of HttpApplicationState.

Application state remains allocated until:

  • The web application is restarted.
  1. You can add any kind of object to application state, as follows:

    HttpContext.Application.Lock();
    HttpContext.Application["copyright"] = "Acme Inc";
    HttpContext.Application["visitCount"] = 1;
    HttpContext.Application.Unlock();
  2. You can access an item in application state by its key, as follows:

    object i = HttpContext.Application["visitCount"];
    if (i == null)
     HttpContext.Application["visitCount"] = 1;
    else
     HttpContext. Application["visitCount"] = (int)i + 1;
  3. You can also remove an item from application state by its key, as follows:

    HttpContext.Application.Remove("visitCount");
    // to remove all
    HttpContext.Application.RemoveAll();

In the next tutorials we will enhance the application further by using Ajax and Jquery to allow us to update specific part of the webpage without the need to reload the whole page and much more.

 

Well done. You have completed the tutorial in the MVC4 course. The next tutorial is

7. ASP.NET MVC4 Using Ajax and jQuery


Back to beginning
Copyright © 2016 TalkIT®






If you liked this post, please comment with your suggestions to help others.
If you would like to see more content like this in the future, please fill-in our quick survey.
Scroll to Top