In Ninject 2.0, how do I have both a general binding and a binding for a specific case?
Asked Answered
S

1

8

I have a situation where I want to dependency inject my user object, but also place the current user in the IoC container. I want the following lines to work:

kernel.Get<User>(); // Should return a new User()
kernel.Get<User>("Current"); // Should return the current user

One might think bindings like this would work:

Bind<User>().ToSelf();
Bind<User>().ToMethod(LoadCurrentUser).InRequestScope().Named("Current");

Of course, that gives:

Ninject.ActivationException: Error activating User
More than one matching bindings are available.
Activation path:
1) Request for User

Suggestions:
1) Ensure that you have defined a binding for User only once.

I understand the error since a Named binding does not restrict the application of that binding, so both bindings apply. It seems clear that I need to use the contextual bind with the .When*() methods but I can't come up with any way to do that. I feel like there should be when methods that detect whether a named instance is applied. Something like:

// Not valid Ninject syntax
Bind<User>().ToSelf().WhenUnnamedRequested();
Bind<User>().ToMethod(LoadCurrentUser).WhenNamedRequested().InRequestScope().Named("Current");

I can't find any place on the IRequest interface or it's properties that tells me the name requested. How do I do this?

Sukiyaki answered 9/9, 2010 at 14:54 Comment(0)
B
3

This question was answerd on the mailing list: http://groups.google.com/group/ninject/browse_thread/thread/cd95847dc4dcfc9d?hl=en


If you are accessing the user by calling Get on the kernel (which I hope you do not) then give the first binding a name as well and access User always by name. Actually, there is a way to get an instance from the binding without a name. But because I heartily recommend not to do this, I do not show how to to this here. If you still want to do it this way I'll tell you later how this would work.

If you are doing it the better and prefered way and inject the user to the objects that require it as dependency there are two options:

  1. The easier one: Give the first binding a name and add a named attribute to the parameters e.g. ctor([Named("NewUser") IUser newUser, [Named("Current")] IUser currentUser)
  2. Or the prefered way to keep the implementation classes free of the IoC framework: Specify custom attributes and add them to the parameters e.g. ctor([NewUser] IUser newUser, [CurrentUser]IUser currentUser). Change the Bindings to:

    Bind<User>().ToSelf()
                .WhenTargetHas<NewUserAttribute>();
    Bind<User>().ToMethod(LoadCurrentUser)
                .InRequestScope()
                .WhenTargetHas<CurrentUserAttribute>();
    
Bobbette answered 29/10, 2010 at 11:33 Comment(1)
Sorry for the long delay in response, I can't do either of these because when a new user is being requested, that is happening through NHibernate. So I can't add a name or an attribute to that. I could in the cases where I want the current user, but then the new user binding would still apply.Sukiyaki

© 2022 - 2024 — McMap. All rights reserved.