|
2 | 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
3 | 3 |
|
4 | 4 | using System;
|
| 5 | +using System.Collections.Generic; |
5 | 6 | using System.Data.Common;
|
6 | 7 | using System.Data.SqlClient;
|
7 | 8 | using Benchmarks.Data;
|
8 | 9 | using Microsoft.AspNetCore.Builder;
|
9 | 10 | using Microsoft.AspNetCore.Hosting;
|
10 | 11 | using Microsoft.AspNetCore.Http;
|
| 12 | +using Microsoft.AspNetCore.Http.Features; |
| 13 | +using Microsoft.AspNetCore.Http.Internal; |
11 | 14 | using Microsoft.EntityFrameworkCore;
|
12 | 15 | using Microsoft.Extensions.Configuration;
|
13 | 16 | using Microsoft.Extensions.DependencyInjection;
|
@@ -43,6 +46,7 @@ public void ConfigureServices(IServiceCollection services)
|
43 | 46 | // No scenarios covered by the benchmarks require the HttpContextAccessor so we're replacing it with a
|
44 | 47 | // no-op version to avoid the cost.
|
45 | 48 | services.AddSingleton(typeof(IHttpContextAccessor), typeof(InertHttpContextAccessor));
|
| 49 | + services.AddSingleton(typeof(IHttpContextFactory), typeof(PooledContextFactory)); |
46 | 50 |
|
47 | 51 | if (Scenarios.Any("Db"))
|
48 | 52 | {
|
@@ -161,5 +165,69 @@ public HttpContext HttpContext
|
161 | 165 | set { return; }
|
162 | 166 | }
|
163 | 167 | }
|
| 168 | + |
| 169 | + public class PooledContextFactory : IHttpContextFactory |
| 170 | + { |
| 171 | + private IHttpContextAccessor _httpContextAccessor; |
| 172 | + |
| 173 | + [ThreadStatic] |
| 174 | + static Queue<DefaultHttpContext> _contextPool; |
| 175 | + |
| 176 | + public PooledContextFactory() : this(httpContextAccessor: null) |
| 177 | + { |
| 178 | + } |
| 179 | + |
| 180 | + public PooledContextFactory(IHttpContextAccessor httpContextAccessor) |
| 181 | + { |
| 182 | + _httpContextAccessor = httpContextAccessor; |
| 183 | + } |
| 184 | + |
| 185 | + private Queue<DefaultHttpContext> ContextPool |
| 186 | + { |
| 187 | + get |
| 188 | + { |
| 189 | + if (_contextPool == null) |
| 190 | + { |
| 191 | + _contextPool = new Queue<DefaultHttpContext>(16); |
| 192 | + } |
| 193 | + |
| 194 | + return _contextPool; |
| 195 | + } |
| 196 | + } |
| 197 | + |
| 198 | + public HttpContext Create(IFeatureCollection featureCollection) |
| 199 | + { |
| 200 | + var contextPool = ContextPool; |
| 201 | + if (contextPool.Count > 0) |
| 202 | + { |
| 203 | + var context = contextPool.Dequeue(); |
| 204 | + context.Initialize(featureCollection); |
| 205 | + return context; |
| 206 | + } |
| 207 | + |
| 208 | + return new DefaultHttpContext(featureCollection); |
| 209 | + } |
| 210 | + |
| 211 | + public void Dispose(HttpContext httpContext) |
| 212 | + { |
| 213 | + if (_httpContextAccessor != null) |
| 214 | + { |
| 215 | + _httpContextAccessor.HttpContext = null; |
| 216 | + } |
| 217 | + |
| 218 | + var context = httpContext as DefaultHttpContext; |
| 219 | + |
| 220 | + if (context != null) |
| 221 | + { |
| 222 | + context.Uninitialize(); |
| 223 | + |
| 224 | + var contextPool = ContextPool; |
| 225 | + if (contextPool.Count < 16) |
| 226 | + { |
| 227 | + contextPool.Enqueue(context); |
| 228 | + } |
| 229 | + } |
| 230 | + } |
| 231 | + } |
164 | 232 | }
|
165 | 233 | }
|
0 commit comments