Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

Commit d1649ea

Browse files
committed
Reduce FeatureReference checking, lazy init FormFeature
1 parent 271612a commit d1649ea

File tree

8 files changed

+93
-22
lines changed

8 files changed

+93
-22
lines changed

src/Microsoft.AspNetCore.Http.Features/FeatureReferences.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ public FeatureReferences(IFeatureCollection collection)
1515
Revision = collection.Revision;
1616
}
1717

18+
public FeatureReferences(IFeatureCollection collection, int revision)
19+
{
20+
Collection = collection;
21+
Cache = default(TCache);
22+
Revision = revision;
23+
}
24+
1825
public IFeatureCollection Collection { get; private set; }
1926
public int Revision { get; private set; }
2027

src/Microsoft.AspNetCore.Http/DefaultHttpContext.cs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Runtime.CompilerServices;
67
using System.Security.Claims;
78
using System.Threading;
89
using Microsoft.AspNetCore.Http.Authentication;
@@ -24,6 +25,7 @@ public class DefaultHttpContext : HttpContext
2425
private readonly static Func<IFeatureCollection, ISessionFeature> _nullSessionFeature = f => null;
2526
private readonly static Func<IFeatureCollection, IHttpRequestIdentifierFeature> _newHttpRequestIdentifierFeature = f => new HttpRequestIdentifierFeature();
2627

28+
private FormOptions _formOptions;
2729
private FeatureReferences<FeatureInterfaces> _features;
2830

2931
private HttpRequest _request;
@@ -44,15 +46,26 @@ public DefaultHttpContext()
4446
}
4547

4648
public DefaultHttpContext(IFeatureCollection features)
49+
: this(features, FormOptions.Default)
4750
{
48-
Initialize(features);
4951
}
5052

51-
public virtual void Initialize(IFeatureCollection features)
53+
public DefaultHttpContext(IFeatureCollection features, FormOptions formOptions)
54+
{
55+
Initialize(features, formOptions);
56+
}
57+
58+
public virtual void Initialize(IFeatureCollection features, FormOptions formOptions)
5259
{
5360
_features = new FeatureReferences<FeatureInterfaces>(features);
5461
_request = InitializeHttpRequest();
5562
_response = InitializeHttpResponse();
63+
_formOptions = formOptions;
64+
}
65+
66+
public virtual void Initialize(IFeatureCollection features)
67+
{
68+
Initialize(features, FormOptions.Default);
5669
}
5770

5871
public virtual void Uninitialize()
@@ -85,6 +98,7 @@ public virtual void Uninitialize()
8598
UninitializeWebSocketManager(_websockets);
8699
_websockets = null;
87100
}
101+
_formOptions = null;
88102
}
89103

90104
private IItemsFeature ItemsFeature =>
@@ -185,18 +199,43 @@ public override ISession Session
185199
}
186200
}
187201

188-
189-
190202
public override void Abort()
191203
{
192204
LifetimeFeature.Abort();
193205
}
194206

207+
[MethodImpl(MethodImplOptions.NoInlining)]
208+
private void InitializeRequestResponse()
209+
{
210+
var revision = _features.Revision;
211+
var collection = _features.Collection;
212+
213+
_request = new DefaultHttpRequest(this, revision, collection, _formOptions);
214+
_response = new DefaultHttpResponse(this, revision, collection);
215+
}
216+
217+
protected virtual HttpRequest InitializeHttpRequest()
218+
{
219+
if (_request == null)
220+
{
221+
InitializeRequestResponse();
222+
}
223+
224+
return _request;
225+
}
195226

196-
protected virtual HttpRequest InitializeHttpRequest() => new DefaultHttpRequest(this);
197227
protected virtual void UninitializeHttpRequest(HttpRequest instance) { }
198228

199-
protected virtual HttpResponse InitializeHttpResponse() => new DefaultHttpResponse(this);
229+
protected virtual HttpResponse InitializeHttpResponse()
230+
{
231+
if (_response == null)
232+
{
233+
InitializeRequestResponse();
234+
}
235+
236+
return _response;
237+
}
238+
200239
protected virtual void UninitializeHttpResponse(HttpResponse instance) { }
201240

202241
protected virtual ConnectionInfo InitializeConnectionInfo() => new DefaultConnectionInfo(Features);

src/Microsoft.AspNetCore.Http/Features/FormFeature.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ namespace Microsoft.AspNetCore.Http.Features
1515
{
1616
public class FormFeature : IFormFeature
1717
{
18-
private static readonly FormOptions DefaultFormOptions = new FormOptions();
19-
2018
private readonly HttpRequest _request;
2119
private readonly FormOptions _options;
2220
private Task<IFormCollection> _parsedFormTask;
@@ -32,7 +30,7 @@ public FormFeature(IFormCollection form)
3230
Form = form;
3331
}
3432
public FormFeature(HttpRequest request)
35-
: this(request, DefaultFormOptions)
33+
: this(request, FormOptions.Default)
3634
{
3735
}
3836

src/Microsoft.AspNetCore.Http/Features/FormOptions.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ namespace Microsoft.AspNetCore.Http.Features
88
{
99
public class FormOptions
1010
{
11+
public static readonly FormOptions Default = new FormOptions();
12+
1113
public const int DefaultMemoryBufferThreshold = 1024 * 64;
1214
public const int DefaultBufferBodyLengthLimit = 1024 * 1024 * 128;
1315
public const int DefaultMultipartBoundaryLengthLimit = 128;

src/Microsoft.AspNetCore.Http/HttpContextFactory.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public HttpContextFactory(IOptions<FormOptions> formOptions, IHttpContextAccesso
2424
throw new ArgumentNullException(nameof(formOptions));
2525
}
2626

27-
_formOptions = formOptions.Value;
27+
_formOptions = formOptions.Value ?? FormOptions.Default;
2828
_httpContextAccessor = httpContextAccessor;
2929
}
3030

@@ -35,15 +35,12 @@ public HttpContext Create(IFeatureCollection featureCollection)
3535
throw new ArgumentNullException(nameof(featureCollection));
3636
}
3737

38-
var httpContext = new DefaultHttpContext(featureCollection);
38+
var httpContext = new DefaultHttpContext(featureCollection, _formOptions);
3939
if (_httpContextAccessor != null)
4040
{
4141
_httpContextAccessor.HttpContext = httpContext;
4242
}
4343

44-
var formFeature = new FormFeature(httpContext.Request, _formOptions);
45-
featureCollection.Set<IFormFeature>(formFeature);
46-
4744
return httpContext;
4845
}
4946

src/Microsoft.AspNetCore.Http/Internal/DefaultHttpRequest.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,39 @@ public class DefaultHttpRequest : HttpRequest
1515
// Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624
1616
private readonly static Func<IFeatureCollection, IHttpRequestFeature> _nullRequestFeature = f => null;
1717
private readonly static Func<IFeatureCollection, IQueryFeature> _newQueryFeature = f => new QueryFeature(f);
18-
private readonly static Func<HttpRequest, IFormFeature> _newFormFeature = r => new FormFeature(r);
18+
private readonly static Func<(HttpRequest request, FormOptions options), IFormFeature> _newFormFeature = (r) => new FormFeature(r.request, r.options ?? FormOptions.Default);
1919
private readonly static Func<IFeatureCollection, IRequestCookiesFeature> _newRequestCookiesFeature = f => new RequestCookiesFeature(f);
2020

21+
private FormOptions _formOptions;
2122
private HttpContext _context;
2223
private FeatureReferences<FeatureInterfaces> _features;
2324

2425
public DefaultHttpRequest(HttpContext context)
26+
: this (context, context.Features.Revision, context.Features, FormOptions.Default)
2527
{
26-
Initialize(context);
2728
}
2829

29-
public virtual void Initialize(HttpContext context)
30+
internal DefaultHttpRequest(HttpContext context, int revision, IFeatureCollection features, FormOptions formOptions)
3031
{
3132
_context = context;
32-
_features = new FeatureReferences<FeatureInterfaces>(context.Features);
33+
Initialize(features, revision, formOptions);
34+
}
35+
36+
public virtual void Initialize(HttpContext context)
37+
{
38+
Initialize(context.Features, context.Features.Revision, FormOptions.Default);
39+
}
40+
41+
private void Initialize(IFeatureCollection features, int revision, FormOptions formOptions)
42+
{
43+
_features = new FeatureReferences<FeatureInterfaces>(features, revision);
44+
_formOptions = formOptions;
3345
}
3446

3547
public virtual void Uninitialize()
3648
{
3749
_context = null;
50+
_formOptions = null;
3851
_features = default(FeatureReferences<FeatureInterfaces>);
3952
}
4053

@@ -47,7 +60,7 @@ public virtual void Uninitialize()
4760
_features.Fetch(ref _features.Cache.Query, _newQueryFeature);
4861

4962
private IFormFeature FormFeature =>
50-
_features.Fetch(ref _features.Cache.Form, this, _newFormFeature);
63+
_features.Fetch(ref _features.Cache.Form, (this, _formOptions), _newFormFeature);
5164

5265
private IRequestCookiesFeature RequestCookiesFeature =>
5366
_features.Fetch(ref _features.Cache.Cookies, _newRequestCookiesFeature);

src/Microsoft.AspNetCore.Http/Internal/DefaultHttpResponse.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,25 @@ public class DefaultHttpResponse : HttpResponse
1919
private FeatureReferences<FeatureInterfaces> _features;
2020

2121
public DefaultHttpResponse(HttpContext context)
22+
: this(context, context.Features.Revision, context.Features)
2223
{
23-
Initialize(context);
24+
}
25+
26+
internal DefaultHttpResponse(HttpContext context, int revision, IFeatureCollection features)
27+
{
28+
_context = context;
29+
Initialize(features, revision);
2430
}
2531

2632
public virtual void Initialize(HttpContext context)
2733
{
2834
_context = context;
29-
_features = new FeatureReferences<FeatureInterfaces>(context.Features);
35+
Initialize(context.Features, context.Features.Revision);
36+
}
37+
38+
private void Initialize(IFeatureCollection features, int revision)
39+
{
40+
_features = new FeatureReferences<FeatureInterfaces>(features, revision);
3041
}
3142

3243
public virtual void Uninitialize()

test/Microsoft.AspNetCore.Http.Tests/DefaultHttpContextTests.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ public void UpdateFeatures_ClearsCachedFeatures()
159159

160160
// featurecollection is set. all cached interfaces are null.
161161
var context = new DefaultHttpContext(features);
162+
// Trigger initalization
163+
Assert.NotNull(context.Request);
162164
TestAllCachedFeaturesAreNull(context, features);
163165
Assert.Equal(3, features.Count());
164166

@@ -178,7 +180,9 @@ public void UpdateFeatures_ClearsCachedFeatures()
178180
newFeatures.Set<IHttpWebSocketFeature>(new TestHttpWebSocketFeature());
179181

180182
// featurecollection is set to newFeatures. all cached interfaces are null.
181-
context.Initialize(newFeatures);
183+
context.Initialize(newFeatures, FormOptions.Default);
184+
// Trigger initalization
185+
Assert.NotNull(context.Request);
182186
TestAllCachedFeaturesAreNull(context, newFeatures);
183187
Assert.Equal(3, newFeatures.Count());
184188

0 commit comments

Comments
 (0)