Rough implementation of feature collection optimization

This commit is contained in:
Louis DeJardin 2015-10-02 16:09:46 -07:00
parent 0c1b05ce2d
commit dcf591c832
10 changed files with 500 additions and 64 deletions

View File

@ -19,6 +19,9 @@ namespace SampleApp
{
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IApplicationEnvironment env)
{
var ksi = app.ServerFeatures[typeof(IKestrelServerInformation)] as IKestrelServerInformation;
//ksi.ThreadCount = 4;
loggerFactory.MinimumLevel = LogLevel.Debug;
loggerFactory.AddConsole(LogLevel.Debug);
@ -46,6 +49,8 @@ namespace SampleApp
context.Request.Path,
context.Request.QueryString);
foreach (var q in context.Request.Query) { }
context.Response.ContentLength = 11;
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello world");

View File

@ -2,45 +2,44 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Server.Kestrel
namespace Microsoft.AspNet.Server.Kestrel.Http
{
public class ServerRequest : IHttpRequestFeature, IHttpResponseFeature, IHttpUpgradeFeature
public partial class Frame : IFeatureCollection, IHttpRequestFeature, IHttpResponseFeature, IHttpUpgradeFeature
{
private Frame _frame;
private string _scheme;
private string _pathBase;
private FeatureCollection _features;
private int _featureRevision;
public ServerRequest(Frame frame)
{
_frame = frame;
_features = new FeatureCollection();
PopulateFeatures();
}
private Dictionary<Type, object> Extra => MaybeExtra ?? Interlocked.CompareExchange(ref MaybeExtra, new Dictionary<Type, object>(), null);
private Dictionary<Type, object> MaybeExtra;
internal IFeatureCollection Features
public void ResetFeatureCollection()
{
get { return _features; }
FastReset();
MaybeExtra?.Clear();
Interlocked.Increment(ref _featureRevision);
}
string IHttpRequestFeature.Protocol
{
get
{
return _frame.HttpVersion;
return HttpVersion;
}
set
{
_frame.HttpVersion = value;
HttpVersion = value;
}
}
@ -61,12 +60,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{
get
{
return _frame.Method;
return Method;
}
set
{
_frame.Method = value;
Method = value;
}
}
@ -87,12 +86,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{
get
{
return _frame.Path;
return Path;
}
set
{
_frame.Path = value;
Path = value;
}
}
@ -100,12 +99,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{
get
{
return _frame.QueryString;
return QueryString;
}
set
{
_frame.QueryString = value;
QueryString = value;
}
}
@ -113,12 +112,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{
get
{
return _frame.RequestHeaders;
return RequestHeaders;
}
set
{
_frame.RequestHeaders = value;
RequestHeaders = value;
}
}
@ -126,12 +125,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{
get
{
return _frame.RequestBody;
return RequestBody;
}
set
{
_frame.RequestBody = value;
RequestBody = value;
}
}
@ -139,12 +138,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{
get
{
return _frame.StatusCode;
return StatusCode;
}
set
{
_frame.StatusCode = value;
StatusCode = value;
}
}
@ -152,12 +151,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{
get
{
return _frame.ReasonPhrase;
return ReasonPhrase;
}
set
{
_frame.ReasonPhrase = value;
ReasonPhrase = value;
}
}
@ -165,12 +164,12 @@ namespace Microsoft.AspNet.Server.Kestrel
{
get
{
return _frame.ResponseHeaders;
return ResponseHeaders;
}
set
{
_frame.ResponseHeaders = value;
ResponseHeaders = value;
}
}
@ -178,18 +177,18 @@ namespace Microsoft.AspNet.Server.Kestrel
{
get
{
return _frame.ResponseBody;
return ResponseBody;
}
set
{
_frame.ResponseBody = value;
ResponseBody = value;
}
}
bool IHttpResponseFeature.HasStarted
{
get { return _frame.HasResponseStarted; }
get { return HasResponseStarted; }
}
bool IHttpUpgradeFeature.IsUpgradableRequest
@ -197,7 +196,7 @@ namespace Microsoft.AspNet.Server.Kestrel
get
{
StringValues values;
if (_frame.RequestHeaders.TryGetValue("Connection", out values))
if (RequestHeaders.TryGetValue("Connection", out values))
{
return values.Any(value => value.IndexOf("upgrade", StringComparison.OrdinalIgnoreCase) != -1);
}
@ -205,38 +204,45 @@ namespace Microsoft.AspNet.Server.Kestrel
}
}
private void PopulateFeatures()
bool IFeatureCollection.IsReadOnly => false;
int IFeatureCollection.Revision => _featureRevision;
object IFeatureCollection.this[Type key]
{
_features[typeof(IHttpRequestFeature)] = this;
_features[typeof(IHttpResponseFeature)] = this;
_features[typeof(IHttpUpgradeFeature)] = this;
get { return FastFeatureGet(key); }
set { FastFeatureSet(key, value); }
}
void IHttpResponseFeature.OnStarting(Func<object, Task> callback, object state)
{
_frame.OnStarting(callback, state);
OnStarting(callback, state);
}
void IHttpResponseFeature.OnCompleted(Func<object, Task> callback, object state)
{
_frame.OnCompleted(callback, state);
OnCompleted(callback, state);
}
Task<Stream> IHttpUpgradeFeature.UpgradeAsync()
{
_frame.StatusCode = 101;
_frame.ReasonPhrase = "Switching Protocols";
_frame.ResponseHeaders["Connection"] = "Upgrade";
if (!_frame.ResponseHeaders.ContainsKey("Upgrade"))
StatusCode = 101;
ReasonPhrase = "Switching Protocols";
ResponseHeaders["Connection"] = "Upgrade";
if (!ResponseHeaders.ContainsKey("Upgrade"))
{
StringValues values;
if (_frame.RequestHeaders.TryGetValue("Upgrade", out values))
if (RequestHeaders.TryGetValue("Upgrade", out values))
{
_frame.ResponseHeaders["Upgrade"] = values;
ResponseHeaders["Upgrade"] = values;
}
}
_frame.ProduceStart();
return Task.FromResult(_frame.DuplexStream);
ProduceStart();
return Task.FromResult(DuplexStream);
}
IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
}
}

View File

@ -0,0 +1,297 @@
using System;
using System.Collections.Generic;
namespace Microsoft.AspNet.Server.Kestrel.Http
{
public partial class Frame
{
private object _currentIHttpRequestFeature;
private object _currentIHttpResponseFeature;
private object _currentIHttpUpgradeFeature;
private object _currentIHttpRequestIdentifierFeature;
private object _currentIHttpConnectionFeature;
private object _currentITlsConnectionFeature;
private object _currentIServiceProvidersFeature;
private object _currentIHttpSendFileFeature;
private object _currentIHttpWebSocketFeature;
private object _currentIQueryFeature;
private object _currentIFormFeature;
private object _currentIItemsFeature;
private object _currentIHttpAuthenticationFeature;
private object _currentIHttpRequestLifetimeFeature;
private object _currentISessionFeature;
private object _currentIResponseCookiesFeature;
private void FastReset()
{
_currentIHttpRequestFeature = this as global::Microsoft.AspNet.Http.Features.IHttpRequestFeature;
_currentIHttpResponseFeature = this as global::Microsoft.AspNet.Http.Features.IHttpResponseFeature;
_currentIHttpUpgradeFeature = this as global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature;
_currentIHttpRequestIdentifierFeature = this as global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature;
_currentIHttpConnectionFeature = this as global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature;
_currentITlsConnectionFeature = this as global::Microsoft.AspNet.Http.Features.ITlsConnectionFeature;
_currentIServiceProvidersFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IServiceProvidersFeature;
_currentIHttpSendFileFeature = this as global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature;
_currentIHttpWebSocketFeature = this as global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature;
_currentIQueryFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IQueryFeature;
_currentIFormFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IFormFeature;
_currentIItemsFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IItemsFeature;
_currentIHttpAuthenticationFeature = this as global::Microsoft.AspNet.Http.Features.Authentication.IHttpAuthenticationFeature;
_currentIHttpRequestLifetimeFeature = this as global::Microsoft.AspNet.Http.Features.IHttpRequestLifetimeFeature;
_currentISessionFeature = this as global::Microsoft.AspNet.Http.Features.ISessionFeature;
_currentIResponseCookiesFeature = this as global::Microsoft.AspNet.Http.Features.Internal.IResponseCookiesFeature;
}
private object FastFeatureGet(Type key)
{
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature))
{
return _currentIHttpRequestFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature))
{
return _currentIHttpResponseFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature))
{
return _currentIHttpUpgradeFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature))
{
return _currentIHttpRequestIdentifierFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature))
{
return _currentIHttpConnectionFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.ITlsConnectionFeature))
{
return _currentITlsConnectionFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IServiceProvidersFeature))
{
return _currentIServiceProvidersFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature))
{
return _currentIHttpSendFileFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature))
{
return _currentIHttpWebSocketFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IQueryFeature))
{
return _currentIQueryFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IFormFeature))
{
return _currentIFormFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IItemsFeature))
{
return _currentIItemsFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Authentication.IHttpAuthenticationFeature))
{
return _currentIHttpAuthenticationFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestLifetimeFeature))
{
return _currentIHttpRequestLifetimeFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.ISessionFeature))
{
return _currentISessionFeature;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IResponseCookiesFeature))
{
return _currentIResponseCookiesFeature;
}
object feature = null;
if (MaybeExtra?.TryGetValue(key, out feature) ?? false)
{
return feature;
}
return null;
}
private void FastFeatureSet(Type key, object feature)
{
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature))
{
_currentIHttpRequestFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature))
{
_currentIHttpResponseFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature))
{
_currentIHttpUpgradeFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature))
{
_currentIHttpRequestIdentifierFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature))
{
_currentIHttpConnectionFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.ITlsConnectionFeature))
{
_currentITlsConnectionFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IServiceProvidersFeature))
{
_currentIServiceProvidersFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature))
{
_currentIHttpSendFileFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature))
{
_currentIHttpWebSocketFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IQueryFeature))
{
_currentIQueryFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IFormFeature))
{
_currentIFormFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IItemsFeature))
{
_currentIItemsFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Authentication.IHttpAuthenticationFeature))
{
_currentIHttpAuthenticationFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestLifetimeFeature))
{
_currentIHttpRequestLifetimeFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.ISessionFeature))
{
_currentISessionFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
if (key == typeof(global::Microsoft.AspNet.Http.Features.Internal.IResponseCookiesFeature))
{
_currentIResponseCookiesFeature = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}
Extra[key] = feature;
}
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{
if (_currentIHttpRequestFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestFeature), _currentIHttpRequestFeature);
}
if (_currentIHttpResponseFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpResponseFeature), _currentIHttpResponseFeature);
}
if (_currentIHttpUpgradeFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpUpgradeFeature), _currentIHttpUpgradeFeature);
}
if (_currentIHttpRequestIdentifierFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestIdentifierFeature), _currentIHttpRequestIdentifierFeature);
}
if (_currentIHttpConnectionFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpConnectionFeature), _currentIHttpConnectionFeature);
}
if (_currentITlsConnectionFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.ITlsConnectionFeature), _currentITlsConnectionFeature);
}
if (_currentIServiceProvidersFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IServiceProvidersFeature), _currentIServiceProvidersFeature);
}
if (_currentIHttpSendFileFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpSendFileFeature), _currentIHttpSendFileFeature);
}
if (_currentIHttpWebSocketFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpWebSocketFeature), _currentIHttpWebSocketFeature);
}
if (_currentIQueryFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IQueryFeature), _currentIQueryFeature);
}
if (_currentIFormFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IFormFeature), _currentIFormFeature);
}
if (_currentIItemsFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IItemsFeature), _currentIItemsFeature);
}
if (_currentIHttpAuthenticationFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Authentication.IHttpAuthenticationFeature), _currentIHttpAuthenticationFeature);
}
if (_currentIHttpRequestLifetimeFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.IHttpRequestLifetimeFeature), _currentIHttpRequestLifetimeFeature);
}
if (_currentISessionFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.ISessionFeature), _currentISessionFeature);
}
if (_currentIResponseCookiesFeature != null)
{
yield return new KeyValuePair<Type, object>(typeof(global::Microsoft.AspNet.Http.Features.Internal.IResponseCookiesFeature), _currentIResponseCookiesFeature);
}
if (MaybeExtra != null)
{
foreach(var item in MaybeExtra)
{
yield return item;
}
}
}
}
}

View File

@ -2,12 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
@ -16,7 +18,7 @@ using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Server.Kestrel.Http
{
public class Frame : FrameContext, IFrameControl
public partial class Frame : FrameContext, IFrameControl
{
private static readonly Encoding _ascii = Encoding.ASCII;
private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n");
@ -80,6 +82,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
_requestHeaders.Reset();
ResetResponseHeaders();
ResetFeatureCollection();
Method = null;
RequestUri = null;
@ -725,5 +728,5 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
statusCode != 205 &&
statusCode != 304;
}
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNet.Http.Features;
using Microsoft.AspNet.Server.Kestrel.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
using Microsoft.AspNet.Server.Kestrel.Networking;
@ -98,7 +99,7 @@ namespace Microsoft.AspNet.Server.Kestrel
Threads.Clear();
}
public IDisposable CreateServer(ServerAddress address, Func<Frame, Task> application)
public IDisposable CreateServer(ServerAddress address, Func<IFeatureCollection, Task> application)
{
var listeners = new List<IDisposable>();

View File

@ -88,11 +88,7 @@ namespace Microsoft.AspNet.Server.Kestrel
atLeastOneListener = true;
disposables.Push(engine.CreateServer(
parsedAddress,
async frame =>
{
var request = new ServerRequest(frame);
await application.Invoke(request.Features).ConfigureAwait(false);
}));
application));
}
}

View File

@ -52,7 +52,7 @@
"scripts": {
"prepare": [
"dnu restore ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode",
"dnx -p ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode run Http/FrameHeaders.Generated.cs"
"dnx -p ../../tools/Microsoft.AspNet.Server.Kestrel.GeneratedCode run Http/FrameHeaders.Generated.cs Http/Frame.Generated.cs"
],
"postrestore": [
"dnu restore ../../tools/Microsoft.AspNet.Server.Kestrel.LibuvCopier",
@ -65,6 +65,5 @@
"runtimes/win7-x86/native/": "runtimes/win7-x86/native/*",
"runtimes/win10-arm/native/": "runtimes/win10-arm/native/*",
"runtimes/osx/native/": "runtimes/osx/native/*"
}
}

View File

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Http.Features;
using Microsoft.Dnx.Compilation.CSharp;
using Microsoft.AspNet.Http.Features.Internal;
using Microsoft.AspNet.Http.Features.Authentication;
namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
{
// This project can output the Class library as a NuGet Package.
// To enable this option, right-click on the project and select the Properties menu item. In the Build tab select "Produce outputs on build".
public class FrameFeatureCollection : ICompileModule
{
static string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
{
return values.Select(formatter).Aggregate((a, b) => a + b);
}
public virtual void BeforeCompile(BeforeCompileContext context)
{
var syntaxTree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(GeneratedFile());
context.Compilation = context.Compilation.AddSyntaxTrees(syntaxTree);
}
public static string GeneratedFile()
{
var commonFeatures = new[]
{
typeof(IHttpRequestFeature),
typeof(IHttpResponseFeature),
typeof(IHttpRequestIdentifierFeature),
typeof(IHttpSendFileFeature),
typeof(IServiceProvidersFeature),
typeof(IHttpAuthenticationFeature),
typeof(IHttpRequestLifetimeFeature),
typeof(IQueryFeature),
typeof(IFormFeature),
typeof(IResponseCookiesFeature),
typeof(IItemsFeature),
typeof(IHttpConnectionFeature),
typeof(ITlsConnectionFeature),
typeof(IHttpUpgradeFeature),
typeof(IHttpWebSocketFeature),
typeof(ISessionFeature),
};
return $@"
using System;
using System.Collections.Generic;
namespace Microsoft.AspNet.Server.Kestrel.Http
{{
public partial class Frame
{{
{Each(commonFeatures, feature => $@"
private object _current{feature.Name};")}
private void FastReset()
{{{Each(commonFeatures, feature => $@"
_current{feature.Name} = this as global::{feature.FullName};")}
}}
private object FastFeatureGet(Type key)
{{{Each(commonFeatures, feature => $@"
if (key == typeof(global::{feature.FullName}))
{{
return _current{feature.Name};
}}")}
object feature = null;
if (MaybeExtra?.TryGetValue(key, out feature) ?? false)
{{
return feature;
}}
return null;
}}
private void FastFeatureSet(Type key, object feature)
{{{Each(commonFeatures, feature => $@"
if (key == typeof(global::{feature.FullName}))
{{
_current{feature.Name} = feature;
System.Threading.Interlocked.Increment(ref _featureRevision);
return;
}}")}
Extra[key] = feature;
}}
private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
{{{Each(commonFeatures, feature => $@"
if (_current{feature.Name} != null)
{{
yield return new KeyValuePair<Type, object>(typeof(global::{feature.FullName}), _current{feature.Name});
}}")}
if (MaybeExtra != null)
{{
foreach(var item in MaybeExtra)
{{
yield return item;
}}
}}
}}
}}
}}
";
}
public virtual void AfterCompile(AfterCompileContext context)
{
}
}
}

View File

@ -7,19 +7,34 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
{
public int Main(string[] args)
{
var text = KnownHeaders.GeneratedFile();
var text0 = KnownHeaders.GeneratedFile();
var text1 = FrameFeatureCollection.GeneratedFile();
if (args.Length == 1)
{
var existing = File.Exists(args[0]) ? File.ReadAllText(args[0]) : "";
if (!string.Equals(text, existing))
if (!string.Equals(text0, existing))
{
File.WriteAllText(args[0], text);
File.WriteAllText(args[0], text0);
}
}
else if (args.Length == 2)
{
var existing0 = File.Exists(args[0]) ? File.ReadAllText(args[0]) : "";
if (!string.Equals(text0, existing0))
{
File.WriteAllText(args[0], text0);
}
var existing1 = File.Exists(args[1]) ? File.ReadAllText(args[1]) : "";
if (!string.Equals(text1, existing1))
{
File.WriteAllText(args[1], text1);
}
}
else
{
Console.WriteLine(text);
Console.WriteLine(text0);
}
return 0;
}

View File

@ -1,8 +1,10 @@
{
{
"version": "1.0.0-*",
"dependencies": {
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*"
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*",
"Microsoft.AspNet.Http.Features": "1.0.0-*",
"Microsoft.AspNet.Hosting": "1.0.0-*"
},
"commands": {