Reacting to new IServer IHttpApplication design

This commit is contained in:
John Luo 2015-11-03 13:24:23 -08:00
parent 82c855d172
commit 8712ba4855
8 changed files with 100 additions and 39 deletions

View File

@ -21,7 +21,6 @@ using System.Diagnostics.Contracts;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Features;
using Microsoft.Extensions.Logging;
@ -35,9 +34,8 @@ namespace Microsoft.AspNet.Server.WebListener
private readonly Microsoft.Net.Http.Server.WebListener _listener;
private readonly ILogger _logger;
private readonly IHttpContextFactory _httpContextFactory;
private RequestDelegate _appFunc;
private IHttpApplication<object> _application;
private int _maxAccepts;
private int _acceptorCounts;
@ -47,17 +45,16 @@ namespace Microsoft.AspNet.Server.WebListener
private int _outstandingRequests;
private ManualResetEvent _shutdownSignal;
internal MessagePump(Microsoft.Net.Http.Server.WebListener listener, ILoggerFactory loggerFactory, IFeatureCollection features, IHttpContextFactory httpContextFactory)
internal MessagePump(Microsoft.Net.Http.Server.WebListener listener, ILoggerFactory loggerFactory, IFeatureCollection features)
{
if (features == null)
{
throw new ArgumentNullException(nameof(Features));
throw new ArgumentNullException(nameof(features));
}
Contract.Assert(listener != null);
_listener = listener;
_logger = LogHelper.CreateLogger(loggerFactory, typeof(MessagePump));
_httpContextFactory = httpContextFactory;
Features = features;
_processRequest = new Action<object>(ProcessRequestAsync);
@ -90,11 +87,11 @@ namespace Microsoft.AspNet.Server.WebListener
public IFeatureCollection Features { get; }
public void Start(RequestDelegate app)
public void Start<TContext>(IHttpApplication<TContext> application)
{
if (app == null)
if (application == null)
{
throw new ArgumentNullException(nameof(app));
throw new ArgumentNullException(nameof(application));
}
var addressesFeature = Features.Get<IServerAddressesFeature>();
@ -106,11 +103,11 @@ namespace Microsoft.AspNet.Server.WebListener
ParseAddresses(addressesFeature.Addresses, Listener);
// Can't call Start twice
Contract.Assert(_appFunc == null);
Contract.Assert(_application == null);
Contract.Assert(app != null);
Contract.Assert(application != null);
_appFunc = app;
_application = new ApplicationWrapper<TContext>(application);
if (_listener.UrlPrefixes.Count == 0)
{
@ -183,14 +180,15 @@ namespace Microsoft.AspNet.Server.WebListener
return;
}
HttpContext httpContext = null;
object context = null;
try
{
Interlocked.Increment(ref _outstandingRequests);
FeatureContext featureContext = new FeatureContext(requestContext, EnableResponseCaching);
httpContext = _httpContextFactory.Create(featureContext.Features);
await _appFunc(httpContext).SupressContext();
context = _application.CreateContext(featureContext.Features);
await _application.ProcessRequestAsync(context).SupressContext();
requestContext.Dispose();
_application.DisposeContext(context, null);
}
catch (Exception ex)
{
@ -205,13 +203,10 @@ namespace Microsoft.AspNet.Server.WebListener
requestContext.Response.Reset();
SetFatalResponse(requestContext, 500);
}
_application.DisposeContext(context, ex);
}
finally
{
if (httpContext != null)
{
_httpContextFactory.Dispose(httpContext);
}
if (Interlocked.Decrement(ref _outstandingRequests) == 0 && _stopping)
{
_shutdownSignal.Set();
@ -253,5 +248,30 @@ namespace Microsoft.AspNet.Server.WebListener
// All requests are finished
_listener.Dispose();
}
private class ApplicationWrapper<TContext> : IHttpApplication<object>
{
private readonly IHttpApplication<TContext> _application;
public ApplicationWrapper(IHttpApplication<TContext> application)
{
_application = application;
}
public object CreateContext(IFeatureCollection contextFeatures)
{
return _application.CreateContext(contextFeatures);
}
public void DisposeContext(object context, Exception exception)
{
_application.DisposeContext((TContext)context, exception);
}
public Task ProcessRequestAsync(object context)
{
return _application.ProcessRequestAsync((TContext)context);
}
}
}
}

View File

@ -37,7 +37,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Features;
using Microsoft.Extensions.Configuration;
@ -51,12 +50,10 @@ namespace Microsoft.AspNet.Server.WebListener
public class ServerFactory : IServerFactory
{
private ILoggerFactory _loggerFactory;
private IHttpContextFactory _httpContextFactory;
public ServerFactory(ILoggerFactory loggerFactory, IHttpContextFactory httpContextFactory)
public ServerFactory(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
_httpContextFactory = httpContextFactory;
}
/// <summary>
@ -72,7 +69,7 @@ namespace Microsoft.AspNet.Server.WebListener
serverFeatures.Set(listener);
serverFeatures.Set(SplitAddresses(configuration));
return new MessagePump(listener, _loggerFactory, serverFeatures, _httpContextFactory);
return new MessagePump(listener, _loggerFactory, serverFeatures);
}
private IServerAddressesFeature SplitAddresses(IConfiguration config)

View File

@ -20,9 +20,7 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Http.Features.Authentication;
using Microsoft.AspNet.Http.Internal;
using Xunit;
using AuthenticationSchemes = Microsoft.Net.Http.Server.AuthenticationSchemes;

View File

@ -0,0 +1,51 @@
// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Http.Internal;
namespace Microsoft.AspNet.Server.WebListener
{
internal 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 httpContext, Exception exception)
{
}
public async Task ProcessRequestAsync(HttpContext httpContext)
{
await _requestDelegate(httpContext);
}
}
}

View File

@ -22,7 +22,6 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Http.Internal;
using Xunit;
namespace Microsoft.AspNet.Server.WebListener

View File

@ -20,11 +20,9 @@ using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting.Builder;
using Microsoft.AspNet.Hosting.Server;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Http.Internal;
using Microsoft.Net.Http.Server;
using Xunit;
@ -171,7 +169,7 @@ namespace Microsoft.AspNet.Server.WebListener
var dynamicServer = Utilities.CreateHttpServerReturnRoot("/", out root, app);
dynamicServer.Dispose();
var rootUri = new Uri(root);
var factory = new ServerFactory(loggerFactory: null, httpContextFactory: new HttpContextFactory(new HttpContextAccessor()));
var factory = new ServerFactory(loggerFactory: null);
var server = factory.CreateServer(configuration: null);
var listener = server.Features.Get<Microsoft.Net.Http.Server.WebListener>();
@ -180,7 +178,7 @@ namespace Microsoft.AspNet.Server.WebListener
listener.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path));
}
server.Start(app);
server.Start(new DummyApplication(app));
return server;
}

View File

@ -24,10 +24,8 @@ using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Hosting.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Http.Internal;
using Microsoft.Net.Http.Server;
using Xunit;
@ -253,7 +251,7 @@ namespace Microsoft.AspNet.Server.WebListener
string address;
using (Utilities.CreateHttpServer(out address, httpContext => Task.FromResult(0))) { }
var factory = new ServerFactory(loggerFactory: null, httpContextFactory: new HttpContextFactory(new HttpContextAccessor()));
var factory = new ServerFactory(loggerFactory: null);
var server = factory.CreateServer(configuration: null);
var listener = server.Features.Get<Microsoft.Net.Http.Server.WebListener>();
listener.UrlPrefixes.Add(UrlPrefix.Create(address));
@ -261,7 +259,7 @@ namespace Microsoft.AspNet.Server.WebListener
using (server)
{
server.Start(httpContext => Task.FromResult(0));
server.Start(new DummyApplication(httpContext => Task.FromResult(0)));
string response = await SendRequestAsync(address);
Assert.Equal(string.Empty, response);
}

View File

@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Server.WebListener
internal static IServer CreateDynamicHttpServer(string basePath, AuthenticationSchemes authType, out string root, out string baseAddress, RequestDelegate app)
{
var factory = new ServerFactory(loggerFactory: null, httpContextFactory: Factory);
var factory = new ServerFactory(loggerFactory: null);
lock (PortLock)
{
while (NextPort < MaxPort)
@ -73,7 +73,7 @@ namespace Microsoft.AspNet.Server.WebListener
listener.AuthenticationManager.AuthenticationSchemes = authType;
try
{
server.Start(app);
server.Start(new DummyApplication(app));
return server;
}
catch (WebListenerException)
@ -92,10 +92,10 @@ namespace Microsoft.AspNet.Server.WebListener
internal static IServer CreateServer(string scheme, string host, int port, string path, RequestDelegate app)
{
var factory = new ServerFactory(loggerFactory: null, httpContextFactory: Factory);
var factory = new ServerFactory(loggerFactory: null);
var server = factory.CreateServer(configuration: null);
server.Features.Get<IServerAddressesFeature>().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString());
server.Start(app);
server.Start(new DummyApplication(app));
return server;
}
}