-
Notifications
You must be signed in to change notification settings - Fork 116
/
ParallelApplicationPipelinesExtensions.cs
110 lines (92 loc) · 4.44 KB
/
ParallelApplicationPipelinesExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Builder;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace WebApiContrib.Core
{
public static class ParallelApplicationPipelinesExtensions
{
/// <summary>
/// Sets up an application branch with an isolated DI container
/// </summary>
/// <param name="app">Application builder</param>
/// <param name="path">Relative path for the application branch</param>
/// <param name="servicesConfiguration">DI container configuration</param>
/// <param name="appBuilderConfiguration">Application pipeline configuration for the created branch</param>
public static IApplicationBuilder UseBranchWithServices(this IApplicationBuilder app, PathString path,
Action<IServiceCollection> servicesConfiguration, Action<IApplicationBuilder> appBuilderConfiguration)
{
return app.UseBranchWithServices(new[] { path }, servicesConfiguration, appBuilderConfiguration);
}
/// <summary>
/// Sets up an application branch with an isolated DI container with several routes (entry points)
/// </summary>
/// <param name="app">Application builder</param>
/// <param name="paths">Relative paths for the application branch</param>
/// <param name="servicesConfiguration">DI container configuration</param>
/// <param name="appBuilderConfiguration">Application pipeline configuration for the created branch</param>
public static IApplicationBuilder UseBranchWithServices(this IApplicationBuilder app, IEnumerable<PathString> paths,
Action<IServiceCollection> servicesConfiguration, Action<IApplicationBuilder> appBuilderConfiguration)
{
var webHost = new WebHostBuilder().
ConfigureServices(s => {
s.AddSingleton<IServer, DummyServer>();
}).
ConfigureServices(servicesConfiguration).
UseStartup<EmptyStartup>().
Build();
var serviceProvider = webHost.Services;
var serverFeatures = webHost.ServerFeatures;
var appBuilderFactory = serviceProvider.GetRequiredService<IApplicationBuilderFactory>();
var branchBuilder = appBuilderFactory.CreateBuilder(serverFeatures);
var factory = serviceProvider.GetRequiredService<IServiceScopeFactory>();
branchBuilder.Use(async (context, next) =>
{
var oldServiceProvider = context.RequestServices;
using (var scope = factory.CreateScope())
{
context.RequestServices = scope.ServiceProvider;
var httpContextAccessor = context.RequestServices
.GetService<IHttpContextAccessor>();
if (httpContextAccessor != null)
httpContextAccessor.HttpContext = context;
await next();
}
context.RequestServices = oldServiceProvider;
});
appBuilderConfiguration(branchBuilder);
var branchDelegate = branchBuilder.Build();
foreach (var path in paths)
{
app.Map(path, builder =>
{
builder.Use(async (context, next) =>
{
await branchDelegate(context);
});
});
}
return app;
}
private class EmptyStartup
{
public void ConfigureServices(IServiceCollection services) {}
public void Configure(IApplicationBuilder app) {}
}
private class DummyServer : IServer
{
public IFeatureCollection Features { get; } = new FeatureCollection();
public void Dispose() {}
public Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken) => Task.CompletedTask;
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}
}