Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing
public class RouteValueDictionary : IDictionary<string, object?>, IReadOnlyDictionary<string, object?>
{
// 4 is a good default capacity here because that leaves enough space for area/controller/action/id
private const int DefaultCapacity = 4;
private readonly int DefaultCapacity = 4;

internal KeyValuePair<string, object?>[] _arrayStorage;
internal PropertyStorage? _propertyStorage;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
<ItemGroup>
<Reference Include="BenchmarkDotNet" />
<Reference Include="Microsoft.AspNetCore.Http" />

<Compile Include="$(SharedSourceRoot)BenchmarkRunner\*.cs" />
</ItemGroup>

Expand Down
150 changes: 150 additions & 0 deletions src/Http/Http/perf/Microbenchmarks/SmallCapacityDictionaryBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// 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.Collections.Generic;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Internal.Dictionary;

namespace Microsoft.AspNetCore.Http
{
public class AdaptiveCapacityDictionaryBenchmark
{
private AdaptiveCapacityDictionary<string, string> _smallCapDict;
private AdaptiveCapacityDictionary<string, string> _smallCapDictFour;
private AdaptiveCapacityDictionary<string, string> _smallCapDictTen;
private Dictionary<string, string> _dict;
private Dictionary<string, string> _dictFour;
private Dictionary<string, string> _dictTen;

private KeyValuePair<string, string> _oneValue;
private List<KeyValuePair<string, string>> _fourValues;
private List<KeyValuePair<string, string>> _tenValues;

[IterationSetup]
public void Setup()
{
_oneValue = new KeyValuePair<string, string>("a", "b");

_fourValues = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("a", "b"),
new KeyValuePair<string, string>("c", "d"),
new KeyValuePair<string, string>("e", "f"),
new KeyValuePair<string, string>("g", "h"),
};

_tenValues = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("a", "b"),
new KeyValuePair<string, string>("c", "d"),
new KeyValuePair<string, string>("e", "f"),
new KeyValuePair<string, string>("g", "h"),
new KeyValuePair<string, string>("i", "j"),
new KeyValuePair<string, string>("k", "l"),
new KeyValuePair<string, string>("m", "n"),
new KeyValuePair<string, string>("o", "p"),
new KeyValuePair<string, string>("q", "r"),
new KeyValuePair<string, string>("s", "t"),
};

_smallCapDict = new AdaptiveCapacityDictionary<string, string>(capacity: 1, StringComparer.OrdinalIgnoreCase);
_smallCapDictFour = new AdaptiveCapacityDictionary<string, string>(capacity: 4, StringComparer.OrdinalIgnoreCase);
_smallCapDictTen = new AdaptiveCapacityDictionary<string, string>(capacity: 10, StringComparer.OrdinalIgnoreCase);
_dict = new Dictionary<string, string>(1, StringComparer.OrdinalIgnoreCase);
_dictFour = new Dictionary<string, string>(4, StringComparer.OrdinalIgnoreCase);
_dictTen = new Dictionary<string, string>(10, StringComparer.OrdinalIgnoreCase);
}

[Benchmark]
public void OneValue_SmallDict()
{
_smallCapDict[_oneValue.Key] = _oneValue.Value;
_ = _smallCapDict[_oneValue.Key];
}

[Benchmark]
public void OneValue_Dict()
{
_dict[_oneValue.Key] = _oneValue.Value;
_ = _dict[_oneValue.Key];
}

[Benchmark]
public void FourValues_SmallDict()
{
foreach (var val in _fourValues)
{
_smallCapDictFour[val.Key] = val.Value;
_ = _smallCapDictFour[val.Key];
}
}

[Benchmark]
public void FourValues_Dict()
{
foreach (var val in _fourValues)
{
_dictFour[val.Key] = val.Value;
_ = _dictFour[val.Key];
}
}

[Benchmark]
public void TenValues_SmallDict()
{
foreach (var val in _tenValues)
{
_smallCapDictTen[val.Key] = val.Value;
_ = _smallCapDictTen[val.Key];
}
}

[Benchmark]
public void TenValues_Dict()
{
foreach (var val in _tenValues)
{
_dictTen[val.Key] = val.Value;
_ = _dictTen[val.Key];
}
}

[Benchmark]
public void SmallDict()
{
_ = new AdaptiveCapacityDictionary<string, string>(capacity: 1);
}

[Benchmark]
public void Dict()
{
_ = new Dictionary<string, string>(capacity: 1);
}


[Benchmark]
public void SmallDictFour()
{
_ = new AdaptiveCapacityDictionary<string, string>(capacity: 4);
}

[Benchmark]
public void DictFour()
{
_ = new Dictionary<string, string>(capacity: 4);
}

[Benchmark]
public void SmallDictTen()
{
_ = new AdaptiveCapacityDictionary<string, string>(capacity: 10);
}

[Benchmark]
public void DictTen()
{
_ = new Dictionary<string, string>(capacity: 10);
}
}
}
23 changes: 14 additions & 9 deletions src/Http/Http/src/Internal/RequestCookieCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Primitives;
using Microsoft.AspNetCore.Internal.Dictionary;
using Microsoft.Net.Http.Headers;
using System.Linq;

namespace Microsoft.AspNetCore.Http
{
Expand All @@ -19,20 +21,21 @@ internal class RequestCookieCollection : IRequestCookieCollection
private static readonly IEnumerator<KeyValuePair<string, string>> EmptyIEnumeratorType = EmptyEnumerator;
private static readonly IEnumerator EmptyIEnumerator = EmptyEnumerator;

private Dictionary<string, string>? Store { get; set; }
private AdaptiveCapacityDictionary<string, string> Store { get; set; }

public RequestCookieCollection()
{
Store = new AdaptiveCapacityDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}

public RequestCookieCollection(Dictionary<string, string> store)
public RequestCookieCollection(int capacity)
{
Store = store;
Store = new AdaptiveCapacityDictionary<string, string>(capacity, StringComparer.OrdinalIgnoreCase);
}

public RequestCookieCollection(int capacity)
public RequestCookieCollection(Dictionary<string, string> store)
{
Store = new Dictionary<string, string>(capacity, StringComparer.OrdinalIgnoreCase);
Store = new AdaptiveCapacityDictionary<string, string>(store.ToList(), capacity: store.Count, StringComparer.OrdinalIgnoreCase);
}

public string? this[string key]
Expand Down Expand Up @@ -121,7 +124,9 @@ public bool TryGetValue(string key, [MaybeNullWhen(false)] out string? value)
value = null;
return false;
}
return Store.TryGetValue(key, out value);
var res = Store.TryGetValue(key, out var objValue);
value = objValue as string;
return res;
}

/// <summary>
Expand Down Expand Up @@ -172,10 +177,10 @@ IEnumerator IEnumerable.GetEnumerator()
public struct Enumerator : IEnumerator<KeyValuePair<string, string>>
{
// Do NOT make this readonly, or MoveNext will not work
private Dictionary<string, string>.Enumerator _dictionaryEnumerator;
private AdaptiveCapacityDictionary<string, string>.Enumerator _dictionaryEnumerator;
private bool _notEmpty;

internal Enumerator(Dictionary<string, string>.Enumerator dictionaryEnumerator)
internal Enumerator(AdaptiveCapacityDictionary<string, string>.Enumerator dictionaryEnumerator)
{
_dictionaryEnumerator = dictionaryEnumerator;
_notEmpty = true;
Expand All @@ -197,7 +202,7 @@ public KeyValuePair<string, string> Current
if (_notEmpty)
{
var current = _dictionaryEnumerator.Current;
return new KeyValuePair<string, string>(current.Key, current.Value);
return new KeyValuePair<string, string>(current.Key, (string)current.Value!);
}
return default(KeyValuePair<string, string>);
}
Expand Down
1 change: 1 addition & 0 deletions src/Http/Http/src/Microsoft.AspNetCore.Http.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<Compile Include="..\..\Shared\HttpRuleParser.cs" LinkBase="Internal" />
<Compile Include="..\..\Shared\HttpParseResult.cs" LinkBase="Internal" />
<Compile Include="..\..\WebUtilities\src\AspNetCoreTempDirectory.cs" LinkBase="Internal" />
<Compile Include="..\..\..\Shared\Dictionary\AdaptiveCapacityDictionary.cs" LinkBase="Internal" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/Http/Shared/CookieHeaderParserShared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.Net.Http.Headers
{
internal static class CookieHeaderParserShared
{
public static bool TryParseValues(StringValues values, Dictionary<string, string> store, bool enableCookieNameEncoding, bool supportsMultipleValues)
public static bool TryParseValues(StringValues values, IDictionary<string, string> store, bool enableCookieNameEncoding, bool supportsMultipleValues)
{
// If a parser returns an empty list, it means there was no value, but that's valid (e.g. "Accept: "). The caller
// can ignore the value.
Expand Down
35 changes: 19 additions & 16 deletions src/Security/Authentication/Cookies/samples/CookieSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,34 @@ public class Startup
public void ConfigureServices(IServiceCollection services)
{
// This can be removed after https://github.com/aspnet/IISIntegration/issues/371
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie();
//services.AddAuthentication(options =>
//{
// options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
//}).AddCookie();
}

public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
//app.UseAuthentication();

app.Run(async context =>
{
if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
{
var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") }, CookieAuthenticationDefaults.AuthenticationScheme));
await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);
var cookie = context.Request.Cookies[".AspNetCore.Cookies"];

await context.Response.WriteAsync($"Hello World {cookie}");
//if (!context.User.Identities.Any(identity => identity.IsAuthenticated))
//{
// var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "bob") }, CookieAuthenticationDefaults.AuthenticationScheme));
// await context.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);

context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello First timer");
return;
}
// context.Response.ContentType = "text/plain";
// await context.Response.WriteAsync("Hello First timer");
// return;
//}

context.Response.ContentType = "text/plain";
await context.Response.WriteAsync("Hello old timer");
//context.Response.ContentType = "text/plain";
//await context.Response.WriteAsync("Hello old timer");
});
}
}
Expand Down
Loading