Example #1
0
        /// <summary>
        /// Creates a new isolated application builder which gets its own <see cref="ServiceCollection"/>, which only
        /// has the default services registered. It will not share the <see cref="ServiceCollection"/> from the
        /// originating app.
        /// </summary>
        /// <param name="app">The application builder to create the isolated app from.</param>
        /// <param name="configuration">The branch of the isolated app.</param>
        /// <param name="registration">A method to configure the newly created service collection.</param>
        /// <returns>The new pipeline with the isolated application integrated.</returns>
        public static IApplicationBuilder Isolate(
            this IApplicationBuilder app,
            Action <IApplicationBuilder> configuration,
            Func <IServiceCollection, IServiceProvider> registration)
        {
            var services = CreateDefaultServiceCollection(app.ApplicationServices);
            var provider = registration(services);

            var builder = new ApplicationBuilder(null);

            builder.ApplicationServices = provider;

            builder.Use(async(context, next) =>
            {
                var factory = provider.GetRequiredService <IServiceScopeFactory>();

                // Store the original request services in the current ASP.NET context.
                context.Items[typeof(IServiceProvider)] = context.RequestServices;

                try
                {
                    using (var scope = factory.CreateScope())
                    {
                        context.RequestServices = scope.ServiceProvider;

                        await next();
                    }
                }

                finally
                {
                    context.RequestServices = null;
                }
            });

            configuration(builder);

            return(app.Use(next =>
            {
                // Run the rest of the pipeline in the original context,
                // with the services defined by the parent application builder.
                builder.Run(async context =>
                {
                    var factory = app.ApplicationServices.GetRequiredService <IServiceScopeFactory>();

                    try
                    {
                        using (var scope = factory.CreateScope())
                        {
                            context.RequestServices = scope.ServiceProvider;

                            await next(context);
                        }
                    }

                    finally
                    {
                        context.RequestServices = null;
                    }
                });

                var branch = builder.Build();

                return context => branch(context);
            }));
        }