SingingEels : Development Community & Resource

Login

Articles

  • ADO.NET (2)
  • ASP.NET (36)
  • LINQ (5)
  • Security (2)
  • Silverlight (3)
  • SQL (7)
  • Standards (5)
  • WCF (2)

Syndication

  • Articles RSS
  • Blogs RSS

Contribute

  • Our Authors List
  • Member Sign-Up
  • Suggestions Box

Logging with ASP.NET MVC Action Filters

(Aug 19 2008 - 07:23:15 PM by Timothy Khouri) - [print article]

Logging is a common Cross-Cutting Concern that many ASP.NET developers solve in the Global.asax file. Because MVC is built on top of ASP.NET you *could* tap into the same solution, but there is a better way. This article will show how easy it is to add logging to your web app using ASP.NET MVC Action Filters.

Action Filters give you the ability to run custom code before or after an action (or page) is hit. Applying action filters to your MVC app is simple because they are implemented as attributes that can be placed on a method (an individual Action), or a class (the entire Controller).

To show how easy this is, we're going to take the out-of-the-box ASP.NET MVC template, and very slightly tweak it to begin logging. We'll add one class (our custom Action Filter), and salt the existing pages with our new "LogRequest" attribute.

Creating a Custom Action Filter

To create your own action filter, you simply have to inherit from the base "ActionFilterAttribute" class that's already a part of the MVC framework. To make this easier on myself, I've also implemented the IActionFilter interface so that Visual Studio can auto-generate my two methods for me.

At this point, my custom action filter looks like this:

public class LogsRequestsAttribute : ActionFilterAttribute, IActionFilter
{
   void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
   {
       // I need to do something here...

   }

   void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
   {
       // I need to do something here...

   }
}

The ActionFilterAttribute and IActionFilter interface comes from the System.Web.Mvc namespace.

It's important to remember that this article was written (and the sample app was compiled) for ASP.NET MVC Preview 4. When the beta and release is eventually out, specifics of the article may not be 100% relevant. However, this capability should remain the same.

Applying Our Custom Action Filter

Now that we have created our action filter, we need to apply it to our Controllers or optionally, to our Actions. Because logging is something that you would likely want on all of your "pages", we'll simply add it at the controller level. Here is what we've added to the two existing controllers that were supplied in the ASP.NET MVC template.

// HandleError was already there...
[HandleError]
[LogRequest]
public class HomeController : Controller
{
   ...
}

// HandleError was already there...

[HandleError]
[LogRequest]
public class AccountController : Controller
{
   ...
}

That's it! The ASP.NET MVC framework will automatically call our methods (OnActionExecuting and then OnActionExecuted) when a request comes in to any of those two controllers.

At this point, all we have to do is actually implement our logging code. Because I want to be able to easily report against my site's activity, I'm going to log to a SQL database. Now, it's important to note that action filters are executed synchronously (for obvious reasons), but I don't want the user to have to wait for my logging to happen before he can enjoy my great site. So, I'm going to use the fire and forget design pattern.

When we're all done, this is what our logger will look like:

// By the way, I'm using the Entity Framework for fun.
public class LogRequestAttribute : ActionFilterAttribute, IActionFilter
{
   private static LoggerDataStoreEntities DataStore = new LoggerDataStoreEntities();

   void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
   {
       ThreadPool.QueueUserWorkItem(delegate
       {
           DataStore.AddToSiteLog(new SiteLog
           {
               Action = filterContext.ActionMethod.Name,
               Controller = filterContext.Controller.ToString(),
               TimeStamp = filterContext.HttpContext.Timestamp,
               IPAddress = filterContext.HttpContext.Request.UserHostAddress,
           });

           DataStore.SaveChanges();
       });
   }
}
Update: Sep 12 2008

As was mentioned in a comment below, to get the "ActionMethod" in Preview 5, you would use:

filterContext.RouteData.Values["action"]

Conclusion

There are a lot of features in MVC that could each merrit their own articles, but Action Filters are definately one feature that shows off the advantages of the MVC design pattern. Action Filters make perfect sense for cross-cutting concerns like logging, but you can get creative with how and why you use them.

This article isn't here to show you the best way to do logging, but rather how and why you would use ASP.NET MVC Action Filters. Here's the source code, play around with it: MVC_CustomActionFilter_Logging.zip

  • Sep 09 2008 - 01:54:00 PM wshaddix

    You could also consider creating a "LoggingController" and have your other controllers inherit from it vs. having to put a [LogRequest] attribute on every controller.

    Also, with preview 5, the way you pull your action method changed to having it in the RouteData dictionary I believe.

You must be logged in to add comments. If you have not already done so, you can create an account here. If you already are a member, you first need to login before you can comment.

Developer / Architect / Author

People to Follow

Experts in the categories related to this article.

  • Jonathan Carter

Related Blogs

These are the most recent blog posts related to this article.

  • Follow up to Self Sorting GridView
  • A Change to the MVC "ActionSelectionAttribute"?
  • How to Handle "Side Content" in ASP.NET MVC
  • LINQ to SQL - Am I Hitting The Database?
  • ASP.NET MVC - Issue with CSS Class Name on ActionLinks

Related Ads

SingingEels.com as of Mar 20 2010 - 11:50:42 AM - (0.125008)