| File: Internal\HostingApplication.cs | Web Access |
| Project: src\aspnetcore\src\Hosting\Hosting\src\Microsoft.AspNetCore.Hosting.csproj (Microsoft.AspNetCore.Hosting) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Abstractions; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Hosting; internal sealed class HostingApplication : IHttpApplication<HostingApplication.Context> { private readonly RequestDelegate _application; private readonly IHttpContextFactory? _httpContextFactory; private readonly DefaultHttpContextFactory? _defaultHttpContextFactory; private readonly HostingApplicationDiagnostics _diagnostics; // Internal for testing purposes only internal bool SuppressActivityOpenTelemetryData { get => _diagnostics.SuppressActivityOpenTelemetryData; set => _diagnostics.SuppressActivityOpenTelemetryData = value; } public HostingApplication( RequestDelegate application, ILogger logger, DiagnosticListener diagnosticSource, ActivitySource activitySource, DistributedContextPropagator propagator, IHttpContextFactory httpContextFactory, HostingEventSource eventSource, HostingMetrics metrics) { _application = application; _diagnostics = new HostingApplicationDiagnostics(logger, diagnosticSource, activitySource, propagator, eventSource, metrics); if (httpContextFactory is DefaultHttpContextFactory factory) { _defaultHttpContextFactory = factory; } else { _httpContextFactory = httpContextFactory; } } // Set up the request public Context CreateContext(IFeatureCollection contextFeatures) { Context? hostContext; if (contextFeatures is IHostContextContainer<Context> container) { hostContext = container.HostContext; if (hostContext is null) { hostContext = new Context(); container.HostContext = hostContext; } } else { // Server doesn't support pooling, so create a new Context hostContext = new Context(); } HttpContext httpContext; if (_defaultHttpContextFactory != null) { var defaultHttpContext = (DefaultHttpContext?)hostContext.HttpContext; if (defaultHttpContext is null) { httpContext = _defaultHttpContextFactory.Create(contextFeatures); hostContext.HttpContext = httpContext; } else { _defaultHttpContextFactory.Initialize(defaultHttpContext, contextFeatures); httpContext = defaultHttpContext; } } else { httpContext = _httpContextFactory!.Create(contextFeatures); hostContext.HttpContext = httpContext; } _diagnostics.BeginRequest(httpContext, hostContext); return hostContext; } // Execute the request public Task ProcessRequestAsync(Context context) { return _application(context.HttpContext!); } // Clean up the request public void DisposeContext(Context context, Exception? exception) { var httpContext = context.HttpContext!; _diagnostics.RequestEnd(httpContext, exception, context); if (_defaultHttpContextFactory != null) { _defaultHttpContextFactory.Dispose((DefaultHttpContext)httpContext); if (_defaultHttpContextFactory.HttpContextAccessor != null) { // Clear the HttpContext if the accessor was used. It's likely that the lifetime extends // past the end of the http request and we want to avoid changing the reference from under // consumers. context.HttpContext = null; } } else { _httpContextFactory!.Dispose(httpContext); } _diagnostics.ContextDisposed(context); // Reset the context as it may be pooled context.Reset(); } internal sealed class Context { public HttpContext? HttpContext { get; set; } public IDisposable? Scope { get; set; } public Activity? Activity { get => HttpActivityFeature?.Activity; set { if (HttpActivityFeature is null) { if (value != null) { HttpActivityFeature = new HttpActivityFeature(value); } } else { HttpActivityFeature.Activity = value!; } } } internal HostingRequestStartingLog? StartLog { get; set; } public long StartTimestamp { get; set; } internal bool HasDiagnosticListener { get; set; } public bool MetricsEnabled { get; set; } public bool EventLogEnabled { get; set; } internal HttpActivityFeature? HttpActivityFeature; internal HttpMetricsTagsFeature? MetricsTagsFeature; public void Reset() { // Not resetting HttpContext here as we pool it on the Context Scope = null; Activity = null; StartLog = null; StartTimestamp = 0; HasDiagnosticListener = false; MetricsEnabled = false; EventLogEnabled = false; MetricsTagsFeature?.Reset(); } } }