using Microsoft.AspNetCore.Http.Features; namespace Microsoft.AspNetCore.Http; /// <summary> /// Provides methods to create and dispose of <see cref="HttpContext"/> instances. /// </summary> public interface IHttpContextFactory { /// <summary> /// Creates an <see cref="HttpContext"/> instance for the specified set of HTTP features. /// </summary> /// <param name="featureCollection">The collection of HTTP features to set on the created instance.</param> /// <returns>The <see cref="HttpContext"/> instance.</returns> HttpContext Create(IFeatureCollection featureCollection); /// <summary> /// Releases resources held by the <see cref="HttpContext"/>. /// </summary> /// <param name="httpContext">The <see cref="HttpContext"/> to dispose.</param> void Dispose(HttpContext httpContext); }
#nullable enable using System.Diagnostics; using System.Runtime.CompilerServices; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; namespace Microsoft.AspNetCore.Http; /// <summary> /// A factory for creating <see cref="HttpContext" /> instances. /// </summary> public class DefaultHttpContextFactory : IHttpContextFactory { private readonly IHttpContextAccessor? _httpContextAccessor; private readonly FormOptions _formOptions; private readonly IServiceScopeFactory _serviceScopeFactory; // This takes the IServiceProvider because it needs to support an ever expanding // set of services that flow down into HttpContext features /// <summary> /// Creates a factory for creating <see cref="HttpContext" /> instances. /// </summary> /// <param name="serviceProvider">The <see cref="IServiceProvider"/> to be used when retrieving services.</param> public DefaultHttpContextFactory(IServiceProvider serviceProvider) { // May be null _httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>(); _formOptions = serviceProvider.GetRequiredService<IOptions<FormOptions>>().Value; _serviceScopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>(); } internal IHttpContextAccessor? HttpContextAccessor => _httpContextAccessor; /// <summary> /// Create an <see cref="HttpContext"/> instance given an <paramref name="featureCollection" />. /// </summary> /// <param name="featureCollection"></param> /// <returns>An initialized <see cref="HttpContext"/> object.</returns> public HttpContext Create(IFeatureCollection featureCollection) { if (featureCollection is null) { throw new ArgumentNullException(nameof(featureCollection)); } var httpContext = new DefaultHttpContext(featureCollection); Initialize(httpContext); return httpContext; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void Initialize(DefaultHttpContext httpContext, IFeatureCollection featureCollection) { Debug.Assert(featureCollection != null); Debug.Assert(httpContext != null); httpContext.Initialize(featureCollection); Initialize(httpContext); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private DefaultHttpContext Initialize(DefaultHttpContext httpContext) { if (_httpContextAccessor != null) { _httpContextAccessor.HttpContext = httpContext; } httpContext.FormOptions = _formOptions; httpContext.ServiceScopeFactory = _serviceScopeFactory; return httpContext; } /// <summary> /// Clears the current <see cref="HttpContext" />. /// </summary> public void Dispose(HttpContext httpContext) { if (_httpContextAccessor != null) { _httpContextAccessor.HttpContext = null; } } internal void Dispose(DefaultHttpContext httpContext) { if (_httpContextAccessor != null) { _httpContextAccessor.HttpContext = null; } httpContext.Uninitialize(); } }