Search code examples
c#asp.net-mvcaop

ASP.NET: How to make data visible for AOP/Cross-cutting concerns?


I would be interested in seeing a relevant pattern for this, but here is my immediate specific problem.

I have a requirement to modify logging in a web application such that every entry in the log is annotated with the entity (user name or process name) responsible for executing the code that resulted in the log entry. For example, rather than:

timestamp level loggerName A sensitive object was deleted from the database

you would get

timestamp level loggerName [ELLIOT.ALDERSON] A sensitive object was deleted from the database

or

timestamp level loggerName [DAILY CRON JOB] A sensitive object was deleted from the database

In addition to identifying the "user" (or process) that took an action, if it is a user, there is also a requirement to log information about the request itself (e.g. ip address, user agent, headers, etc.), although that data can be written to an adjunct log so the main log itself stays readable.

In Java, this was relatively trivial to do without modifying the interface to our logger because the HTTP server we use (Tomcat) 'guarantees' one request/one thread, resulting in my being able to put both user information and request information in thread-local variables. Any of my code, anywhere, could figure out "who" called it and access request properties by asking for the current user and request associated with that thread, with no need to pass user and request variables in every method down through the entire application. Which meant that when any of my code wrote to the log, my minimally-modified logger code could produce the desired output without changing any single call to the logger in my application.

In C#.NET, I don't know how to do this. IIS pretty much guarantees thread reuse from a pool, so there goes thread-local variables to identify what user and which request is associated to any particular method call (and therefore the the user/request to tie to logger calls made by that method). All of the AOP articles I've ever read deal with applying behavior, not so much data. Inside the controller method itself, of course, I can see session and request information. But the controllers call methods that call methods that call methods, etc. ad nauseum, those methods don't have visibility unless the session and request are passed as additional parameters to every method, which is a non-starter (I also thought of and dismissed walking the stack up to the controller or until I'm convinced there is no controller; however, the stack trace just essentially identifies the source code associated with a particular frame, it doesn't give you access to the actual objects on the stack. Plus, as expensive as formatting and writing log data is, the additional expense of walking the stack seems a bit excessive).

Is there a technique that would allow me the same kind of visibility to arbitrary context-specific data (in this case session and request objects) to my cross-cutting concern code?


Solution

  • If you need a static access to current request data you can use HttpContext.Current.Items . It Is a dictionary of string, object and differs for every request. If you change thread (i.e. you are using async await) the context will be preserved and you will find the correct data.