Custom ActionFilter in ASP.NET MVC with EntLib Logging Application Block

A few days ago I posted an example of a Custom ASP.NET MVC ActionFilter using AutoMapper and thought I would mention another one I created for a presentation awhile back that uses the Enterprise Library Logging Application Block.

ActionFilters feel like Decorators to me. I use Decorators and/or AOP to pull cross-cutting concerns out of my business logic. This helps make the code that much more maintainable and testable. ActionFilters can do the same thing. Whenever you find your controllers in ASP.NET MVC becoming too fat and doing more than just delegating requests to your model and serving up the correct view for the request, you should step back and refactor the code and understand whom should be getting those responsibilities that have crept into the Controller.

Here is an example of pulling out logging functionality into an ActionFilter. The point of the example is nothing more than to show you an example of a custom ActionFilter in ASP.NET MVC to remove cross-cutting concerns and infrastructure code out of the controller action. The filter itself is pretty simple, but the power of ActionFilters are pretty amazing.

 

Custom Logging ActionFilter

Most of the time you will create a custom ActionFilterAttribute for your ActionFilters unless you want to create some type of ActionFilter Repository and dish out the ActionFilters via a Custom ControllerActionInvoker. Here is an LogFilterAttribute that uses the Enterprise Library Logging Application Block's LogWriter for logging message to your data store. Note that you want to be careful about putting too much code inside an attribute. In cases where you have a complex ActionFilter you will probably want to separate the attribute from the filter. In this case, things are pretty simple:

 

public class LogFilterAttribute : ActionFilterAttribute

{

    [Dependency]

    public LogWriter Logger { get; set; }

 

    public string Category { get; set; }

 

    public override void OnActionExecuting(ActionExecutingContext filterContext)

    {

        string message = string.Format("{0} ActionMethod on {1}Controller executing...", filterContext.ActionDescriptor.ActionName,

                                       filterContext.ActionDescriptor.ControllerDescriptor.ControllerName);

 

        var category = Category ?? "General";

 

        Logger.Write(new LogEntry { Message = message, Categories = new[] { category }});

    }

}

 

For demo purposes, the LogFilterAttribute just displays the name of the ActionMethod that is decorating and currently executing. If I place it on an Action as such:

 

public class RegionsController : Controller

{

    private readonly IRegionDAO _dao;

 

    public RegionsController(IRegionDAO dao)

    {

        _dao = dao;

    }

 

    [LogFilter(Category = "General")]

    public ActionResult Index()

    {

        var regions = _dao.FetchAll();

        return View(regions);

    }

 

}

 

The LogWriter will write something like:

 

Index ActionMethod on RegionsController executing...

 

to the General Category as configured by the Enterprise Library Logging Application Block.

 

Unity Dependency Injection and Custom ControllerActionInvoker

I am not going to dive into the Unity Application Block Configuration of the Logging Application Block in detail as it is beyond the scope of this post, but you will notice in the LogFilterAttribute that it has a DependencyAttribute on the Logger Property that encapsulates the LogWriter. The DependencyAttribute is a Unity Attribute that can be used to decorate properties that have dependencies and have Unity inject the dependency into the property.

 

[Dependency]

public LogWriter Logger { get; set; }

 

I have a Custom ControllerActionInvoker that injects the dependency into the LogFilterAttribute as simple as:

 

public class CustomControllerActionInvoker : ControllerActionInvoker

{

    private readonly IUnityContainer _container;

 

    public CustomControllerActionInvoker(IUnityContainer container)

    {

        _container = container;

    }

 

    protected override FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)

    {

        var filters = base.GetFilters(controllerContext, actionDescriptor);

        foreach (var filter in filters.ActionFilters)

            _container.BuildUp(filter.GetType(), filter);

 

        return filters;

    }

}

 

Very cool IMHO and shows the wonderful extensibility of the ASP.NET MVC Framework.

Maybe I will show this off at the next Tampa ASP.NET MVC Developer Group in detail as it further talks about ASP.NET MVC Extensibility that we discussed this month and shows off integration with Enterprise Library that a number of people have wanted us to talk about.

 

Conclusion

Enjoy the wonderful worlds of ASP.NET MVC and Enterprise Library to pull those cross-cutting concerns from your code. Can't wait for Enterprise Library 5.0 and ASP.NET MVC 2.0 :)

 

David Hayden

 

ASP.NET MVC Tutorials

 

posted on Tuesday, July 14, 2009 12:02 PM

Main

News

Green Tea

.NET Development

Enterprise Library

Patterns & Practices