Skip to content

Instantly share code, notes, and snippets.

@mgroves
Created February 15, 2012 03:38
Show Gist options
  • Save mgroves/1832983 to your computer and use it in GitHub Desktop.
Save mgroves/1832983 to your computer and use it in GitHub Desktop.
Audit ActionFilter in ASP.NET MVC
public class CustomerController : Controller
{
public ViewResult Index()
{
return View();
}
public ViewResult Edit()
{
var existingCustomer = new Customer();
existingCustomer.Name = "Matthew D. Groves";
existingCustomer.ShoeSize = 14;
existingCustomer.Birthday = new DateTime(1980, 1, 29);
return View(existingCustomer);
}
[HttpPost]
[AuditAttribute(typeof(Customer), "Name", "ShoeSize")]
public ActionResult Edit(Customer customer)
{
if(ModelState.IsValid)
{
// put code here to save edited customer to database
return RedirectToAction("Index");
}
return View(customer);
}
}
public class AuditAttribute : ActionFilterAttribute
{
readonly Type _typeToAudit;
readonly string[] _fieldsToAudit;
public AuditAttribute(Type typeToAudit, params string[] fieldsToAudit)
{
_typeToAudit = typeToAudit;
_fieldsToAudit = fieldsToAudit;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.Controller.ViewData.ModelState.IsValid)
{
var auditRecord = new AuditRecord();
auditRecord.ActionName = filterContext.ActionDescriptor.ActionName;
auditRecord.ControllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
auditRecord.DateTimeAuditRecorded = DateTime.Now;
auditRecord.EntityTypeAudited = _typeToAudit.Name;
auditRecord.User = "nlopez"; // use in reality something like: filterContext.HttpContext.User.Identity.Name
var parameters = filterContext.ActionDescriptor.GetParameters();
var parameterToAudit = parameters.SingleOrDefault(p => p.ParameterType == _typeToAudit);
var argumentToAudit = filterContext.ActionParameters[parameterToAudit.ParameterName];
var propertiesToAudit = parameterToAudit.ParameterType.GetProperties()
.Where(p => _fieldsToAudit.Contains(p.Name));
foreach (var propertyInfo in propertiesToAudit)
{
var pi = argumentToAudit.GetType().GetProperty(propertyInfo.Name);
var auditValue = pi.GetValue(argumentToAudit, null);
auditRecord.AuditedFields[propertyInfo.Name] = auditValue.ToString();
}
filterContext.Controller.TempData["AuditValues"] = auditRecord;
}
else
{
filterContext.HttpContext.Response.Write("Auditing not performed, since submission was not valid.");
}
}
}
public class Customer
{
[Required]
public string Name { get; set; }
[Required, Range(1, 20)]
public int ShoeSize { get; set; }
[Required]
public DateTime Birthday { get; set; }
}
public class AuditRecord
{
public AuditRecord()
{
AuditedFields = new Dictionary<string, string>();
}
public IDictionary<string, string> AuditedFields { get; private set; }
public string EntityTypeAudited { get; set; }
public DateTime DateTimeAuditRecorded { get; set; }
public string User { get; set; }
public string ControllerName { get; set; }
public string ActionName { get; set; }
}
@model ActionFiltersKitchenSink.Controllers.Customer
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Customer</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ShoeSize)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ShoeSize)
@Html.ValidationMessageFor(model => model.ShoeSize)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Birthday)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Birthday)
@Html.ValidationMessageFor(model => model.Birthday)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@using ActionFiltersKitchenSink.Controllers;
@{
ViewBag.Title = "Index";
}
<h2>ActionFilter Audit Demo</h2>
@if (TempData["AuditValues"] != null)
{
<fieldset>
<legend>Audit of last transaction</legend>
<ul>
<li><strong>Entity type:</strong> @((TempData["AuditValues"] as AuditRecord).EntityTypeAudited)</li>
<li><strong>Date/time:</strong> @((TempData["AuditValues"] as AuditRecord).DateTimeAuditRecorded)</li>
<li><strong>User:</strong> @((TempData["AuditValues"] as AuditRecord).User)</li>
<li><strong>Controller name:</strong> @((TempData["AuditValues"] as AuditRecord).ControllerName)</li>
<li><strong>Action name:</strong> @((TempData["AuditValues"] as AuditRecord).ActionName)</li>
<li><strong>Fields</strong>
<ul>
@foreach (var kvp in (TempData["AuditValues"] as AuditRecord).AuditedFields)
{
<li><strong>@kvp.Key</strong>: @kvp.Value</li>
}
</ul>
</li>
</ul>
</fieldset>
}
<p>Click here to @Html.ActionLink("edit the customer record for Matthew D. Groves", "Edit", "Customer")</p>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment