Sometimes you want to know what your users are doing in your system. You probably don't want to spend too much time on this feature, but it is nice to be able to prove that a certain user introduced data inconsistencies and it isn't your fault. Obviously, the "client is always right" but tracking down the source of a problem (and pointing fingers) is something that is very useful to developers like us!

We decided to add events in our controllers to catch when an object is updated or inserted. When that occurs, we can produce simple HTML about the object through reflection. If the user changed an object, we can generate a nice view of what was changed, as well. Here is an example of a save to the database. We generate a string and insert it into our ElectronicJournal (audit log) to keep track of all the actions in the system:

Type: InventoryItem
Schema: SubSonic.TableSchema+Table
ItemGUID: d7fc5f85-129a-4909-b4ac-490fc26d9007
StoreID: TestStore1
StorePrice: [12.99] -> [7.99]
Tax1: True
Tax2: True
Tax3: True
Tax4: True
CreditPoints: [129] -> [79]
SalePoints: [1299] -> [799]
BonusPoints: 0
StockQuantity: 0
IsReportable: True
PromptForPrice: False
HideItemInStore: False
Item: 3.2
Store: Test Store 1
TableName: InventoryItems
ProviderName:
NullExceptionMessage: {0} requires a value
InvalidTypeExceptionMessage: {0} is not a valid {1}
LengthExceptionMessage: {0} exceeds the maximum length of {1}

By tracking various actions in your database, you can make a quick listing to track a user's actions. If you add a few more columns in your audit log table, you can track who did the change, when they did it, their IP, etc. We keep track of a set of action types which allows us to filter by "Saved Objects" on a particular date, for a certain person (for example). This allows us to visualize what a user did in an efficient manner. Obviously this is a pretty simple example that is based on the existence of SubSonic objects and we don't handle complicated scenarios for the time being. If you run update queries on the database that change multiple objects in one save, we obviously never generated any SubSonic objects and cannot track those changes. However, most of the time, it is sufficient to have a good idea of what is going on. Again, we reap the benefits of our standard use of custom SubSonic controllers.

I have included a pretty simple utility class that you can use to do this. It's pretty generic, so you can easily use this with your own classes. The methods of interest in the class are:

public static string DumpObjectToHtml<T>(T before, T after)

and

public static string DumpObjectToHtml(object obj)

 

The class includes some other useful functions like:

 

public static C Paging<T, C>(C result, int startRowIndex, int maximumRows)
where T : ActiveRecord<T>, new()
where C : ActiveList<T, C>, new()

and

public static void Sort<T, C>(string sort, C result)
where T : ActiveRecord<T>, new()
where C : ActiveList<T, C>, new()

 

Those two methods enable you to page or sort a SubSonic collection if you can't use SQL Paging/Sorting. I had to use this to Page/Sort a SubSonic collection containing both database objects and my objects that I created after the database call. I hope this can be useful to someone.

SubSonicHelper.cs (3.57 kb)

kick it on DotNetKicks.com