title: Audit Logging using ASP.NET MVC 4 ActionFilter
body: <p>I'm building a web app using ASP.NET MVC 4, with data storage provided by T-SQL database via Entity Framework. I'm integrating audit logging as I go, and I'd like to provide a nice human-readable summary of the action, so that I can present a friendly logs view with clear statements like "User Bob logged in", "User Alice updated article 'Foo'", etc.</p>
  
  <p>An audit record currently consists of:</p>
  
  <ul>
  <li>GUID</li>
  <li>timestamp</li>
  <li>user ID</li>
  <li>action category (controller name)</li>
  <li>action (action method name)</li>
  <li>IsError (boolean; true means either this is a record of an error, or this action did not complete successfully)</li>
  <li>blob of serialised details</li>
  </ul>
  
  <p>At the moment, my logging uses a custom attribute which implements <code>IActionFIlter</code>; the <code>OnActionExecuting()</code> method logs the attempted action (serialising things like URL, parameters etc to the detail blob) and the <code>OnActionExecuted()</code> method goes back and sets IsError to true if there are no errors, and appends either the returned result or exception with error message and stack trace etc to the details. I want to add another column for description strings, but I can't see a tidy way to do it.</p>
  
  <p>The furthest I got was to pass a string to the attribute, something like "User $user logged in" and then have the log method scan the string for the $ character and replace that word with anything from the parameters dictionary whose key value matches that word (minus the $ character). This is a little limited; for example, if articles are stored by ID number, then the best you can manage is "User 18 edited article 37". There's no real way to get at the username or article title; you can't pass instance data to the attribute because it's baked in at compile time, and I don't really want my logging method to be making all sorts of database calls to get that sort of data, not least because it then becomes impossible (or at least a real pain) to have a single generic logging method.</p>
  
  <p>The alternative to all this is to have a static audit logging class and call something like <code>AuditRecord.WriteLog(foo);</code> all over the place, perhaps with some kind of descriptor class I can use (or inherit from) to describe different types of action, storing all the parameters and generating a description string as needed, but seems less elegant to me; I really like being able to just tag <code>[AuditLog]</code> on top of a method and know that it'll be recorded.</p>
  
  <p>I'd like to avoid huge amounts of conditional logic, like using the controller and action names in some big switch statement to select the correct string template. If I could just get hold of things like article titles in the logging method then it'd be fine. Is there a neat, simple way to do this? </p>