Ninject and static classes - how to?
Asked Answered
B

2

9

I have a static class and I need to inject some instances into it. A static class can have a static constructor but it must be parameterless. So, how am I supposed to inject something into it?

I do not wish to create a singleton. I wish to have a static class, and one of its methods operate on an instance that should be injected. Below is an example of the sort of thing I need:

public static class AuthenticationHelper
{
    // Fields.
    private static object _lock = new object();
    private static readonly UserBusiness _userBusiness; // <-- this field needs to be injected.

    // Public properties.
    public static User CurrentUser
    {
        get
        {
            if (IsAuthenticated)
            {
                User user = (User)Context.Session[SessionKeys.CURRENT_USER];

                if (user == null)
                {
                    lock (_lock)
                    {
                        if (user == null)
                        {
                            user = _userBusiness.Find(CurrentUserId);
                            Context.Session[SessionKeys.CURRENT_USER] = user;
                        }
                    }
                }

                return user;
            }

            return null;
        }
    }
    public static int CurrentUserId { get; /* implementation omitted for brevity */ }
    public static bool IsAuthenticated { get; /* implementation omitted for brevity */ }
}

Background info: this is an MVC4 application, so I'm using ninject.mvc3 plugin.

PS.: I've seen some questions concerning Ninject and static methods, but none of them seemed to address an issue like this.

Bede answered 31/5, 2013 at 23:46 Comment(0)
G
21

Don't do it. Don't use a static class that needs dependencies of its own. This makes testing harder and other types that depend on this AuthenticationHelper won't be able to include it in their constructor which means they hide the fact that they depend on it.

Instead just do what you would always do: make AuthenticationHelper non-static, implement an IAuthenticationHelper interface on it and inject all dependencies through its public constructor.

But if you insist into keeping that class static (which again is a really bad idea), create a static Initialize(UserBusiness userBusiness) method on it, and call this method in the start-up path of your application. You can't let your DI container call this static method. They don't allow because 1. it's a bad idea, and 2. such static method only has to be called once, so letting your container auto-wire this for you doesn't really help.

Graeme answered 1/6, 2013 at 0:11 Comment(2)
I see. I didn't realize it was such a bad practice, but with your explanation I can now understant it, and will follow your advice. Anyways, it is good to know how to work around this if there's no other option. Thanks!Bede
It's true, sometimes you can't. For instance when introducing Dependency Injection into legacy applications you will have to move in small steps. On of those temporary steps could be a solution like this. It's ugly, it's technical depth, but temporary (at least it should be). But if your application is already built up using DI, there is really no reason to do this.Graeme
L
1

As a side note, the lock is completely useless since you are locking access to a local variable "user" which will not change between the 2 "if (user == null)" lines.

Your intention is to lock access to the Context.Session[CURRENT_USER] element, so ..

            User user = (User)Context.Session[SessionKeys.CURRENT_USER];

            if (user == null)
            {
                lock (_lock)
                {
                    user = (User)Context.Session[SessionKeys.CURRENT_USER];
                    if (user == null)
                    {
                        user = _userBusiness.Find(CurrentUserId);
                        Context.Session[SessionKeys.CURRENT_USER] = user;
                    }
                }
            }
Liston answered 4/3, 2014 at 13:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.