ASP.NET MVC: Using a ActionFilter for logging

The "pre-" preview 3 of the MVC Framework (see here for more information) introduced new features for the ActionFilter.

The "FilterExecutingContext" (using in the OnActionExecuted method) and "FilterExecutedContext" (using in the OnActionExecuting method) are now called "ActionEx…Context".

This is the complete method list from an ActionFilter in this pre-preview:

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            ActionExecutingContext contect = filterContext;
            string test = contect.ActionMethod.ToString();
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            ActionExecutedContext context = filterContext;
            string test = context.ActionMethod.ToString();
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            ResultExecutingContext context = filterContext;
            string test = context.ToString();
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            ResultExecutedContext context = filterContext;
            string test = context.ToString();
        }

A great new feature: You have access to the viewdata form the…

  • ResultExecutedContext
  • ResultExecutingContext
  • ActionExecutedContext Yeah!

image 

With this feature we can now build a very smart logger: Get all ViewData typ information recursive and save this by using Log4Net.

I use this "DumpObject Code" and configure Log4Net like this guy.

The "simple log FilterAction":

namespace Mvc2.Filters
{
    public class LogAttribute : ActionFilterAttribute
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(LogAttribute).Name);

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            ActionExecutedContext context = filterContext;

            StringBuilder logMessage = new StringBuilder();
            logMessage.AppendLine(context.ActionMethod.Name);

            if(context.Result.GetType() == typeof(RenderViewResult))
            {
                RenderViewResult viewResult = context.Result as RenderViewResult;
                logMessage.AppendLine("ActionResult: RenderViewResult");
                logMessage.AppendLine();
                logMessage.AppendLine(Dumper.DumpObject(viewResult.ViewData, 5));
            }
            logMessage.AppendLine();
            log.Info(logMessage.ToString());
        }

    }
}

And now just add the attribute above the Controller:

[Log]
public class EntryController : Controller
{...}

The result in the log.txt:

2008-04-17 20:41:02,204 [10] INFO  LogAttribute [(null)] - List
ActionResult: RenderViewResult

[ObjectToDump] AS Mvc2.Views.Entry.ListViewData = Mvc2.Views.Entry.ListViewData
+<EntryList>k__BackingField AS Mvc2.Helpers.PagedList`1[[Mvc2.Models.DataObjects.Entry, Mvc2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] = Mvc2.Helpers.PagedList`1[Mvc2.Models.DataObjects.Entry]
|+<TotalPages>k__BackingField AS System.Int32 = 2
|+<TotalCount>k__BackingField AS System.Int32 = 17
|+<PageIndex>k__BackingField AS System.Int32 = 1
|+<PageSize>k__BackingField AS System.Int32 = 10
+(System.Collections.Generic.List`1[[Mvc2.Models.DataObjects.Entry, Mvc2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]])
|+_items AS Mvc2.Models.DataObjects.Entry[] = Mvc2.Models.DataObjects.Entry[]
||+[0] AS Mvc2.Models.DataObjects.Entry = Mvc2.Models.DataObjects.Entry
|||+_Id AS System.Guid = 797c70f0-f571-4969-80e8-d4a085445b6d
|||+_Title AS System.String = test
|||+_Url AS System.String = test
|||+_UserId AS System.Guid = cf2e5ccc-bd32-405d-bd54-eda112ebe06c
|||+_Link AS System.String = http...
|||+_Description AS System.String = tealkjdlsakj
|||+_CategoryId AS System.Guid = 7bd8028e-02c1-45f4-a0a6-403f5bf0ff0c
|||+_Date AS System.DateTime = 17.04.2008 15:48:53
|||+_EntryTags AS System.Data.Linq.EntitySet`1[[Mvc2.Models.DataObjects.EntryTag, Mvc2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] = System.Data.Linq.EntitySet`1[Mvc2.Models.DataObjects.EntryTag]
|||+_Category AS System.Data.Linq.EntityRef`1[[Mvc2.Models.DataObjects.Category, Mvc2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] = System.Data.Linq.EntityRef`1[Mvc2.Models.DataObjects.Category]
|||+PropertyChanging AS System.ComponentModel.PropertyChangingEventHandler = System.ComponentModel.PropertyChangingEventHandler
|||+(System.MulticastDelegate)
|||+(System.Delegate)
||+[1] AS Mvc2.Models.DataObjects.Entry = Mvc2.Models.DataObjects.Entry
|||+_Id AS System.Guid = 8e1554c1-47fa-4db5-af41-91c3fcf92fb3
|||+_Title AS System.String = EntryTitle
|||+_Url AS System.String = EntryTitle_13
|||+_UserId AS System.Guid = cf2e5ccc-bd32-405d-bd54-eda112ebe06c
|||+_Link AS System.String = http://.../
|||+_Description AS System.String = Blabla
|||+_CategoryId AS System.Guid = 16d09b0a-2157-43b7-a881-b536e90f7fbf
...

This is not the perfect solution – but it should show the "power" of the new ActionFilters.

I will try to create a better (and more readable) version in the next days – with the RouteData/submitted parameters and so on :)

If you enjoyed this post, please consider leaving a comment or subscribing to the RSS feed to have future articles delivered to your feed reader.

About the author

Written by Code Inside Team

Currently there is no additional info about this author.

3 Responses

Comment on this post

Recent Posts

  • image1452_thumb.png
    Javascript to Dart Translator

      Dart, a Google Javascript alternative was presented a few months ago and the web developer scene are a little bit unsure about the usability of Dart. To declare the language Google has translated the Javascript basics into Dart. The result is this “Translator”. In my opinion the name doesn’t find that well because it’s ...

  • image1366-570x194.png
    Twitter Bootstrap as UI-kit

      HTML and CSS are not foreign words for me but I regret, I’m not a Web designer – I see myself as a webdeveloper. But at least a dressy side is a must. But thank good there are some ready “Systems”. Twitter Bootstrap Twitter Bootstrap is a Toolkit for every kind of Web applications. ...

  • image1441.png
    Fix: the value ‚x‘ is not valid for Foo in ASP.NET MVC

      To get files into the MVC Controller Modelbinding from MVC is a clever method. But in fact it is a little bit complicated to set the error message if the connection failed. Example: public class RegisterModel { ... [Required] [DataType(DataType.EmailAddress)] [Display(Name = "Email address")] public string Email { get; set; } [Required] [Display(Name = ...

  • You Tube API – recall Video Meta files with .NET

      A loooong time ago I’ve blogged about how to access to You Tube with the Google Data APIs. After all that time there are several new ways how to recall files. Google offers You Tube a “simple” surface. If you prefer to do low-Level HTTP calls it is also possible. Aim: I want the ...

  • image1426-570x194.png
    MacBook Pro for .NET Developer – useful ore just pretty?

      I own a MacBook Pro (from 2010) for about a year now and because I’ve used to think about this Question since I have it, I’m going to blog about my experience now. My Notebook Configurations MacBook Pro April 2010 - 2,66 Intel Core i7 - 8GB RAM - 15’’ Glossy Display - Intel ...

Support us