Skip to content
This repository has been archived by the owner on Sep 18, 2021. It is now read-only.

Getting access to the Autofac Container #828

Closed
jkrlin opened this issue Jan 27, 2015 · 5 comments
Closed

Getting access to the Autofac Container #828

jkrlin opened this issue Jan 27, 2015 · 5 comments
Labels

Comments

@jkrlin
Copy link

jkrlin commented Jan 27, 2015

Is there any way I can get to the Autofac container when IdentityServer is coming up? I have an existing robust back-end stack I'm leveraging which already uses Autofac and being able to just reuse the registrations would save me a lot of time rather than having to implement everything in your DI wrapper which is nowhere near as robust.

I just need access to the application container via a static or preferably something on the IdentityServerServiceFactory that would expose it so that I can update it with my registrations. Looking at the source code it seems you guys did a really good job at hiding it, excessively so IMO.

@brockallen
Copy link
Member

This question has been asked many times -- please search the archives.

@jkrlin
Copy link
Author

jkrlin commented Jan 28, 2015

So from what I can gather as a design decision you do not expose the internals of IdentityServer so getting access to it's container is a no go. OK, I can respect that. After looking at some of the other comment I went with the route of implementing my own container. The tricky part was to get it integrated into the OWIN message lifetime. It might be helpful if you could provide something similar in the DI documentation but in the mean time for the benefit of others I'll document my solution here:

...
using Autofac;
using Autofac.Integration.Mvc;
using Owin;

        public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Map("/identity", idsrvApp =>
            {
                var autofacResolver = StsConfiguration.Configure(idsrvApp);

                var factory = InMemoryFactory.Create(
                    clients: Clients.Get(),
                    scopes: Scopes.Get());

                factory.UserService = new Registration<IUserService>(resolver =>
                {
                    var scope = (IComponentContext)autofacResolver.RequestLifetimeScope;

                    var userService = scope.Resolve<IUserService>();
                    return userService;
                });

                var options = new IdentityServerOptions
                {
                    SiteName = "My STS",
                    SigningCertificate = Certificate.Get(),

                    Factory = factory
                };

                idsrvApp.UseIdentityServer(options);
            });
        }
    }

    public static class StsConfiguration
    {
        public static AutofacDependencyResolver Configure(IAppBuilder app)
        {
            var container = ContainerInstanceProvider.GetContainerInstance();

            // this has to be done before registering my custom middleware 
            app.UseAutofacMiddleware(container);
            var autofacResolver = new AutofacDependencyResolver(container);

            app.Use<AutofacRequestContextMiddleware>(autofacResolver);

            return autofacResolver;
        }
    }

    internal class AutofacRequestContextMiddleware
    {
        readonly private Func<IDictionary<string, object>, Task> _next;
        readonly private AutofacDependencyResolver _resolver;

        public AutofacRequestContextMiddleware(Func<IDictionary<string, object>, Task> next, AutofacDependencyResolver resolver)
        {
            _next = next;
            _resolver = resolver;
        }

        public async Task Invoke(IDictionary<string, object> env)
        {
            var scope = (IComponentContext) _resolver.RequestLifetimeScope;
            var myService = scope.Resolve<MyService>();

            myService.Process("Begin Request");

            await _next(env);

            myService.Process("End Request");
        }
    }

@brockallen
Copy link
Member

I guess what I'm confused about is why you're so tightly integrating IdentityServer in with another application (the other one that has its own DI system).

@jkrlin
Copy link
Author

jkrlin commented Jan 28, 2015

The code I'm integrating with in question has a UI/Host component and a back end business component. The host can be WebApi, MVC, IdentityServer, NServiceBus etc and for any given host entry point it can leverage the same business logic which heavily uses IOC interception for logging and aspects and also nhibernate where session management is tied to the IOC lifetime. Also the existing app has it's own login page with logic for login validation, reset password, forgot password etc. I'm in the process of moving this login functionality to IdentityServer and therefore want to leverage the same back end stack. Rather than having to tweak everything to work with another IOC registration system it's much easier to just provide the existing autofac registrations and set the lifetime properly and the rest works without change. The alternative would be a lot of work.

@brockallen
Copy link
Member

Much like my answer here: #819 (comment)

We've not designed IdentityServer to intermingle with other application frameworks. If you can get it to work, then great, but it's not intentional on our part and we don't plan on guaranteeing that it will work in the future. Building a token service is complex enough -- supporting what you're asking for is beyond our bandwidth. Sorry.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants