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.

Serializing a stack to XML in C#

Serializing a class to XML in C# is straightforward; most collections can be easily serialized also.

Something like the following will work in most scenarios –

public string GetSerializedString<T>(T objectToSerialize)
{
    var serializer = new XmlSerializer(typeof(T));
    TextWriter textWriter = new StringWriter();

    var xmlWriter = XmlWriter.Create(textWriter);
    serializer.Serialize(xmlWriter, objectToSerialize);

    string result = textWriter.ToString();
    return result;
}

This also works nicely with lists, arrays and the like. But if you want to serialize a stack to XML you get an InvalidOperationException
You must implement a default accessor on System.Collections.Generic.Stack`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] because it inherits from ICollection.

There might be some third party libraries out there that will work but I’m going to stick with Microsoft technologies.

So I need to add an accessor to a stack, but a quick look at the System.Collections.Generic.Stack class using dotPeek shows that the underlying collection is a private array.

namespace System.Collections.Generic
{
    public class Stack<T> : IEnumerable<T>, ICollection, IEnumerable
    {
        private T[] _array;
    ...snip...

I could inherit from the Stack class, access the private array through reflection and add the required interface and methods to my class, or I could write my own stack class, but I don’t like these approaches.
An alternative is to start with a collection that can be serialized to XML successfully and add the required stack functionality, peek, pop and push, to it. This a relatively straightforward approach, is easy to understand and provides a familiar interface. I chose to use the List as my base class.

using System.Collections.Generic;
using System.Linq;

namespace SerializingStack
{
    public class StackList<T> : List<T>
    {
        #region Public Methods

        public void Push(T historyItem)
        {
            Add(historyItem);
        }

        public T Pop()
        {
            if (this.Any())
            {
                T historyItem = base[Count - 1];
                Remove(historyItem);
                return historyItem;
            }

            return default(T);
        }

        public T Peek()
        {
            if (this.Any())
            {
                return base[Count - 1];
            }
            return default(T);
        }

        #endregion
    }
}

A problem with this approach is that order that items come out of the enumerator is the opposite from a traditional stack, but as long as the stack is accessed using peek, pop and push it will work the same. Compromises have to be accepted with mixing the features of two different types.

After deserialization

If you have never deserialized a stack then you can just use the StackList with no problems.

If you are used to working with stack, you’ll know that a stack create from another Stack will have its contents reversed. To overcome this you can call the Reverse method on the new stack. This is due to the way the stack constructor is written.

public Stack(IEnumerable<T> collection)
{
    ...snip...
    ICollection<T> collection1 = collection as ICollection<T>;
    if (collection1 != null)
    {
        ...snip...
        collection1.CopyTo(this._array, 0);
        ...snip...
    }
}

If you want to overcome this issue you will need to implement your own enumerator functionality, this is not very difficult, but I didn’t need to do it for my purposes so I’m not including it here.

Conclusions

Be careful as you create your own types that inherit from Microsoft types, especially when you alter how parts of them work!
Every step you take away from the standard approach you are getting in to trouble, it might not be apparent immediately, but it will catch up with you.
This StackList is a cross between and a stack and list that behaves in some particular/peculiar ways that suit me for a for a limited purpose, I don’t plan to use this code widely.