0

In order to access the underlying data source, I need to provide the current user credentials which I don't have beforehand.

So, in order to provide the data access layer with proper current user credentials, I have been suggested that my ConfigurationProvider would depend on an instance of ICurrentUser InSingletonScope() as per this answer.

The way I understand it, I shall make sure about authenticating the user, and bind my ICurrentUser afterwards, and binding the rest of my data access layer.

As the authentication occurs in my main MDI form, the only way I can see to achieve it, is to inject the Ninject kernel into the constructor of my MDI form.

My concern is about the fact that the way I see it, it would be necessary to depend on the Ninject kernel itself, which is absolutely out of the question, since this would then be, if I am not mistaken, just like using the ServiceLocator anti-pattern.

So, in this scenario, how to avoid the ServiceLocator anti-pattern?

Community
  • 1
  • 1
Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • Take a look at this http://stackoverflow.com/questions/9021766/multitenancy-with-fluent-nhibernate-and-ninject-one-database-per-tenant, describes a bit the same problem. But I think you're missing the point. You don't need IKernel on your authentication form. Access `CurrentUser.Instance` as a singleton and don't reference the `ServiceLocator`. But now you are coupled to a `static`. :) But again, you can get around this implementing an `ICurrentUserAcessor` and masking the static access inside! – cvbarros Apr 11 '14 at 21:02

1 Answers1

2

Will,

You don't need to have access to IResolutionRoot in your authentication form. Having configured. I've came up with a sample implementation that uses an IAuthenticationService injected into your form. After user input you can call SignIn() and it will change the current credentials instance.

From that point on, every time a class that requires a IDatabaseUserCredentials will receive this instance instead of the default instance.

I've also made the ConfigurationProvider receive a IConnectionStringProvider instead of a string. Check the complete gist for a full-working example.

public class AuthenticationService : IAuthenticationService
{
    public void SignIn(string dbInstance, string login, string password)
    {
        var user = new DatabaseUserCredentials(dbInstance, login, password);

        // A single point to manipulate your singleton instance
        DatabaseUserCredentials.Current = user;
    }
}

And the bindings:

public override void Load()
{
    Bind<Configuration>().ToProvider<ConfigurationProvider>();

    Bind<IAuthenticationService>().To<AuthenticationService>();

    Bind<IConnectionStringProvider>().To<ConnectionStringProvider>();

    //Use Current user if available. If not, use default credentials.
    Bind<IDatabaseUserCredentials>().ToMethod(c => DatabaseUserCredentials.Current ?? DatabaseUserCredentials.Default);
}
cvbarros
  • 1,684
  • 1
  • 12
  • 19
  • This sounds like it makes sense at all, my friend (if I may say so)! I shall give it a try on the beginning of next week, I provide you feedback with your solution. Sincerely, pretty much thank you for your assistance. I really, and I mean really, appreciate it. Thanks a lot. – Will Marcouiller Apr 12 '14 at 01:15