Search code examples
c#asp.net-mvcdependency-injectionsimple-injector

Add SessionId to Logger when constructed via Simple Injector


Using c# MVC and Simple Injector.

My Logger is created as so;

container.Register<ILogger>(() => new Logger("MVC Logging Startup"), Lifestyle.Scoped);

And this is passed into all the classes that need it perfectly. However, I need a way of identifying events that happen to a user. To my mind the easiest way of implementing that is by passing the sessionId into the logger, so that each time a class that uses the logger, whether its a controller, a business class or a data handling class I can track that individual sessions event.

container.Register<ILogger>(() => new Logger(this.Session.SessionId), Lifestyle.Scoped);

won't work as on application Startup the HttpContext is null. The only way I can see to do this is to manually set the sessionId into the logger each time a controllers constructor is called. But that just seems to be counter intuitive. So how do I pass the current SessionId (or a Unique identifier) into my Logger.


Solution

  • The problem you are having is caused by you injecting runtime data into your components. This is an anti-pattern and should be prevented, because:

    it causes ambiguity, complicates the composition root with an extra responsibility and makes it extraordinarily hard to verify the correctness of your DI configuration.

    The solution is to:

    let runtime data flow through the method calls of constructed object graphs.

    The linked article also describes the solution to your problem, which is to extract the runtime value behind an abstraction. For instance:

    public interface IUserContext
    {
        int SessionId { get; }   
    }
    

    This can be implemented as follows:

    class HttpSessionUserContext : IUserContext 
    {
         public int SessionId => (int)HttpContext.Current.SessionId;
    }
    

    Now you can complete your registration as follows:

    var userContext = new HttpSessionUserContext();
    
    container.Register<ILogger>(() => new Logger("MVC Logging Startup", userContext), 
        Lifestyle.Scoped);