Ah, so that's reflection!
Reflection in .NET is something I’d heard of but never knew what it was. I’d also never thought to find out. That all changed when working on a .NET MVC project recently.
One of the requirements for the project I was working on was to create an audit trail of user actions including fields that had been updated. This wasn’t a problem for small records where only 1 or 2 fields were editable by the user. I would simply compare the new value with the previous value however I would have to have an if
statement for each field in the class. Obviously this isn’t DRY so there had to be a better way.
After some investigation I discovered that it was possible to loop through the properties of an object. This meant I could just compare the previous and new values of each field in a foreach
loop. This was a much cleaner solution to my problem especially as I now had some object with around 9 properties which were editable by the user. Using the previous method would have caused me to have to write 9 individual if
statements, not clean at all and very repetitive.
The code I ended up writing was as follows:
private void AuditDetailUpdate(ref DetailRecord original, DetailRecord updated, ref bool objUpdated)
{
var props = typeof(DetailRecord).GetProperties();
foreach (var p in props)
{
Type t = p.PropertyType;
//Only check strings, ints etc..
if (t.IsPrimitive || t.IsValueType || (t == typeof(string)))
{
Object fieldOriginal = p.GetValue(original);
Object fieldUpdated = p.GetValue(updated);
if ((fieldOriginal != null) && !fieldOriginal.Equals(fieldUpdated))
{
objUpdated = true;
p.SetValue(original, fieldUpdated);
auditRepository.UpdateAdditionalHour(currentUser, original.Id, p.Name, fieldOriginal.ToString(), fieldUpdated.ToString());
}
}
}
}
A brief overview of what’s happening is as follows:
-
GetProperties() returns an array of properties System.Reflection.PropertyInfo[] that I will loop through.
-
I then use a
foreach
loop to iterate the properties in the type. -
Within the loop I only want to compare the values of properties which are strings, integers, datetimes etc.. Basically anything that isn’t a complex type. This is because the updated object has come back from a http post from an MVC form and the child objects of that record aren’t populated. I have to specifically check if it is a string also, as strings in .NET are actually reference types even though they have many characteristics of value types. For more info see MSDN
-
I then get the value of the property from both the original and updated objects and compare them to see if they have changed.
-
Only if the value has been updated do I set the objUpdated flag to
true
and then set the value on the original object. This is because the original object in my case is an entity framework proxy object whereas the updated object has been mapped from a view model. TheobjUpdated
flag is used to determine whether I need to update EF or not. -
Finally I call a method on my audit repository to create an audit log record with the previous and new values along with the name of field being updated.