views:

394

answers:

3

I'm currently working on an ASP.NET MVC project using NHibernate and I need to keep track of changes on some entities in order to be able to make some reports and queries over the data. For this reason I wanted to have the data in a table, but I'm trying to decide where to "hook" the auditing code.

On the NHibernate layer:

  • PRO: Powerful event system to track any change
  • PRO: Nothing can be changed in the application without notice (unless someone uses raw SQL...)
  • CON: As I have a generic repository... then I have to filter out the useful entities (I don't need to track everything).
  • CON: I don't have easy access to the controller and the action so I can only track basic operations (update, delete...). I can get the HttpContext at least to get some info.

On an Action Filter at Controller level:

  • PRO: Full information on the request and web application status. This way I can distinguish an "edit" from a "status change" and be more descriptive in the audit information.
  • CON: Someone can forget a filter and an important action can be taken without notice which is a big con.

Any clue?

Update: See how to Create an Audit Log using NHibernate Events.

+1  A: 

I'd rather put it in the data (NHibernate in your case) layer. Putting it in the controller and asking other people (or yourself, in the future) to implement controllers accordingly conflicts with object-oriented design principles.

Adrian Grigore
+4  A: 

I think doing this at the repository level is a much better fit. Mostly because you may, in the future, decide to add some method of access to your repository which does not go through MVC (e.g., a WCF interface to the data).

So the question becomes, how do you address the cons you've listed about doing it on the NHibernate layer?

Filtering out the useful entities is simple enough. I would probably do this via a custom attribute on the entity type. You can tag the entities you want to track, or the ones you don't; whichever is easier.

Figuring out what the controller really intended is harder. I'm going to dispute that you can "get the HttpContext"; I don't think it is a good idea to do this in a repository, because the separation of concerns. The repository should not be dependent on the web. One method would be to create custom methods on the repository for actions you'd like to track differently; this is especially attractive if there are other aspects of these edits which behave differently, such as different security. Another method is to examine the changes by comparing the old and new versions of the objects and derive the actual nature of the change. A third method is to make no attempt to derive the nature of the change, but just store the before and after versions in the log so that the person who reads the log can figure it out for themselves.

Craig Stuntz
A fourth method would be to have the controller provide a mandatory "Comments" parameter that describes that database operation.
Adrian Grigore
+1 Great suggested approaches on dealing with the CONS of the problem. I'd think I'd prefer custom repository methods for the different intents -- it not only provides the desired auditing results, but provides good expression of semantics in the code as well.
Peter Meyer
After listing the cons of the Filter I realized it was not a good idea. Thanks for the tips and I agree that I will violate the SoC accessing the HttpContext. I may use a Filter to implement the "comments" suggested by Adrian and go the NHibernate way.
Marc Climent
+1  A: 

I do this with NHibernate. Objects that require auditing implement an IAudtable interface and I use an Interceptor do the auditing on any object that implements IAuditable by intercepting OnFlushDirty, OnDelete, and OnSave.

Jamie Ide