2

I am working on an ASP.Net MVC project that authenticates using ADFS and uses SimpleInjector as the IoC container. The service layer of the application is in a different project and services are injected in the controller constructors on startup. One of these services is a user service which I would like to use to get user info etc. from my data layer.

I have a custom Principal (inherited from the ClaimsPrincipal) that I would like to use this user service on and store user information in. The issue I face is I'm not sure how to "glue" the user service to the custom principal.

I've tried getting an instance of the user service after each authentication and injecting it into the identity but I get an error saying the container doesn't contain and instance of the service. My code is below:

Application_Start()

    protected void Application_Start()
    {
        // Register the IoC container
        InjectorConfig.RegisterDependencies(_container);

        // RouteConfig etc...
    }

InjectorConfig

public class InjectorConfig
{
    /// <summary>
    /// Create the IoC container and register all dependencies
    /// </summary>
    public static void RegisterDependencies(Container container)
    {
        // Create the IoC container
        //var container = new Container();

        // Get the assembly that houses the services
        var serviceAssembly = typeof (UserService).Assembly;

        // Interate through the assembly and find all the services 
        var registrations = (
            from type in serviceAssembly.GetExportedTypes()
            where type.Namespace == "MyApp.Services"
            where type.GetInterfaces().Any()
            select new
            {
                Service = type.GetInterfaces().Single(), 
                Implementation = type,
            });

        // Register each of the services
        foreach (var registration in registrations)
        {
            container.Register(registration.Service, registration.Implementation, Lifestyle.Transient);
        }

        // Verify the container and set the MVC dependency resolver
        container.Verify();
        DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
    }
}

My Custom ClaimsPrincipal

public class MyCustomPrincipal : ClaimsPrincipal
{
    private readonly IUserService _userService;

    public MyCustomPrincipal(IIdentity identity, IUserService userService)
        :base(identity)
    {
        this._userService = userService;
    }

    public override bool IsInRole(string role)
    {
        return this._userService.IsInRole(this.Identity.GetUserId(), role);
    }
}

My User Service (In different assembly)

public class UserService : IUserService
{
    public bool IsInRole(string currentUserId, string roleName)
    {
        // Check roles here
        return true;
    }
}

Application_PostAuthenticateRequest()

This is where the error occurs. No instance available

    protected void Application_PostAuthenticateRequest()
    {
        var currentUser = ClaimsPrincipal.Current.Identity;

        // This is where the error occurs. No instance available
        var userService = this._container.GetInstance<IUserService>();
        HttpContext.Current.User = new MyCustomPrincipal(currentUser, userService);
    }

I'm a bit of an IoC rookie, so there's probably a simple solution to it but I'm bashing my head against a wall (figuratively speaking) trying to work this one out.

Any help you could provide would be greatly appreciated!

Updated Here is the exception detail

SimpleInjector.ActivationException was unhandled by user code
  HResult=-2146233088
  Message=No registration for type IUserService could be found.
  Source=SimpleInjector
  StackTrace:
       at SimpleInjector.Container.ThrowMissingInstanceProducerException(Type serviceType)
       at SimpleInjector.Container.GetInstanceFromProducer(InstanceProducer instanceProducer, Type serviceType)
       at SimpleInjector.Container.GetInstanceForType[TService]()
       at SimpleInjector.Container.GetInstance[TService]()
       at MyWebApp.Web.MvcApplication.Application_PostAuthenticateRequest() in c:\Projects\MyWebApp\Client\\MyWebApp.Web\Global.asax.cs:line 46
  InnerException: 
Steven
  • 166,672
  • 24
  • 332
  • 435
Andrew
  • 23
  • 6
  • What exactly is the error you are getting? Can you post the complete exception, message and stack trace? – Steven Feb 12 '15 at 08:08
  • Hi @Steven, Thanks for replying. I have updated the question with the stack trace. – Andrew Feb 13 '15 at 04:21
  • Well, the message is clear. Are you sure this the same container? You can view the container's registrations in the debugger. Perhaps your RegisterDependencies isn't called or you create a new container afteer that call. – Steven Feb 13 '15 at 05:48

1 Answers1

1

There are 5 possible reasons I can think of why this happens:

  1. UserService class does not implement IUserService.
  2. The UserService class is not located in the namespace "MyApp.Services".
  3. The class is internal.
  4. You accidentally create a second (empty) container.
  5. The PostAuthentication method is called before RegisterDependencies is called.
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thanks for your help @Steven. I ended up resolving the issue with `var userService = DependencyResolver.Current.GetService();` – Andrew Feb 15 '15 at 22:37
  • @Andrew If that solves the problem, than there MUST be a second container instance. You should really find why that happens, because it might be causing more trouble along the way. – Steven Feb 16 '15 at 00:31