diff --git a/AspNetCore.slnx b/AspNetCore.slnx
index b4b5b19b9662..78284eb90b2c 100644
--- a/AspNetCore.slnx
+++ b/AspNetCore.slnx
@@ -334,6 +334,7 @@
+
@@ -357,6 +358,7 @@
+
diff --git a/src/Http/HttpAbstractions.slnf b/src/Http/HttpAbstractions.slnf
index 2d4c235792cf..69a4e98a5599 100644
--- a/src/Http/HttpAbstractions.slnf
+++ b/src/Http/HttpAbstractions.slnf
@@ -32,6 +32,7 @@
"src\\Http\\Http\\src\\Microsoft.AspNetCore.Http.csproj",
"src\\Http\\Http\\test\\Microsoft.AspNetCore.Http.Tests.csproj",
"src\\Http\\Metadata\\src\\Microsoft.AspNetCore.Metadata.csproj",
+ "src\\Http\\Owin\\benchmarks\\Microsoft.AspNetCore.Owin.Microbenchmarks\\Microsoft.AspNetCore.Owin.Microbenchmarks.csproj",
"src\\Http\\Owin\\src\\Microsoft.AspNetCore.Owin.csproj",
"src\\Http\\Owin\\test\\Microsoft.AspNetCore.Owin.Tests.csproj",
"src\\Http\\Routing.Abstractions\\src\\Microsoft.AspNetCore.Routing.Abstractions.csproj",
@@ -39,15 +40,16 @@
"src\\Http\\Routing\\perf\\Microbenchmarks\\Microsoft.AspNetCore.Routing.Microbenchmarks.csproj",
"src\\Http\\Routing\\src\\Microsoft.AspNetCore.Routing.csproj",
"src\\Http\\Routing\\test\\FunctionalTests\\Microsoft.AspNetCore.Routing.FunctionalTests.csproj",
+ "src\\Http\\Routing\\test\\UnitTests\\Microsoft.AspNetCore.Routing.Tests.csproj",
"src\\Http\\Routing\\test\\testassets\\Benchmarks\\Benchmarks.csproj",
"src\\Http\\Routing\\test\\testassets\\RoutingSandbox\\RoutingSandbox.csproj",
"src\\Http\\Routing\\test\\testassets\\RoutingWebSite\\RoutingWebSite.csproj",
- "src\\Http\\Routing\\test\\UnitTests\\Microsoft.AspNetCore.Routing.Tests.csproj",
- "src\\Http\\samples\\MinimalSample\\MinimalSample.csproj",
- "src\\Http\\samples\\SampleApp\\HttpAbstractions.SampleApp.csproj",
"src\\Http\\WebUtilities\\perf\\Microbenchmarks\\Microsoft.AspNetCore.WebUtilities.Microbenchmarks.csproj",
"src\\Http\\WebUtilities\\src\\Microsoft.AspNetCore.WebUtilities.csproj",
"src\\Http\\WebUtilities\\test\\Microsoft.AspNetCore.WebUtilities.Tests.csproj",
+ "src\\Http\\samples\\MinimalSampleOwin\\MinimalSampleOwin.csproj",
+ "src\\Http\\samples\\MinimalSample\\MinimalSample.csproj",
+ "src\\Http\\samples\\SampleApp\\HttpAbstractions.SampleApp.csproj",
"src\\Middleware\\CORS\\src\\Microsoft.AspNetCore.Cors.csproj",
"src\\Middleware\\Diagnostics.Abstractions\\src\\Microsoft.AspNetCore.Diagnostics.Abstractions.csproj",
"src\\Middleware\\Diagnostics\\src\\Microsoft.AspNetCore.Diagnostics.csproj",
@@ -72,4 +74,4 @@
"src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj"
]
}
-}
+}
\ No newline at end of file
diff --git a/src/Http/Owin/benchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks/AssemblyInfo.cs b/src/Http/Owin/benchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks/AssemblyInfo.cs
new file mode 100644
index 000000000000..09f49228e9e6
--- /dev/null
+++ b/src/Http/Owin/benchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark]
diff --git a/src/Http/Owin/benchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks/Benchmarks/OwinEnvironmentBenchmark.cs b/src/Http/Owin/benchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks/Benchmarks/OwinEnvironmentBenchmark.cs
new file mode 100644
index 000000000000..0e2eead9e260
--- /dev/null
+++ b/src/Http/Owin/benchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks/Benchmarks/OwinEnvironmentBenchmark.cs
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using BenchmarkDotNet.Attributes;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.AspNetCore.Owin.Microbenchmarks.Benchmarks;
+
+[MemoryDiagnoser]
+public class OwinEnvironmentBenchmark
+{
+ const int RequestCount = 10000;
+
+ RequestDelegate _noOperationRequestDelegate;
+ RequestDelegate _accessPortsRequestDelegate;
+ RequestDelegate _accessHeadersRequestDelegate;
+
+ HttpContext _defaultHttpContext;
+ HttpContext _httpContextWithHeaders;
+
+ [GlobalSetup]
+ public void GlobalSetup()
+ {
+ _noOperationRequestDelegate = BuildRequestDelegate();
+ _accessPortsRequestDelegate = BuildRequestDelegate(beforeOwinInvokeAction: env =>
+ {
+ _ = env.TryGetValue("server.LocalPort", out var localPort);
+ _ = env.TryGetValue("server.RemotePort", out var remotePort);
+ });
+ _accessHeadersRequestDelegate = BuildRequestDelegate(
+ beforeOwinInvokeAction: env =>
+ {
+ _ = env.TryGetValue("owin.RequestHeaders", out var requestHeaders);
+ },
+ afterOwinInvokeAction: env =>
+ {
+ _ = env.TryGetValue("owin.ResponseHeaders", out var responseHeaders);
+ }
+ );
+
+ _defaultHttpContext = new DefaultHttpContext();
+
+ _httpContextWithHeaders = new DefaultHttpContext();
+ _httpContextWithHeaders.Request.Headers["CustomRequestHeader1"] = "CustomRequestValue";
+ _httpContextWithHeaders.Request.Headers["CustomRequestHeader2"] = "CustomRequestValue";
+ _httpContextWithHeaders.Response.Headers["CustomResponseHeader1"] = "CustomResponseValue";
+ _httpContextWithHeaders.Response.Headers["CustomResponseHeader2"] = "CustomResponseValue";
+ }
+
+ [Benchmark]
+ public async Task OwinRequest_NoOperation()
+ {
+ foreach (var i in Enumerable.Range(0, RequestCount))
+ {
+ await _noOperationRequestDelegate(_defaultHttpContext);
+ }
+ }
+
+ [Benchmark]
+ public async Task OwinRequest_AccessPorts()
+ {
+ foreach (var i in Enumerable.Range(0, RequestCount))
+ {
+ await _accessPortsRequestDelegate(_defaultHttpContext);
+ }
+ }
+
+ [Benchmark]
+ public async Task OwinRequest_AccessHeaders()
+ {
+ foreach (var i in Enumerable.Range(0, RequestCount))
+ {
+ await _accessHeadersRequestDelegate(_httpContextWithHeaders);
+ }
+ }
+
+ private static RequestDelegate BuildRequestDelegate(
+ Action> beforeOwinInvokeAction = null,
+ Action> afterOwinInvokeAction = null)
+ {
+ var serviceProvider = new ServiceCollection().BuildServiceProvider();
+ var builder = new ApplicationBuilder(serviceProvider);
+
+ return builder.UseOwin(addToPipeline =>
+ {
+ addToPipeline(next =>
+ {
+ return async env =>
+ {
+ if (beforeOwinInvokeAction is not null)
+ {
+ beforeOwinInvokeAction(env);
+ }
+
+ await next(env);
+
+ if (afterOwinInvokeAction is not null)
+ {
+ afterOwinInvokeAction(env);
+ }
+ };
+ });
+ }).Build();
+ }
+}
diff --git a/src/Http/Owin/benchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks.csproj b/src/Http/Owin/benchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks.csproj
new file mode 100644
index 000000000000..5ca0b8f6e5da
--- /dev/null
+++ b/src/Http/Owin/benchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks/Microsoft.AspNetCore.Owin.Microbenchmarks.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ $(DefaultNetCoreTargetFramework)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Http/Owin/src/DictionaryStringArrayWrapper.cs b/src/Http/Owin/src/DictionaryStringArrayWrapper.cs
index 00a726a6f682..e3b3e795458b 100644
--- a/src/Http/Owin/src/DictionaryStringArrayWrapper.cs
+++ b/src/Http/Owin/src/DictionaryStringArrayWrapper.cs
@@ -10,16 +10,16 @@ namespace Microsoft.AspNetCore.Owin;
internal sealed class DictionaryStringArrayWrapper : IDictionary
{
+ public readonly IHeaderDictionary Inner;
+
public DictionaryStringArrayWrapper(IHeaderDictionary inner)
{
Inner = inner;
}
- public readonly IHeaderDictionary Inner;
-
- private static KeyValuePair Convert(KeyValuePair item) => new KeyValuePair(item.Key, item.Value);
+ private static KeyValuePair Convert(KeyValuePair item) => new(item.Key, item.Value);
- private static KeyValuePair Convert(KeyValuePair item) => new KeyValuePair(item.Key, item.Value);
+ private static KeyValuePair Convert(KeyValuePair item) => new(item.Key, item.Value);
private string[] Convert(StringValues item) => item;
@@ -55,9 +55,11 @@ void ICollection>.CopyTo(KeyValuePair Inner.Select(Convert).GetEnumerator();
+ public ConvertingEnumerator GetEnumerator() => new ConvertingEnumerator(Inner);
+
+ IEnumerator> IEnumerable>.GetEnumerator() => new ConvertingEnumerator(Inner);
- IEnumerator> IEnumerable>.GetEnumerator() => Inner.Select(Convert).GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => new ConvertingEnumerator(Inner);
bool ICollection>.Remove(KeyValuePair item) => Inner.Remove(Convert(item));
@@ -74,4 +76,40 @@ bool IDictionary.TryGetValue(string key, out string[] value)
value = default(StringValues);
return false;
}
+
+ public struct ConvertingEnumerator : IEnumerator>, IEnumerator
+ {
+ private IEnumerator> _inner;
+ private KeyValuePair _current;
+
+ internal ConvertingEnumerator(IDictionary inner)
+ {
+ _inner = inner.GetEnumerator();
+ _current = default;
+ }
+
+ public void Dispose()
+ {
+ _inner?.Dispose();
+ _inner = null;
+ }
+
+ public bool MoveNext()
+ {
+ if (!_inner.MoveNext())
+ {
+ _current = default;
+ return false;
+ }
+
+ _current = Convert(_inner.Current);
+ return true;
+ }
+
+ public KeyValuePair Current => _current;
+
+ object IEnumerator.Current => Current;
+
+ void IEnumerator.Reset() => throw new NotSupportedException();
+ }
}
diff --git a/src/Http/Owin/src/DictionaryStringValuesWrapper.cs b/src/Http/Owin/src/DictionaryStringValuesWrapper.cs
index 50ab189ba5c2..171680772949 100644
--- a/src/Http/Owin/src/DictionaryStringValuesWrapper.cs
+++ b/src/Http/Owin/src/DictionaryStringValuesWrapper.cs
@@ -11,16 +11,16 @@ namespace Microsoft.AspNetCore.Owin;
internal sealed class DictionaryStringValuesWrapper : IHeaderDictionary
{
+ public readonly IDictionary Inner;
+
public DictionaryStringValuesWrapper(IDictionary inner)
{
Inner = inner;
}
- public readonly IDictionary Inner;
-
- private static KeyValuePair Convert(KeyValuePair item) => new KeyValuePair(item.Key, item.Value);
+ private static KeyValuePair Convert(KeyValuePair item) => new(item.Key, item.Value);
- private static KeyValuePair Convert(KeyValuePair item) => new KeyValuePair(item.Key, item.Value);
+ private static KeyValuePair Convert(KeyValuePair item) => new(item.Key, item.Value);
private StringValues Convert(string[] item) => item;
@@ -100,9 +100,11 @@ void ICollection>.CopyTo(KeyValuePair Inner.Select(Convert).GetEnumerator();
+ public ConvertingEnumerator GetEnumerator() => new ConvertingEnumerator(Inner);
+
+ IEnumerator> IEnumerable>.GetEnumerator() => new ConvertingEnumerator(Inner);
- IEnumerator> IEnumerable>.GetEnumerator() => Inner.Select(Convert).GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => new ConvertingEnumerator(Inner);
bool ICollection>.Remove(KeyValuePair item) => Inner.Remove(Convert(item));
@@ -119,4 +121,40 @@ bool IDictionary.TryGetValue(string key, out StringValues
value = default(StringValues);
return false;
}
+
+ public struct ConvertingEnumerator : IEnumerator>, IEnumerator
+ {
+ private IEnumerator> _inner;
+ private KeyValuePair _current;
+
+ internal ConvertingEnumerator(IDictionary inner)
+ {
+ _inner = inner.GetEnumerator();
+ _current = default;
+ }
+
+ public void Dispose()
+ {
+ _inner?.Dispose();
+ _inner = null;
+ }
+
+ public bool MoveNext()
+ {
+ if (!_inner.MoveNext())
+ {
+ _current = default;
+ return false;
+ }
+
+ _current = Convert(_inner.Current);
+ return true;
+ }
+
+ public KeyValuePair Current => _current;
+
+ object IEnumerator.Current => Current;
+
+ void IEnumerator.Reset() => throw new NotSupportedException();
+ }
}
diff --git a/src/Http/Owin/src/OwinEnvironment.cs b/src/Http/Owin/src/OwinEnvironment.cs
index cc2995a10afe..32322fb4d0b2 100644
--- a/src/Http/Owin/src/OwinEnvironment.cs
+++ b/src/Http/Owin/src/OwinEnvironment.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
+using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Net;
@@ -28,8 +29,8 @@ namespace Microsoft.AspNetCore.Owin;
///
public class OwinEnvironment : IDictionary
{
+ private readonly OwinEntries _owinEntries;
private readonly HttpContext _context;
- private readonly IDictionary _entries;
///
/// Initializes a new instance of .
@@ -47,65 +48,7 @@ public OwinEnvironment(HttpContext context)
}
_context = context;
- _entries = new Dictionary()
- {
- { OwinConstants.RequestProtocol, new FeatureMap(feature => feature.Protocol, () => string.Empty, (feature, value) => feature.Protocol = Convert.ToString(value, CultureInfo.InvariantCulture)) },
- { OwinConstants.RequestScheme, new FeatureMap(feature => feature.Scheme, () => string.Empty, (feature, value) => feature.Scheme = Convert.ToString(value, CultureInfo.InvariantCulture)) },
- { OwinConstants.RequestMethod, new FeatureMap(feature => feature.Method, () => string.Empty, (feature, value) => feature.Method = Convert.ToString(value, CultureInfo.InvariantCulture)) },
- { OwinConstants.RequestPathBase, new FeatureMap(feature => feature.PathBase, () => string.Empty, (feature, value) => feature.PathBase = Convert.ToString(value, CultureInfo.InvariantCulture)) },
- { OwinConstants.RequestPath, new FeatureMap(feature => feature.Path, () => string.Empty, (feature, value) => feature.Path = Convert.ToString(value, CultureInfo.InvariantCulture)) },
- { OwinConstants.RequestQueryString, new FeatureMap(feature => Utilities.RemoveQuestionMark(feature.QueryString), () => string.Empty,
- (feature, value) => feature.QueryString = Utilities.AddQuestionMark(Convert.ToString(value, CultureInfo.InvariantCulture))) },
- { OwinConstants.RequestHeaders, new FeatureMap(feature => Utilities.MakeDictionaryStringArray(feature.Headers), (feature, value) => feature.Headers = Utilities.MakeHeaderDictionary((IDictionary)value)) },
- { OwinConstants.RequestBody, new FeatureMap(feature => feature.Body, () => Stream.Null, (feature, value) => feature.Body = (Stream)value) },
- { OwinConstants.RequestUser, new FeatureMap(feature => feature.User, () => null, (feature, value) => feature.User = (ClaimsPrincipal)value) },
-
- { OwinConstants.ResponseStatusCode, new FeatureMap(feature => feature.StatusCode, () => 200, (feature, value) => feature.StatusCode = Convert.ToInt32(value, CultureInfo.InvariantCulture)) },
- { OwinConstants.ResponseReasonPhrase, new FeatureMap(feature => feature.ReasonPhrase, (feature, value) => feature.ReasonPhrase = Convert.ToString(value, CultureInfo.InvariantCulture)) },
- { OwinConstants.ResponseHeaders, new FeatureMap(feature => Utilities.MakeDictionaryStringArray(feature.Headers), (feature, value) => feature.Headers = Utilities.MakeHeaderDictionary((IDictionary)value)) },
- { OwinConstants.ResponseBody, new FeatureMap(feature => feature.Stream, () => Stream.Null, (feature, value) => context.Response.Body = (Stream)value) }, // DefaultHttpResponse.Body.Set has built in logic to handle replacing the feature.
- { OwinConstants.CommonKeys.OnSendingHeaders, new FeatureMap(
- feature => new Action, object>((cb, state) => {
- feature.OnStarting(s =>
- {
- cb(s);
- return Task.CompletedTask;
- }, state);
- }))
- },
-
- { OwinConstants.CommonKeys.ConnectionId, new FeatureMap(feature => feature.ConnectionId,
- (feature, value) => feature.ConnectionId = Convert.ToString(value, CultureInfo.InvariantCulture)) },
-
- { OwinConstants.CommonKeys.LocalPort, new FeatureMap(feature => feature.LocalPort.ToString(CultureInfo.InvariantCulture),
- (feature, value) => feature.LocalPort = Convert.ToInt32(value, CultureInfo.InvariantCulture)) },
- { OwinConstants.CommonKeys.RemotePort, new FeatureMap(feature => feature.RemotePort.ToString(CultureInfo.InvariantCulture),
- (feature, value) => feature.RemotePort = Convert.ToInt32(value, CultureInfo.InvariantCulture)) },
-
- { OwinConstants.CommonKeys.LocalIpAddress, new FeatureMap(feature => feature.LocalIpAddress.ToString(),
- (feature, value) => feature.LocalIpAddress = IPAddress.Parse(Convert.ToString(value, CultureInfo.InvariantCulture))) },
- { OwinConstants.CommonKeys.RemoteIpAddress, new FeatureMap(feature => feature.RemoteIpAddress.ToString(),
- (feature, value) => feature.RemoteIpAddress = IPAddress.Parse(Convert.ToString(value, CultureInfo.InvariantCulture))) },
-
- { OwinConstants.SendFiles.SendAsync, new FeatureMap(feature => new SendFileFunc(feature.SendFileAsync)) },
-
- { OwinConstants.Security.User, new FeatureMap(feature => feature.User,
- ()=> null, (feature, value) => feature.User = Utilities.MakeClaimsPrincipal((IPrincipal)value),
- () => new HttpAuthenticationFeature())
- },
-
- { OwinConstants.RequestId, new FeatureMap(feature => feature.TraceIdentifier,
- ()=> null, (feature, value) => feature.TraceIdentifier = (string)value,
- () => new HttpRequestIdentifierFeature())
- }
- };
-
- // owin.CallCancelled is required but the feature may not be present.
- if (context.Features.Get() != null)
- {
- _entries[OwinConstants.CallCancelled] = new FeatureMap(feature => feature.RequestAborted);
- }
- else if (!_context.Items.ContainsKey(OwinConstants.CallCancelled))
+ if (!_context.Items.ContainsKey(OwinConstants.CallCancelled))
{
_context.Items[OwinConstants.CallCancelled] = CancellationToken.None;
}
@@ -116,57 +59,37 @@ public OwinEnvironment(HttpContext context)
_context.Items[OwinConstants.OwinVersion] = "1.0";
}
- if (context.Request.IsHttps)
- {
- _entries.Add(OwinConstants.CommonKeys.ClientCertificate, new FeatureMap(feature => feature.ClientCertificate,
- (feature, value) => feature.ClientCertificate = (X509Certificate2)value));
- _entries.Add(OwinConstants.CommonKeys.LoadClientCertAsync, new FeatureMap(
- feature => new Func(() => feature.GetClientCertificateAsync(CancellationToken.None))));
- }
-
- if (context.WebSockets.IsWebSocketRequest)
- {
- _entries.Add(OwinConstants.WebSocket.AcceptAlt, new FeatureMap(feature => new WebSocketAcceptAlt(feature.AcceptAsync)));
- }
-
_context.Items[typeof(HttpContext).FullName] = _context; // Store for lookup when we transition back out of OWIN
+
+ _owinEntries = new(context);
}
// Public in case there's a new/custom feature interface that needs to be added.
///
/// Get the environment's feature maps.
///
- public IDictionary FeatureMaps
- {
- get { return _entries; }
- }
+ public IDictionary FeatureMaps => _owinEntries.GetFeatureMaps();
void IDictionary.Add(string key, object value)
{
- if (_entries.ContainsKey(key))
+ if (_owinEntries.ContainsKey(key))
{
throw new InvalidOperationException("Key already present");
}
_context.Items.Add(key, value);
}
- bool IDictionary.ContainsKey(string key)
- {
- return ((IDictionary)this).TryGetValue(key, out _);
- }
+ bool IDictionary.ContainsKey(string key) => ((IDictionary)this).TryGetValue(key, out _);
ICollection IDictionary.Keys
- {
- get
- {
- return _entries.Where(pair => pair.Value.TryGet(_context, out _))
- .Select(pair => pair.Key).Concat(_context.Items.Keys.Select(key => Convert.ToString(key, CultureInfo.InvariantCulture))).ToList();
- }
- }
+ => _owinEntries
+ .Where(pair => pair.Value.TryGet(_context, out _)).Select(pair => pair.Key)
+ .Concat(_context.Items.Keys.Select(key => Convert.ToString(key, CultureInfo.InvariantCulture)))
+ .ToList();
bool IDictionary.Remove(string key)
{
- if (_entries.Remove(key))
+ if (_owinEntries.Remove(key))
{
return true;
}
@@ -175,8 +98,7 @@ bool IDictionary.Remove(string key)
bool IDictionary.TryGetValue(string key, out object value)
{
- FeatureMap entry;
- if (_entries.TryGetValue(key, out entry) && entry.TryGet(_context, out value))
+ if (_owinEntries.TryGetValue(key, out var entry) && entry.TryGet(_context, out value))
{
return true;
}
@@ -194,7 +116,7 @@ object IDictionary.this[string key]
{
FeatureMap entry;
object value;
- if (_entries.TryGetValue(key, out entry) && entry.TryGet(_context, out value))
+ if (_owinEntries.TryGetValue(key, out entry) && entry.TryGet(_context, out value))
{
return value;
}
@@ -207,7 +129,7 @@ object IDictionary.this[string key]
set
{
FeatureMap entry;
- if (_entries.TryGetValue(key, out entry))
+ if (_owinEntries.TryGetValue(key, out entry))
{
if (entry.CanSet)
{
@@ -215,7 +137,7 @@ object IDictionary.this[string key]
}
else
{
- _entries.Remove(key);
+ _owinEntries.Remove(key);
if (value != null)
{
_context.Items[key] = value;
@@ -243,7 +165,7 @@ void ICollection>.Add(KeyValuePair
void ICollection>.Clear()
{
- _entries.Clear();
+ _owinEntries.Clear();
_context.Items.Clear();
}
@@ -256,7 +178,7 @@ void ICollection>.CopyTo(KeyValuePair array.Length)
+ if (arrayIndex + _owinEntries.Count + _context.Items.Count > array.Length)
{
throw new ArgumentException("Not enough available space in array", nameof(array));
}
@@ -270,7 +192,7 @@ void ICollection>.CopyTo(KeyValuePair>.Count
{
- get { return _entries.Count + _context.Items.Count; }
+ get { return _owinEntries.Count + _context.Items.Count; }
}
bool ICollection>.IsReadOnly
@@ -286,7 +208,7 @@ bool ICollection>.Remove(KeyValuePair
public IEnumerator> GetEnumerator()
{
- foreach (var entryPair in _entries)
+ foreach (var entryPair in _owinEntries)
{
object value;
if (entryPair.Value.TryGet(_context, out value))
@@ -478,4 +400,229 @@ public FeatureMap(Func getter, Func