Skipping ActionFilters in ASP.NET MVC

In the previous post I showed how you can use an action filter to execute code both before and after an action method and how to apply the filter globally.

I found myself in a scenario where I wanted to run the action filter almost globally. I needed to exclude all actions methods in one controller and one action method in another controller.

This is easily done with the use of an Attribute, see here for more.

Create a SkipImportantTaskAttribute like so –

  public class SkipImportantTaskAttribute : Attribute {}

I then decorate the relevant action methods or controllers with this attribute.
To skip an entire controller do this –

    [SkipImportantTask]
    public class CustomersController : Controller

To skip just a single action method do this –

	[SkipImportantTask]
	public ActionResult Index()

Change the OnActionExecuted (or OnActionExecuting) method of the action filter to the following

 
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
	bool skipImportantTaskFilter = filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(SkipImportantTaskAttribute), true) ||
		filterContext.ActionDescriptor.IsDefined(typeof(SkipImportantTaskAttribute), true);

	if (!skipImportantTaskFilter)
	{
		PerformModelAlteration(filterContext);
	}

	base.OnActionExecuted(filterContext);
}

Now if SkipImportantTaskAttribute is present on the controller or action method the action filter code will not be executed.

Full source code here.

Altering the ASP.NET MVC model with an ActionFilter

Action filters are executed before and/or after the execution of an action method, they can be used to modify how an action executes or to perform a separate task, such as authorization or logging.

Action filters can be applied globally, at the controller level, or on an action method.

See here for more details.

In this post I’ll deal with how action filters allow you intercept an outgoing response to change a value in the returned model.

Action filter

Create a filter that inherits from ActionFilterAttribute and override the OnActionExecuted method.

public override void OnActionExecuted(ActionExecutedContext filterContext)

From the filterContext we can get model.

var model = filterContext.Controller.ViewData.Model as BaseModel;

Any value in the BaseModel can now be changed, in the example provided I change the MeetingDate property.

This action filter to needs to be applied to the appropriate action methods.
I’m going to register the filter globally, in this way it will run on all executed action methods.

Go to the FilterConfig class to register the filter.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
	filters.Add(new HandleErrorAttribute());
	filters.Add(new ModelAlterFilterAttribute());
}

That is all you need to do to create an action filter, register it and to alter the returned model.

As an aside, if you want to alter the value of an incoming parameter you override the OnActionExecuting method of the action filter.
In this example customerID is just an int but this approach will work for complex models too.

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
	var actionParams = filterContext.ActionParameters;

	object customerID;
	actionParams.TryGetValue("customerid", out customerID);
	if (customerID != null)
	{
		customerID = 222;
	}

	base.OnActionExecuting(filterContext);
}

In the next post I show how you to selectively disable a global action filter on specific action methods or controllers.

Full source code here.

Arguments model and action methods in ASP.NET MVC Part 2 – using Glimpse

In my previous post I discussed how values sent from the browser are bound to objects in the action methods of a controller.

If binding is not working as expected you need to examine the html element names and the types you are binding to, I showed how the FormCollection can be of help in this regard.

In this post I will show how to use Glimpse to examine how binding is occurring.

I should at this point say that I am one of the contributors to the Glimpse project.

Add the Glimpse Mvc 4 package to your project.

nuget

Start your application; in the browser open glimpse.axd from the root and turn glimpse on by clicking the Turn Glimpse On button.

request

Browse to the page where you want to see how binding is working.

In the example, edit employee 1, John Jones. Make some changes to the employee and add a comment to the reason for edit and save.

You’ll be brought back to the index page listing all employees.

At the bottom of the browser you should have a Glimpse bar showing some statistics about the page.

Open Glimpse fully by clicking the ‘g’ in the right corner and click History on the far right.

Here you will see all the recent requests, we are interested in the most recent POST.

requests

Click inspect on that request, the POST request http://localhost:55809/Employee/Edit?EmployeeID=1. The tabs along the top of Glimpse have been refreshed with data from that request.

Open the Model Binding tab to see how the values from your request have been bound to your types in the action method.

model_binding

Here you can see parameters to the action method, their type and and what they were bound to.

If you see a parameter that has “–” (two dashes) in the Value column, nothing was sent to the action method that could be bound to a parameter on the action method.

Now take a look at the Request tab and the form variables. Note how the keys of the form variables match the parameters in the model binding tab.

request

This is the easiest way I have found to understand how model binding works in MVC and fix problems.

Arguments model and action methods in ASP.NET MVC Part 1

Sending values from an MVC view to a controller works very well when you are binding back to the same model/viewmodel you populated the view with. But when you start trying to do something a little different, it’s not so obvious or straightforward.

The quick answer

The name attribute of the html element must match the argument sent to the action method.

Here are a few examples.

If the type sent to the action method is an Employee (which has strings for Fristname and Lastname) the html input elements should look like

	<input type="text" name="Firstname" value="" />
	<input type="text" name="Lastname" value="" />

If the type sent to the action method is an EmployeeViewModel (this has an Employee type inside, which has strings for Fristname and Lastname) the html input elements should look like

	<input type="text" name="Employee.Firstname" value="" />
	<input type="text" name="Employee.Lastname" value="" />

Note the name attributes are different from the previous example, but that they match the EmployeeViewModel.

That might be enough to solve your problem, if so you can get back to work, if not, read on.

The long answer

The following example is a bit contrived, and don’t use it as an example of how to code MVC models, or viewmodels, but it allows me to show a few ways of achieving some unusual model binding. Full source code is attached.
I’ve followed the standard MVC Index, Create, Edit and Delete approach that comes out of the box with Visual Studio 2012.

I have an Employee –

    public class Employee
    {
        public int EmployeeID { get; set; }
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public int RoleID { get; set; }
    }

and a Role –

    public class Role
    {
        public int RoleID { get; set; }
        public string Description { get; set; }
    }

For the purpose of this demo I’m using a list to store the employees and roles, you can see them in the FakeData class in the attached source.

The EmployeeViewModel is used to populate the Create and Edit views, it contains an Employee and the SelectList of Roles for the dropdownlist –

    public class EmployeeViewModel
    {
    ...snip...
        public Employee Employee { get; set; }
        public IEnumerable Roles { get; set; }
    ...snip...
    }

The Create View

The Create view follows the standard MVC approach, pass in the EmployeeViewModel, use LabelFor, EditorFor and DropDownListFor.

On the controller side, take the EmployeeViewModel as the argument to the POST Create action method. All the model binding “just works”. This is because the @Html.EditorFor has created html like the following –

<input class="text-box single-line" id="Employee_Firstname" type="text" name="Employee.Firstname" value="" />

Note the name="Employee.Firstname", this matches the EmployeeViewModel.Employee.Firstname, same behaviour applies to Lastname and RoldID.

We stuck with what MVC gave us and everything worked.

The Edit View

With the Edit view we’ll do something different, something you won’t normally do in this scenario, but I want to keep it simple from a code perspective.

The Edit view will take a the EmployeeViewModel to populate the controls, but the POST Edit action method will an EmployeeArgsModel

    public class EmployeeArgsModel
    {
        public int EmployeeID { get; set; }
        public string Firstname { get; set; }
        public string Lastname { get; set; }
        public int RoleID { get; set; }

        public string ReasonForEdit { get; set; }
    }

You’ll note that it has all the properties that the Employee has, and yes, I could have used an Employee instead, but I need to do it this way for demonstration purposes.
I’ve added a string property called ReasonForEdit, this is going to be textbox on the view.

In order for the POST method to get the right parameters and perform model binding the way we are expecting we need to change the way we write the Edit View from how we wrote the Create View.

Why use an arguments model

You could pass in the EmployeeID, Firstname, Lastname, RoleID and ReasonForEdit directly to the action method

    public ActionResult Edit(int employeeID, string firstname, string lastname, int roleID, string reasonForEdit)

But this will quickly become unwieldy. Many parameters would be needed for a search with filtering, sorting, and paging!
Creating a model that captures what you need in a much neater way.

You can combine the usage of an arguments model and simple arguments, there is an example of this in the source code.

The importance of the “name” attribute

For simplicity I’m going to say that you need to match the “name” attribute of your html to the public property on the model the controller takes as an argument. If the controller takes an EmployeeViewModel with an Employee inside it, then the “name”s of your html attributes should be prefixed with “Employee.” and the name of the property.

If you are having trouble working out what names your should be using in the view change your action method to something like –

public ActionResult Edit(FormCollection collectionOfValues)

Use the debugger to check the names of the values passed to the method in the collectionOfValues.

Comparison of Create and Edit views and action methods

The rest of this post deals with the attached source code, please have a look at it before reading on.

The Create view follows the normal MVC approach, the view takes a model and the POST action method takes the same model.

        [HttpPost]
        public ActionResult Create(EmployeeViewModel employeeViewModel)

The Edit view takes a different approach, the view takes the a EmployeeViewModel but the POST action method takes an EmployeeArgeModel.

        [HttpPost]
        public ActionResult Edit(EmployeeArgsModel employeeArgsModel)

Below compares the Razor code and html produced for the two views on a element by element basis, note how the “name” attributes differ.

Firstname

Create View

Razor : @Html.EditorFor(model => model.Employee.Firstname)
binds to EmployeeViewModel.Employee.Firstname property.
HTML : <input id="Employee_Firstname" type="text" value="" name="Employee.Firstname">

Edit View

Razor : @Html.Editor("Employee.Firstname","", "Firstname") 
shows the value in the Employee.Firstname of the Model sent to the view, and binds to Firstname (set in the third argument to Html.Editor) property in the argument to the action method.
HTML : <input id="Firstname" type="text" value="Dave" name="Firstname">

Lastname

Create View

Razor : @Html.EditorFor(model => model.Employee.Lastname) 
binds to EmployeeViewModel.Employee.Lasttname property.
HTML : <input type="text" value="" name="Employee.Lastname" id="Employee_Lastname">

Edit View

Razor : @Html.EditorFor(model => model.Employee.Lastname,"", "Lastname") 
shows the value in the Employee.Lastname of the Model sent to the view and binds to Lastname (set in the third argument to Html.Editor) property in the argument to the action method.
HTML : <input type="text" value="Jones" name="Lastname" id="Lastname">

ReasonForEdit

Edit view

Razor : @Html.TextBox("ReasonForEdit", null)
binds to the ReasonForEdit property in the argument to the action method
HTML : <input type="text" value="" name="ReasonForEdit" id="ReasonForEdit">

Role ID

Create View

Razor : @Html.DropDownListFor(model => model.Employee.RoleID, Model.Roles, "--Select a role --" ) 
binds to EmployeeViewModel.Employee.RoleID property in the argument to the action method.
HTML :

<select name="Employee.RoleID" id="Employee_RoleID" data-val-required="The RoleID field is required." data-val-number="The field RoleID must be a number." data-val="true">
   <option value="">--Select a role --</option>
   <option value="1">Junior Engineer</option>
   <option value="2">Senior Engineer</option>
   <option value="3">Lead Engineer</option>
</select>

Edit View

Razor : @Html.DropDownListFor(model => model.Employee.RoleID, Model.Roles, "--Select a role --", new { Name = "RoleID"} )
binds to the RoleID property in the argument to the action method
HTML :

<select id="Employee_RoleID" data-val-required="The RoleID field is required." data-val-number="The field RoleID must be a number." data-val="true" name="RoleID">
    <option value="">--Select a role --</option>
    <option value="1" selected="selected">Junior Engineer</option>
    <option value="2">Senior Engineer</option>
    <option value="3">Lead Engineer</option>
</select>

Summary

The html elements must be named to match the arguments your action method takes.
If this explanation doesn’t make it clear, I hope the source code will.

ASP.MVC and Web Forms in one web application

I was recently asked to add an ASP.NET MVC 4 application to an existing Web Forms site. The ideal solution was to keep the code bases separate and the apps on a common domain.

But I wasn’t able to achieve this in a way that would satisfy both requirements and produce simple, easy to understand code without changing any of the standard configurations for both apps. There is a post by Scott Hanselman on this topic, but it is from 2011 and requires significant tinkering with the MVC application. I gave it a go, but kept hitting issues with missing dlls, or web.config errors. Unlikely to work without grief, especially with the next release of MVC.

I had to compromise on something. The first option was to combine the two applications into one. Most likely I would create a new MVC 4 app and add the web forms application to it. But this was going to be a hodge-podge of old and new technologies, code and libraries many dating back to .NET 2.0. It would have ruined one of the goals for developing a new app, to move away from legacy code that is becoming harder and harder to maintain.

The second option was to put the apps on two subdomains. This approach seems simple, use a common cookie for both applications and you’ll be logged in to both. I tried this and all worked well. However, there was one snag; the old web forms application makes extensive use of the session and the session would expire if the user spent most of their time on the MVC application without occasionally visiting the web forms app. Their cookie would still be valid, but the data in session would be gone and exceptions would fly!

I came up a quick and dirty solution to keep the lights on, I don’t claim this to be ideal and will work on finding something better. I added global action filter to “ping” a tiny page on the web forms app every time the user loaded an MVC page. It works for now, and I’ll try to find a more elegant solution.

Adaptive/dynamic page numbering in c#

If you need to show many results (tens, hundreds or thousands), in a paged manner, you won’t want to display links to all those pages. I looked online for some c# that would adapt the number of page links shown to with the number of pages returned, but found nothing.

If you get 5 pages of results, show them all. If you get 5,000 pages of results, show some around your current page and less and less the further you get from your current page.

This is something I put together in an hour, I make no claims about its efficiency and there are scenarios that are not catered for (like higher current page than the total number of pages).

Here are some examples of what this code does.

Current Page:1 Total Pages:40 Pages to display around current page:5
1 2 3 4 5 6 7 8 9 10 11 20 30 40

Current Page:90 Total Pages:600 Pages to display around current page:5
1 40 50 60 70 80 85 86 87 88 89 90 91 92 93 94 95 100 110 120 130 140 200 300 400 500 600

Current Page:147 Total Pages:6825 Pages to display around current page:5
1 90 100 110 120 130 140 142 143 144 145 146 147 148 149 150 151 152 160 170 180 190 200 300 400 500 600 700 800 900 1000 1100 2000 3000 4000 5000 6000 6825

You could easily change the code to take a Page type to suit your own needs.

Here’s the code.

namespace NoDogmaBlog
{
    public class PagingHelper
    {
        public IEnumerable<int> GetListOfPages(int currentPage, int pagesAroundCurrent, int totalPages)
        {
            var pages = new Dictionary<int, int>();
            double powerOfTenTotalPages = Math.Floor(Math.Log10(totalPages));
            if ((int)powerOfTenTotalPages == 0)
            {
                powerOfTenTotalPages = 1;
            }
            pages.Add(1, 1);
            if (!pages.ContainsKey(totalPages))
            {
                pages.Add(totalPages, totalPages);
            }

            for (int loop = 1; loop <= powerOfTenTotalPages + 1; loop++)
            {
                GetPages(pages, currentPage, pagesAroundCurrent, totalPages, (int)Math.Pow(10, loop - 1));
            }
            return pages.OrderBy(k=>k.Key).Select(p=>p.Key).AsEnumerable();
        }

        private void GetPages(Dictionary<int, int> pages, int currentPage, int pagesAroundCurrent, int totalPages, int jump)
        {
            int startPage = ((currentPage / jump) * jump) - (pagesAroundCurrent * jump);

            if (startPage < 0)
            {
                startPage = 0;
                pagesAroundCurrent = 10;
            }

            int endPage = currentPage + (pagesAroundCurrent * jump);
            if (endPage > totalPages)
            {
                endPage = totalPages;
            }
            AddPagesToDict(pages, startPage, endPage, jump);
        }

        private void AddPagesToDict(Dictionary<int, int> pages, int start, int end, int jump)
        {
            for (int loop = start; loop <= end; loop += jump)
            {
                if (!pages.ContainsKey(loop))
                {
                    if (loop > 0)
                    {
                        pages.Add(loop, loop);
                    }
                }
            }
        }
    }
}

Drop down lists in ASP.NET MVC

This post shows two methods of implementing drop down lists in ASP.NET MVC 4. The code for data access and the general layout of the application should not be considered suitable for anything other than pedagogical purposes.

The provided source code uses entity framework and requires a local database to be running, see the web.config for naming.

The main components of the application are Vehicle and TyreType classes, and controllers for each.
The controllers have the standard Index/Create/Edit/Details/Delete views and actions.
The VehicleController shows two ways of providing a TyreType drop down list, one using the ViewBag and the other using a VehicleViewModel.

The TyreType is as follows.

using System.ComponentModel.DataAnnotations;

namespace Automobile.Models
{
    public class TyreType
    {
        public int TyreTypeID { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public string Material { get; set; }
    }
}

And the Vehicle looks like this.

using System.ComponentModel.DataAnnotations;

namespace Automobile.Models
{
    public class Vehicle
    {
        public int VehicleID { get; set; }
        [Required]
        public string Name { get; set; }
        public string Description { get; set; }
        public double MSRP { get; set; }
        [Required]
        public int TyreTypeID { get; set; }
        public virtual TyreType TypeType { get; set; }
    }
}

The TyreTypeController is a standard controller with text boxes for entering information on the Edit and Create views.

The VehicleController has a drop down list filled with available tyre types as found in the database.

Using the ViewBag

The first method of filling the drop down list is to use the ViewBag.

In the [HttpPost]Edit method we have –

ViewBag.TyreTypeID = new SelectList(db.TyreType, "TyreTypeID", "Name", vehicle.TyreTypeID);

I’ll explain in detail what this line of code is doing –
ViewBag.TyreTypeID – is referencing the ViewBag and dynamically adding an entry called TyreTypeID.

new SelectList(db.TyreType, "TyreTypeID", "Name", vehicle.TyreTypeID) – is doing five things –

  1. new SelectList – creates a new SelectList(this is what drop down lists use)
  2. db.TyreType – passing in the TypeTypes from the database
  3. "TyreTypeID" – specifying that this public property of TyreType will be used for dataValueField
  4. "Name" – specifying that this public property of TyreType will be used for dataTextField
  5. vehicle.TyreTypeID – specifying the selected value in the drop down list, note that it is the same property as the dataValueField

Inside the TyreType Edit view we have –

@model Automobile.Models.Vehicle
…snip…
   <div class="editor-label">
      @Html.LabelFor(model => model.TyreTypeID, "Type Type")
   </div>
   <div class="editor-field">
      @Html.DropDownList("TyreTypeID","--Select a tyre type--")
      @Html.ValidationMessageFor(model => model.TyreTypeID)
   </div>

In this example the "TyreTypeID" specifies both the source of items for the drop down list and the destination property for the selected value that will be sent back to the controller. In the example, the Vehicle is sent to the Edit action, so the Vehicle. TyreTypeID is set with the selected value.

I found this very confusing at first because I wanted to change the name of the ViewBag property for storing the drop down list items, so my selected value was being lost. MVC is doing a lot by convention over coding, if you fight it you will have to learn many rules.

I’m not a big fan of this approach, too many things are happening without my explicit control and if forces me to use the same name for a list of items (the SelectList in the ViewBag) and the selected item (an int).

Using a ViewModel

One alternative is to create a ViewModel for the Vehicle and the values for the drop down list. Note again, I’m not advocating this methodology for data access for production code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Automobile.DataAccess;
using Automobile.Models;

namespace Automobile.ViewModels
{
    public class VehicleViewModel
    {
        private AutomobileContext db = new AutomobileContext();
        public IEnumerable<SelectListItem> TyreTypes { get; set; }
        public Vehicle Vehicle { get; set; }
        public VehicleViewModel(Vehicle vehicle)
        {
            Vehicle = vehicle;
            TyreTypes = PopulateTyreTypes();
        }
        private IEnumerable<SelectListItem> PopulateTyreTypes()
        {
            var tyreTypesQuery = db.TyreType.OrderBy(t => t.Name);
            return new SelectList(tyreTypesQuery,"TyreTypeID","Name");
        }
    }
}

Inside the VehicleController I have

public ActionResult Create()
{
   //we're going to use the view model to send the tyre types to the view here.
   var vehicleViewModel = new VehicleViewModel(new Vehicle());
   return View(vehicleViewModel);
}
   
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Vehicle vehicle)
{
   if (ModelState.IsValid)
   {
      db.Vehicle.Add(vehicle);
      db.SaveChanges();
      return RedirectToAction("Index");
   }
   var vehicleViewModel = new VehicleViewModel(vehicle);
   return View(vehicleViewModel);
}

And the view has

@model Automobile.ViewModels.VehicleViewModel
…snip…
<div class="editor-label">
   @Html.LabelFor(model => model.Vehicle.TyreTypeID, "Tyre Type")
</div>
<div class="editor-field">
   @Html.DropDownListFor(model => model.Vehicle.TyreTypeID, Model.TyreTypes, "--Select a tyre type--" )
   @Html.ValidationMessageFor(model => model.Vehicle.TyreTypeID)
</div>

@Html.DropDownListFor(model => model.Vehicle.TyreTypeID, Model.TyreTypes, "--Select a tyre type--" ) is doing three things –

  1. model => model.Vehicle.TyreTypeID – specifies where the selected value from the DDL is stored
  2. Model.TyreTypes – is the source of SelectListItems for the DDL
  3. "--Select a tyre type--" – is a default value

This is the approach I prefer. Full source code is a attached here.