-
-
Save rabbal/82abe5253dd95c9bcb53 to your computer and use it in GitHub Desktop.
Audit ActionFilter in ASP.NET MVC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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