diff --git a/src/Microsoft.AspNet.Hosting.Server.Abstractions/IHttpApplication.cs b/src/Microsoft.AspNet.Hosting.Server.Abstractions/IHttpApplication.cs
new file mode 100644
index 0000000000..07cbe53f82
--- /dev/null
+++ b/src/Microsoft.AspNet.Hosting.Server.Abstractions/IHttpApplication.cs
@@ -0,0 +1,35 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Http.Features;
+
+namespace Microsoft.AspNet.Hosting.Server
+{
+ ///
+ /// Represents an HttpApplication.
+ ///
+ public interface IHttpApplication
+ {
+ ///
+ /// Create a TContext given a collection of HTTP features.
+ ///
+ /// A collection of HTTP features to be used for creating the TContext.
+ /// The created TContext.
+ TContext CreateContext(IFeatureCollection contextFeatures);
+
+ ///
+ /// Asynchronously processes an TContext.
+ ///
+ /// The TContext that the operation will process.
+ Task ProcessRequestAsync(TContext context);
+
+ ///
+ /// Dispose a given TContext.
+ ///
+ /// The TContext to be disposed.
+ /// The Exception thrown when processing did not complete successfully, otherwise null.
+ void DisposeContext(TContext context, Exception exception);
+ }
+}
diff --git a/src/Microsoft.AspNet.Hosting.Server.Abstractions/IServer.cs b/src/Microsoft.AspNet.Hosting.Server.Abstractions/IServer.cs
index c6909990d0..cc1a88d519 100644
--- a/src/Microsoft.AspNet.Hosting.Server.Abstractions/IServer.cs
+++ b/src/Microsoft.AspNet.Hosting.Server.Abstractions/IServer.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
namespace Microsoft.AspNet.Hosting.Server
@@ -18,9 +17,9 @@ namespace Microsoft.AspNet.Hosting.Server
IFeatureCollection Features { get; }
///
- /// Start the server with the given function that processes an HTTP request.
+ /// Start the server with an HttpApplication.
///
- /// A function that processes an HTTP request.
- void Start(RequestDelegate requestDelegate);
+ /// An instance of .
+ void Start(IHttpApplication application);
}
}
diff --git a/src/Microsoft.AspNet.Hosting/Internal/HostingApplication.cs b/src/Microsoft.AspNet.Hosting/Internal/HostingApplication.cs
new file mode 100644
index 0000000000..c5b74dca72
--- /dev/null
+++ b/src/Microsoft.AspNet.Hosting/Internal/HostingApplication.cs
@@ -0,0 +1,91 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Diagnostics;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Hosting.Server;
+using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Http.Features;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNet.Hosting.Internal
+{
+ public class HostingApplication : IHttpApplication
+ {
+ private readonly RequestDelegate _application;
+ private readonly ILogger _logger;
+ private readonly DiagnosticSource _diagnosticSource;
+ private readonly IHttpContextFactory _httpContextFactory;
+
+ public HostingApplication(
+ RequestDelegate application,
+ ILogger logger,
+ DiagnosticSource diagnosticSource,
+ IHttpContextFactory httpContextFactory)
+ {
+ _application = application;
+ _logger = logger;
+ _diagnosticSource = diagnosticSource;
+ _httpContextFactory = httpContextFactory;
+ }
+
+ public Context CreateContext(IFeatureCollection contextFeatures)
+ {
+ var httpContext = _httpContextFactory.Create(contextFeatures);
+ var startTick = Environment.TickCount;
+
+ var scope = _logger.RequestScope(httpContext);
+ _logger.RequestStarting(httpContext);
+ if (_diagnosticSource.IsEnabled("Microsoft.AspNet.Hosting.BeginRequest"))
+ {
+ _diagnosticSource.Write("Microsoft.AspNet.Hosting.BeginRequest", new { httpContext = httpContext, tickCount = startTick });
+ }
+
+ return new Context
+ {
+ HttpContext = httpContext,
+ Scope = scope,
+ StartTick = startTick,
+ };
+ }
+
+ public void DisposeContext(Context context, Exception exception)
+ {
+ var httpContext = context.HttpContext;
+ var currentTick = Environment.TickCount;
+ _logger.RequestFinished(httpContext, context.StartTick, currentTick);
+
+ if (exception == null)
+ {
+ if (_diagnosticSource.IsEnabled("Microsoft.AspNet.Hosting.EndRequest"))
+ {
+ _diagnosticSource.Write("Microsoft.AspNet.Hosting.EndRequest", new { httpContext = httpContext, tickCount = currentTick });
+ }
+ }
+ else
+ {
+ if (_diagnosticSource.IsEnabled("Microsoft.AspNet.Hosting.UnhandledException"))
+ {
+ _diagnosticSource.Write("Microsoft.AspNet.Hosting.UnhandledException", new { httpContext = httpContext, tickCount = currentTick, exception = exception });
+ }
+ }
+
+ context.Scope.Dispose();
+
+ _httpContextFactory.Dispose(httpContext);
+ }
+
+ public async Task ProcessRequestAsync(Context context)
+ {
+ await _application(context.HttpContext);
+ }
+
+ public struct Context
+ {
+ public HttpContext HttpContext { get; set; }
+ public IDisposable Scope { get; set; }
+ public int StartTick { get; set; }
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs
index 4a796b6e6f..2d232995ee 100644
--- a/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs
+++ b/src/Microsoft.AspNet.Hosting/Internal/HostingEngine.cs
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
-using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting.Builder;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Hosting.Startup;
@@ -90,45 +89,11 @@ namespace Microsoft.AspNet.Hosting.Internal
var logger = _applicationServices.GetRequiredService>();
var diagnosticSource = _applicationServices.GetRequiredService();
+ var httpContextFactory = _applicationServices.GetRequiredService();
logger.Starting();
- Server.Start(
- async httpContext =>
- {
- if (diagnosticSource.IsEnabled("Microsoft.AspNet.Hosting.BeginRequest"))
- {
- diagnosticSource.Write("Microsoft.AspNet.Hosting.BeginRequest", new { httpContext = httpContext });
- }
-
- using (logger.RequestScope(httpContext))
- {
- int startTime = 0;
- try
- {
- logger.RequestStarting(httpContext);
-
- startTime = Environment.TickCount;
- await application(httpContext);
-
- logger.RequestFinished(httpContext, startTime);
- }
- catch (Exception ex)
- {
- logger.RequestFailed(httpContext, startTime);
-
- if (diagnosticSource.IsEnabled("Microsoft.AspNet.Hosting.UnhandledException"))
- {
- diagnosticSource.Write("Microsoft.AspNet.Hosting.UnhandledException", new { httpContext = httpContext, exception = ex });
- }
- throw;
- }
- }
- if (diagnosticSource.IsEnabled("Microsoft.AspNet.Hosting.EndRequest"))
- {
- diagnosticSource.Write("Microsoft.AspNet.Hosting.EndRequest", new { httpContext = httpContext });
- }
- });
+ Server.Start(new HostingApplication(application, logger, diagnosticSource, httpContextFactory));
_applicationLifetime.NotifyStarted();
logger.Started();
diff --git a/src/Microsoft.AspNet.Hosting/Internal/HostingLoggerExtensions.cs b/src/Microsoft.AspNet.Hosting/Internal/HostingLoggerExtensions.cs
index 67f9f114ff..3730736d0b 100644
--- a/src/Microsoft.AspNet.Hosting/Internal/HostingLoggerExtensions.cs
+++ b/src/Microsoft.AspNet.Hosting/Internal/HostingLoggerExtensions.cs
@@ -30,11 +30,14 @@ namespace Microsoft.AspNet.Hosting.Internal
}
}
- public static void RequestFinished(this ILogger logger, HttpContext httpContext, int startTimeInTicks)
+ public static void RequestFinished(this ILogger logger, HttpContext httpContext, int startTimeInTicks, int currentTick)
{
if (logger.IsEnabled(LogLevel.Information))
{
- var elapsed = new TimeSpan(TicksPerMillisecond * (Environment.TickCount - startTimeInTicks));
+ var elapsed = new TimeSpan(TicksPerMillisecond * (currentTick < startTimeInTicks ?
+ (int.MaxValue - startTimeInTicks) + (currentTick - int.MinValue) :
+ currentTick - startTimeInTicks));
+
logger.Log(
logLevel: LogLevel.Information,
eventId: LoggerEventIds.RequestFinished,
@@ -44,20 +47,6 @@ namespace Microsoft.AspNet.Hosting.Internal
}
}
- public static void RequestFailed(this ILogger logger, HttpContext httpContext, int startTimeInTicks)
- {
- if (logger.IsEnabled(LogLevel.Information))
- {
- var elapsed = new TimeSpan(TicksPerMillisecond * (Environment.TickCount - startTimeInTicks));
- logger.Log(
- logLevel: LogLevel.Information,
- eventId: LoggerEventIds.RequestFailed,
- state: new HostingRequestFailed(httpContext, elapsed),
- exception: null,
- formatter: HostingRequestFailed.Callback);
- }
- }
-
public static void ApplicationError(this ILogger logger, Exception exception)
{
logger.LogError(
@@ -221,48 +210,6 @@ namespace Microsoft.AspNet.Hosting.Internal
return _cachedGetValues;
}
}
-
- private class HostingRequestFailed
- {
- internal static readonly Func