4

I have this interface:

public interface IUserProfileService
{
    // stuff
}

Implemented by:

public class UserProfileService : IUserProfileService
{
    private readonly string m_userName;

    public UserProfileService(string userName)
    {
        m_userName = userName;
    }
}

I need this injected into a controller like this:

public class ProfilesController : BaseController
{
    private readonly IUserProfileService m_profileService;

    public ProfilesController(IUserProfileService profileService)
    {
        m_profileService = profileService;
    }
}

I don't know how I can register this interface and its implementation into Ninject container so that userName param is passed in when the Ninject inits an instance of this service.

Any ideas how I can achieve this?

mskfisher
  • 3,028
  • 3
  • 31
  • 47
kind_robot
  • 2,191
  • 3
  • 29
  • 44
  • 3
    I'm in general agreement with what Mike described. For a bit more detail and explanation I'd recommend reading Ruben Bartelink's answer here: http://stackoverflow.com/questions/2227548/creating-an-instance-using-ninject-with-additional-parameters-in-the-constructor. This is a very thorough answer for what you're looking to achieve. – Khepri Jun 12 '11 at 16:33
  • Can someone explain why they down-voted this question? – ryber Nov 02 '12 at 23:55

3 Answers3

5

The technical ninject answer is to use constructor arguments like so:

Bind<IUserProfileService>().To<UserProfileService>().WithConstructorArgument("userName", "karl");

Of course you need to figure out where "karl" comes from. It really depends on your app. Maybe its a web app and it's on the HttpContex? I don't know. If it gets rather complicated then you might want to write a IProvider rather than doing a regular binding.

ryber
  • 4,399
  • 1
  • 23
  • 46
3

One alternative is to inject a factory and create your dependency using Create(string userName).

public class UserProfileServiceFactory
{
    public IUserProfileService Create(string userName)
    {
        return new UserProfileService(userName);
    }
}

It might seem off to have to create another class but the benefits mostly comes when UserProfileService takes in additional dependencies.

Mike
  • 4,137
  • 3
  • 30
  • 47
  • Would the ProfilesController constructor then take a UserProfileServiceFactory and a userName? – JDawg Jan 23 '15 at 22:07
3

The trick is to not inject the username in that class. You call this class a service so it would probably work transparantly with multiple users. I see two solutions:

  1. Inject an abstraction into the service that represents the current user:

    public class UserProfileService : IUserProfileService
    {
        private readonly IPrincipal currentUser;
    
        public UserProfileService(IPrincipal currentUser)
        {
            this.currentUser = currentUser;
        }
    
        void IUserProfileService.SomeOperation()
        {
            var user = this.currentUser;
    
            // Do some nice stuff with user
        }
    }
    
  2. Create an implementation that is specific to the technology you are working with, for instance:

    public class AspNetUserProfileService : IUserProfileService
    {
        public AspNetUserProfileService()
        {
        }
    
        void IUserProfileService.SomeOperation()
        {
            var user = this.CurrentUser;
    
            // Do some nice stuff with user
        }
    
        private IPrincipal CurrentUser
        {
            get { return HttpContext.Current.User; }
        }
    }
    

If you can, go with option one.

Steven
  • 151,500
  • 20
  • 287
  • 393
  • On option one, assuming IPrincipal's concrete constructor takes a userName argument, how does this option help? – JDawg Jan 23 '15 at 21:55