Click here to Skip to main content
15,867,568 members
Articles / Web Development / ASP.NET

Implementing Audit Trails using ASP.NET MVC ActionFilters

Rate me:
Please Sign up or sign in to vote.
4.50/5 (3 votes)
23 Apr 2013CPOL3 min read 26K   12   2
This post will cover how to implement a very basic Audit trail within your ASP.NET MVC Application using custom ActionFilters.

Accountability is always important, especially when dealing with systems that contain sensitive data. It can often be helpful to have an audit trail that will allow you to go back and retrace the steps that a user took, what they saw, where they went and ultimately what they may have done wrong.

This post will cover how to implement a very basic Audit trail within your ASP.NET MVC Application using custom ActionFilters, which will allow you to decorate specific Controllers and Actions that will be designated to log details of a specific user interaction to later identify (or incriminate) them if necessary.

The Problem

A specific user within your system continues to submit incorrect, misspelled and erroneous data in one of the areas of your sensitive application. However, you have no current means of figuring out exactly who they are.

The Solution

We can solve this through creating a custom ActionFilter that we can use to decorate specific Controllers and Actions to be flagged as “Auditable” and will insert an Audit record into our “Auditing” database or table.

First, we will create a very basic framework for a custom ActionFilter.

C#
public class AuditAttribute : ActionFilterAttribute
{
     public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
         //Additional Auditing-based Logic Here
         base.OnActionExecuting(filterContext);
     }
}

Establishing A Basic Audit Record

Then, we will need to determine what kinds of information we will want to store within each of our Audit Records, so we will create an Audit class to store the values and a Context that can be used to access it (for demonstration purposes).

Our class will initially consist of the following fields that will constitute a single Audit record:

  • AuditID (Guid) – A unique identifier for this specific Audit instance
  • UserName (string) -The UserName of the user performing the Action (if available)
  • IPAddress (string) – The IP Address of the user performing the Action
  • AreaAccessed (string) – This will store the URL of the area that was accessed
  • Timestamp (DateTime) – A Timestamp of when the User accessed the area
C#
//Example Audit Class
public class Audit
{
     //Audit Properties
     public Guid AuditID { get; set; }
     public string UserName { get; set; } 
     public string IPAddress { get; set; }
     public string AreaAccessed { get; set; }
     public DateTime Timestamp { get; set; }

     //Default Constructor
     public Audit(){}
}
//Example AuditingContext 
public class AuditingContext : DbContext
{
     public DbSet<Audit> AuditRecords { get; set; }
}

Now, we will need to implement a simple local database that will be used to store our Audit records and allow us to access them as well. This can be accomplished by adding the following area within the web.config of our project:

XML
<connectionStrings>
     <!-- Default Connection goes here -->
     <!-- Our Auditing Context -->
     <add name="AuditContext"
          connectionString="Data Source=(LocalDB)\v11.0;
          AttachDbFilename=|DataDirectory|\Auditing.mdf;Integrated Security=True"
          providerName="System.Data.SqlClient"
     />
 </connectionStrings>

Decorating for Audit-Season

Now that we have a very basic method of saving and retrieving Audit records, we can start fleshing out our custom ActionFilter to populate an Audit whenever a decorated action is performed.

C#
public class AuditAttribute : ActionFilterAttribute
{
     public override void OnActionExecuting(ActionExecutingContext filterContext)
     {
          //Stores the Request in an Accessible object
          var request = filterContext.HttpContext.Request;
          //Generate an audit
          Audit audit = new Audit()
          {
               //Your Audit Identifier     
               AuditID = Guid.NewGuid(),
               //Our Username (if available)
               UserName = (request.IsAuthenticated) ? 
                          filterContext.HttpContext.User.Identity.Name : "Anonymous",
               //The IP Address of the Request
               IPAddress = request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? request.UserHostAddress,
               //The URL that was accessed
               AreaAccessed = request.RawUrl,
               //Creates our Timestamp
               TimeAccessed = DateTime.UtcNow
          };

          //Stores the Audit in the Database
          AuditingContext context = new AuditingContext();
          context.AuditRecords.Add(audit);
          context.SaveChanges();

          //Finishes executing the Action as normal 
          base.OnActionExecuting(filterContext);
     }
}

And we can now add our new [Audit] attribute to any available controllers or actions that we want this to be performed in.

C#
[Authorize]
public class HomeController : Controller
{
     public ActionResult NormalAction()
     {
         return View();
     }
     [Audit]
     public ActionResult AuditedAction()
     {
         return Content("Audit Fired!");
     }

     //Other Actions Here
}

Testing. Testing 1. 2. 3.

So after creating as many “auditable” actions as you desire, you can log in to your application and begin hitting as many of the [Audit] actions as you can to build a decent set of them within your Audit database. When you are all finished with this, we will create a very basic action to display our Audit Trail:

C#
public ActionResult ViewAuditRecords()
{
     var audits = new AuditingContext().AuditRecords;
     return View(audits);
}

and after building it and accessing it, you will be presented with a very basic audit trail:

Example of Audit Logging Trail

A basic example of our Testing User browsing around our application.

Additional Functionality Coming Soon

This blog post covered establishing a very basic system for setting up auditing that could easily be expanded upon. A follow-up will be posted in the future and will discuss methods of adding additional functionality to the Auditing ActionFilter such as serializing Request Data using JSON (to see exactly what our users were posting into fields), creating relationships within Audit objects (to monitor “User Sessions”) and more!

You can download this current example to update, modify and change to suit your needs as well from Github.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
An experienced Software Developer and Graphic Designer with an extensive knowledge of object-oriented programming, software architecture, design methodologies and database design principles. Specializing in Microsoft Technologies and focused on leveraging a strong technical background and a creative skill-set to create meaningful and successful applications.

Well versed in all aspects of the software development life-cycle and passionate about embracing emerging development technologies and standards, building intuitive interfaces and providing clean, maintainable solutions for even the most complex of problems.

Comments and Discussions

 
QuestionGetting Database error Pin
vaibhavs12015-Jun-15 1:04
vaibhavs12015-Jun-15 1:04 
Hey Rion thanks foe writing this article. I am getting an error at examples link (Auditable Action Example) after login into the application
and getting error : CREATE DATABASE permission denied in database 'master'.

I'm using VS 2012 sql databaase and do not have actual database installed on my computer.

The thing is the database is created with the table and application is working fine till the 3 examples comes up.

please help!
QuestionWhat to do if I want to log user after the controller action executes? Pin
Manan Vaghasiya25-Jul-13 23:19
professionalManan Vaghasiya25-Jul-13 23:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.