Reacting to new IServer and IHttpApplication design

This commit is contained in:
John Luo 2015-11-17 16:19:36 -08:00
parent 0c33cad343
commit 168f4770f4
17 changed files with 274 additions and 180 deletions

View File

@ -185,7 +185,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private Frame CreateFrame()
{
return new Frame(this, _remoteEndPoint, _localEndPoint, _filterContext?.PrepareRequest);
return FrameFactory(this, _remoteEndPoint, _localEndPoint, _filterContext?.PrepareRequest);
}
void IConnectionControl.Pause()

View File

@ -19,7 +19,7 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Server.Kestrel.Http
{
public partial class Frame : FrameContext, IFrameControl
public abstract partial class Frame : FrameContext, IFrameControl
{
private static readonly Encoding _ascii = Encoding.ASCII;
private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n");
@ -41,7 +41,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private readonly object _onStartingSync = new Object();
private readonly object _onCompletedSync = new Object();
private readonly FrameRequestHeaders _requestHeaders = new FrameRequestHeaders();
protected readonly FrameRequestHeaders _requestHeaders = new FrameRequestHeaders();
private readonly FrameResponseHeaders _responseHeaders = new FrameResponseHeaders();
private List<KeyValuePair<Func<object, Task>, object>> _onStarting;
@ -50,18 +50,18 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
private bool _requestProcessingStarted;
private Task _requestProcessingTask;
private volatile bool _requestProcessingStopping; // volatile, see: https://msdn.microsoft.com/en-us/library/x13ttww7.aspx
private volatile bool _requestAborted;
private CancellationTokenSource _abortedCts;
private CancellationToken? _manuallySetRequestAbortToken;
protected volatile bool _requestProcessingStopping; // volatile, see: https://msdn.microsoft.com/en-us/library/x13ttww7.aspx
protected volatile bool _requestAborted;
protected CancellationTokenSource _abortedCts;
protected CancellationToken? _manuallySetRequestAbortToken;
private FrameRequestStream _requestBody;
private FrameResponseStream _responseBody;
internal FrameRequestStream _requestBody;
internal FrameResponseStream _responseBody;
private bool _responseStarted;
private bool _keepAlive;
protected bool _responseStarted;
protected bool _keepAlive;
private bool _autoChunk;
private Exception _applicationException;
protected Exception _applicationException;
private HttpVersionType _httpVersion;
@ -306,119 +306,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
/// The resulting Task from this loop is preserved in a field which is used when the server needs
/// to drain and close all currently active connections.
/// </summary>
public async Task RequestProcessingAsync()
{
try
{
var terminated = false;
while (!terminated && !_requestProcessingStopping)
{
while (!terminated && !_requestProcessingStopping && !TakeStartLine(SocketInput))
{
terminated = SocketInput.RemoteIntakeFin;
if (!terminated)
{
await SocketInput;
}
}
while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders))
{
terminated = SocketInput.RemoteIntakeFin;
if (!terminated)
{
await SocketInput;
}
}
if (!terminated && !_requestProcessingStopping)
{
var messageBody = MessageBody.For(HttpVersion, _requestHeaders, this);
_keepAlive = messageBody.RequestKeepAlive;
_requestBody = new FrameRequestStream(messageBody);
RequestBody = _requestBody;
_responseBody = new FrameResponseStream(this);
ResponseBody = _responseBody;
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
_abortedCts = null;
_manuallySetRequestAbortToken = null;
var httpContext = HttpContextFactory.Create(this);
try
{
await Application.Invoke(httpContext).ConfigureAwait(false);
}
catch (Exception ex)
{
ReportApplicationError(ex);
}
finally
{
// Trigger OnStarting if it hasn't been called yet and the app hasn't
// already failed. If an OnStarting callback throws we can go through
// our normal error handling in ProduceEnd.
// https://github.com/aspnet/KestrelHttpServer/issues/43
if (!_responseStarted && _applicationException == null)
{
await FireOnStarting();
}
await FireOnCompleted();
HttpContextFactory.Dispose(httpContext);
// If _requestAbort is set, the connection has already been closed.
if (!_requestAborted)
{
await ProduceEnd();
if (_keepAlive)
{
// Finish reading the request body in case the app did not.
await messageBody.Consume();
}
}
_requestBody.StopAcceptingReads();
_responseBody.StopAcceptingWrites();
}
terminated = !_keepAlive;
}
Reset();
}
}
catch (Exception ex)
{
Log.LogWarning("Connection processing ended abnormally", ex);
}
finally
{
try
{
_abortedCts = null;
// If _requestAborted is set, the connection has already been closed.
if (!_requestAborted)
{
// Inform client no more data will ever arrive
ConnectionControl.End(ProduceEndType.SocketShutdownSend);
// Wait for client to either disconnect or send unexpected data
await SocketInput;
// Dispose socket
ConnectionControl.End(ProduceEndType.SocketDisconnect);
}
}
catch (Exception ex)
{
Log.LogWarning("Connection shutdown abnormally", ex);
}
}
}
public abstract Task RequestProcessingAsync();
public void OnStarting(Func<object, Task> callback, object state)
{
@ -444,7 +332,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
}
private async Task FireOnStarting()
protected async Task FireOnStarting()
{
List<KeyValuePair<Func<object, Task>, object>> onStarting = null;
lock (_onStartingSync)
@ -468,7 +356,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
}
private async Task FireOnCompleted()
protected async Task FireOnCompleted()
{
List<KeyValuePair<Func<object, Task>, object>> onCompleted = null;
lock (_onCompletedSync)
@ -633,7 +521,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
return CreateResponseHeader(statusBytes, appCompleted, immediate);
}
private async Task ProduceEnd()
protected async Task ProduceEnd()
{
if (_applicationException != null)
{
@ -740,7 +628,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
}
private bool TakeStartLine(SocketInput input)
protected bool TakeStartLine(SocketInput input)
{
var scan = input.ConsumingStart();
var consumed = scan;
@ -977,9 +865,16 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
statusCode != 304;
}
private void ReportApplicationError(Exception ex)
protected void ReportApplicationError(Exception ex)
{
_applicationException = ex;
if (_applicationException == null)
{
_applicationException = ex;
}
else
{
_applicationException = new AggregateException(_applicationException, ex);
}
Log.ApplicationError(ex);
}

View File

@ -0,0 +1,153 @@
// 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.Net;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Http.Features;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNet.Server.Kestrel.Http
{
public class Frame<TContext> : Frame
{
private readonly IHttpApplication<TContext> _application;
public Frame(IHttpApplication<TContext> application,
ConnectionContext context)
: this(application, context, remoteEndPoint: null, localEndPoint: null, prepareRequest: null)
{
}
public Frame(IHttpApplication<TContext> application,
ConnectionContext context,
IPEndPoint remoteEndPoint,
IPEndPoint localEndPoint,
Action<IFeatureCollection> prepareRequest)
: base(context, remoteEndPoint, localEndPoint, prepareRequest)
{
_application = application;
}
/// <summary>
/// Primary loop which consumes socket input, parses it for protocol framing, and invokes the
/// application delegate for as long as the socket is intended to remain open.
/// The resulting Task from this loop is preserved in a field which is used when the server needs
/// to drain and close all currently active connections.
/// </summary>
public override async Task RequestProcessingAsync()
{
try
{
var terminated = false;
while (!terminated && !_requestProcessingStopping)
{
while (!terminated && !_requestProcessingStopping && !TakeStartLine(SocketInput))
{
terminated = SocketInput.RemoteIntakeFin;
if (!terminated)
{
await SocketInput;
}
}
while (!terminated && !_requestProcessingStopping && !TakeMessageHeaders(SocketInput, _requestHeaders))
{
terminated = SocketInput.RemoteIntakeFin;
if (!terminated)
{
await SocketInput;
}
}
if (!terminated && !_requestProcessingStopping)
{
var messageBody = MessageBody.For(HttpVersion, _requestHeaders, this);
_keepAlive = messageBody.RequestKeepAlive;
_requestBody = new FrameRequestStream(messageBody);
RequestBody = _requestBody;
_responseBody = new FrameResponseStream(this);
ResponseBody = _responseBody;
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
_abortedCts = null;
_manuallySetRequestAbortToken = null;
var context = _application.CreateContext(this);
try
{
await _application.ProcessRequestAsync(context).ConfigureAwait(false);
}
catch (Exception ex)
{
ReportApplicationError(ex);
}
finally
{
// Trigger OnStarting if it hasn't been called yet and the app hasn't
// already failed. If an OnStarting callback throws we can go through
// our normal error handling in ProduceEnd.
// https://github.com/aspnet/KestrelHttpServer/issues/43
if (!_responseStarted && _applicationException == null)
{
await FireOnStarting();
}
await FireOnCompleted();
_application.DisposeContext(context, _applicationException);
// If _requestAbort is set, the connection has already been closed.
if (!_requestAborted)
{
await ProduceEnd();
if (_keepAlive)
{
// Finish reading the request body in case the app did not.
await messageBody.Consume();
}
}
_requestBody.StopAcceptingReads();
_responseBody.StopAcceptingWrites();
}
terminated = !_keepAlive;
}
Reset();
}
}
catch (Exception ex)
{
Log.LogWarning("Connection processing ended abnormally", ex);
}
finally
{
try
{
_abortedCts = null;
// If _requestAborted is set, the connection has already been closed.
if (!_requestAborted)
{
// Inform client no more data will ever arrive
ConnectionControl.End(ProduceEndType.SocketShutdownSend);
// Wait for client to either disconnect or send unexpected data
await SocketInput;
// Dispose socket
ConnectionControl.End(ProduceEndType.SocketDisconnect);
}
}
catch (Exception ex)
{
Log.LogWarning("Connection shutdown abnormally", ex);
}
}
}
}
}

View File

@ -23,12 +23,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public Task StartAsync(
ServerAddress address,
KestrelThread thread,
RequestDelegate application)
KestrelThread thread)
{
ServerAddress = address;
Thread = thread;
Application = application;
var tcs = new TaskCompletionSource<int>(this);

View File

@ -24,7 +24,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
ServerAddress = listenerContext.ServerAddress;
Thread = listenerContext.Thread;
Application = listenerContext.Application;
Memory2 = listenerContext.Memory2;
Log = listenerContext.Log;
}
@ -33,8 +32,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public KestrelThread Thread { get; set; }
public RequestDelegate Application { get; set; }
public MemoryPool2 Memory2 { get; set; }
}
}

View File

@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.AspNet.Server.Kestrel.Networking;
using Microsoft.Extensions.Logging;
@ -34,12 +33,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public async Task StartAsync(
string pipeName,
ServerAddress address,
KestrelThread thread,
RequestDelegate application)
KestrelThread thread)
{
_pipeName = pipeName;
await StartAsync(address, thread, application).ConfigureAwait(false);
await StartAsync(address, thread).ConfigureAwait(false);
await Thread.PostAsync(_this => _this.PostCallback(),
this).ConfigureAwait(false);

View File

@ -32,15 +32,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
public Task StartAsync(
string pipeName,
ServerAddress address,
KestrelThread thread,
RequestDelegate application)
KestrelThread thread)
{
_pipeName = pipeName;
_buf = thread.Loop.Libuv.buf_init(_ptr, 4);
ServerAddress = address;
Thread = thread;
Application = application;
DispatchPipe = new UvPipeHandle(Log);

View File

@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Server.Kestrel
Threads.Clear();
}
public IDisposable CreateServer(ServerAddress address, RequestDelegate application)
public IDisposable CreateServer(ServerAddress address)
{
var listeners = new List<IDisposable>();
@ -69,7 +69,7 @@ namespace Microsoft.AspNet.Server.Kestrel
(Listener) new PipeListener(this) :
new TcpListener(this);
listeners.Add(listener);
listener.StartAsync(address, thread, application).Wait();
listener.StartAsync(address, thread).Wait();
}
else if (first)
{
@ -78,7 +78,7 @@ namespace Microsoft.AspNet.Server.Kestrel
: new TcpListenerPrimary(this);
listeners.Add(listener);
listener.StartAsync(pipeName, address, thread, application).Wait();
listener.StartAsync(pipeName, address, thread).Wait();
}
else
{
@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Server.Kestrel
? (ListenerSecondary) new PipeListenerSecondary(this)
: new TcpListenerSecondary(this);
listeners.Add(listener);
listener.StartAsync(pipeName, address, thread, application).Wait();
listener.StartAsync(pipeName, address, thread).Wait();
}
first = false;

View File

@ -5,7 +5,6 @@ using System;
using System.Collections.Generic;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.Extensions.Logging;
@ -17,9 +16,8 @@ namespace Microsoft.AspNet.Server.Kestrel
private Stack<IDisposable> _disposables;
private readonly IApplicationLifetime _applicationLifetime;
private readonly ILogger _logger;
private readonly IHttpContextFactory _httpContextFactory;
public KestrelServer(IFeatureCollection features, IApplicationLifetime applicationLifetime, ILogger logger, IHttpContextFactory httpContextFactory)
public KestrelServer(IFeatureCollection features, IApplicationLifetime applicationLifetime, ILogger logger)
{
if (features == null)
{
@ -36,20 +34,14 @@ namespace Microsoft.AspNet.Server.Kestrel
throw new ArgumentNullException(nameof(logger));
}
if (httpContextFactory == null)
{
throw new ArgumentNullException(nameof(httpContextFactory));
}
_applicationLifetime = applicationLifetime;
_logger = logger;
Features = features;
_httpContextFactory = httpContextFactory;
}
public IFeatureCollection Features { get; }
public void Start(RequestDelegate requestDelegate)
public void Start<TContext>(IHttpApplication<TContext> application)
{
if (_disposables != null)
{
@ -64,9 +56,12 @@ namespace Microsoft.AspNet.Server.Kestrel
var dateHeaderValueManager = new DateHeaderValueManager();
var engine = new KestrelEngine(new ServiceContext
{
FrameFactory = (context, remoteEP, localEP, prepareRequest) =>
{
return new Frame<TContext>(application, context, remoteEP, localEP, prepareRequest);
},
AppLifetime = _applicationLifetime,
Log = new KestrelTrace(_logger),
HttpContextFactory = _httpContextFactory,
DateHeaderValueManager = dateHeaderValueManager,
ConnectionFilter = information.ConnectionFilter,
NoDelay = information.NoDelay
@ -119,8 +114,7 @@ namespace Microsoft.AspNet.Server.Kestrel
{
atLeastOneListener = true;
_disposables.Push(engine.CreateServer(
parsedAddress,
requestDelegate));
parsedAddress));
}
}

View File

@ -3,7 +3,6 @@
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Features;
using Microsoft.Extensions.Configuration;
@ -18,13 +17,11 @@ namespace Microsoft.AspNet.Server.Kestrel
{
private readonly IApplicationLifetime _appLifetime;
private readonly ILoggerFactory _loggerFactory;
private readonly IHttpContextFactory _httpContextFactory;
public ServerFactory(IApplicationLifetime appLifetime, ILoggerFactory loggerFactory, IHttpContextFactory httpContextFactory)
public ServerFactory(IApplicationLifetime appLifetime, ILoggerFactory loggerFactory)
{
_appLifetime = appLifetime;
_loggerFactory = loggerFactory;
_httpContextFactory = httpContextFactory;
}
public IServer CreateServer(IConfiguration configuration)
@ -34,7 +31,7 @@ namespace Microsoft.AspNet.Server.Kestrel
var serverFeatures = new FeatureCollection();
serverFeatures.Set<IKestrelServerInformation>(information);
serverFeatures.Set<IServerAddressesFeature>(information);
return new KestrelServer(serverFeatures, _appLifetime, _loggerFactory.CreateLogger("Microsoft.AspNet.Server.Kestrel"), _httpContextFactory);
return new KestrelServer(serverFeatures, _appLifetime, _loggerFactory.CreateLogger("Microsoft.AspNet.Server.Kestrel"));
}
}
}

View File

@ -1,8 +1,10 @@
// 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.Net;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Filter;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
@ -19,7 +21,7 @@ namespace Microsoft.AspNet.Server.Kestrel
{
AppLifetime = context.AppLifetime;
Log = context.Log;
HttpContextFactory = context.HttpContextFactory;
FrameFactory = context.FrameFactory;
DateHeaderValueManager = context.DateHeaderValueManager;
ConnectionFilter = context.ConnectionFilter;
NoDelay = context.NoDelay;
@ -29,7 +31,7 @@ namespace Microsoft.AspNet.Server.Kestrel
public IKestrelTrace Log { get; set; }
public IHttpContextFactory HttpContextFactory { get; set; }
public Func<ConnectionContext, IPEndPoint, IPEndPoint, Action<IFeatureCollection>, Frame> FrameFactory { get; set; }
public DateHeaderValueManager DateHeaderValueManager { get; set; }

View File

@ -0,0 +1,37 @@
// 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.Hosting.Server;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Http.Features;
namespace Microsoft.AspNet.Server.KestrelTests
{
public class DummyApplication : IHttpApplication<HttpContext>
{
private readonly RequestDelegate _requestDelegate;
public DummyApplication(RequestDelegate requestDelegate)
{
_requestDelegate = requestDelegate;
}
public HttpContext CreateContext(IFeatureCollection contextFeatures)
{
return new DefaultHttpContext(contextFeatures);
}
public void DisposeContext(HttpContext context, Exception exception)
{
}
public async Task ProcessRequestAsync(HttpContext context)
{
await _requestDelegate(context);
}
}
}

View File

@ -12,6 +12,7 @@ using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel;
using Microsoft.AspNet.Server.Kestrel.Filter;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.AspNet.Testing.xunit;
using Microsoft.Extensions.Logging;
using Xunit;
@ -91,12 +92,13 @@ namespace Microsoft.AspNet.Server.KestrelTests
[ConditionalTheory]
[MemberData(nameof(ConnectionFilterData))]
[FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Test hangs after execution on Mono.")]
public void ListenerCanCreateAndDispose(ServiceContext testContext)
public void ListenerCanCreateAndDispose(TestServiceContext testContext)
{
testContext.App = App;
var engine = new KestrelEngine(testContext);
engine.Start(1);
var address = ServerAddress.FromUrl("http://localhost:54321/");
var started = engine.CreateServer(address, App);
var started = engine.CreateServer(address);
started.Dispose();
engine.Dispose();
}
@ -104,12 +106,13 @@ namespace Microsoft.AspNet.Server.KestrelTests
[ConditionalTheory]
[MemberData(nameof(ConnectionFilterData))]
[FrameworkSkipCondition(RuntimeFrameworks.Mono, SkipReason = "Test hangs after execution on Mono.")]
public void ConnectionCanReadAndWrite(ServiceContext testContext)
public void ConnectionCanReadAndWrite(TestServiceContext testContext)
{
testContext.App = App;
var engine = new KestrelEngine(testContext);
engine.Start(1);
var address = ServerAddress.FromUrl("http://localhost:54321/");
var started = engine.CreateServer(address, App);
var started = engine.CreateServer(address);
Console.WriteLine("Started");
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
DateHeaderValueManager = new DateHeaderValueManager(),
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
};
var frame = new Frame(connectionContext);
var frame = new Frame<object>(application: null, context: connectionContext);
frame.Scheme = "https";
// Act

View File

@ -20,7 +20,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
DateHeaderValueManager = new DateHeaderValueManager(),
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
};
var frame = new Frame(connectionContext);
var frame = new Frame<object>(application: null, context: connectionContext);
IDictionary<string, StringValues> headers = frame.ResponseHeaders;
Assert.Equal(2, headers.Count);
@ -48,7 +48,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
DateHeaderValueManager = new DateHeaderValueManager(),
ServerAddress = ServerAddress.FromUrl("http://localhost:5000")
};
var frame = new Frame(connectionContext);
var frame = new Frame<object>(application: null, context: connectionContext);
Assert.True(frame.ResponseHeaders.Count > 0);

View File

@ -4,6 +4,7 @@
using System;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel;
using Microsoft.AspNet.Server.Kestrel.Http;
namespace Microsoft.AspNet.Server.KestrelTests
{
@ -32,11 +33,14 @@ namespace Microsoft.AspNet.Server.KestrelTests
public void Create(RequestDelegate app, ServiceContext context, string serverAddress)
{
context.FrameFactory = (connectionContext, remoteEP, localEP, prepareRequest) =>
{
return new Frame<HttpContext>(new DummyApplication(app), connectionContext, remoteEP, localEP, prepareRequest);
};
_engine = new KestrelEngine(context);
_engine.Start(1);
_server = _engine.CreateServer(
ServerAddress.FromUrl(serverAddress),
app);
ServerAddress.FromUrl(serverAddress));
}
public void Dispose()

View File

@ -1,19 +1,37 @@
// 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 Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel;
using Microsoft.AspNet.Server.Kestrel.Http;
namespace Microsoft.AspNet.Server.KestrelTests
{
public class TestServiceContext : ServiceContext
{
private RequestDelegate _app;
public TestServiceContext()
{
AppLifetime = new LifetimeNotImplemented();
Log = new TestKestrelTrace();
HttpContextFactory = new HttpContextFactory(new HttpContextAccessor());
DateHeaderValueManager = new TestDateHeaderValueManager();
}
public RequestDelegate App
{
get
{
return _app;
}
set
{
_app = value;
FrameFactory = (connectionContext, remoteEP, localEP, prepareRequest) =>
{
return new Frame<HttpContext>(new DummyApplication(_app), connectionContext, remoteEP, localEP, prepareRequest);
};
}
}
}
}