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();
}
}