#426 Move IHeaderDictionary to Features to reduce wrapping.

This commit is contained in:
Chris R 2015-10-08 08:36:27 -07:00
parent 8ecb147332
commit 3741d38691
15 changed files with 61 additions and 69 deletions

View File

@ -1,34 +0,0 @@
// 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.Collections.Generic;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Http
{
/// <summary>
/// Represents request and response headers
/// </summary>
public interface IHeaderDictionary : IReadableStringCollection, IDictionary<string, StringValues>
{
// This property is duplicated to resolve an ambiguity between IReadableStringCollection and IDictionary<string, StringValues>
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <returns>The stored value, or StringValues.Empty if the key is not present.</returns>
new StringValues this[string key] { get; set; }
// This property is duplicated to resolve an ambiguity between IReadableStringCollection.Count and IDictionary<string, StringValues>.Count
/// <summary>
/// Gets the number of elements contained in the collection.
/// </summary>
new int Count { get; }
// This property is duplicated to resolve an ambiguity between IReadableStringCollection.Keys and IDictionary<string, StringValues>.Keys
/// <summary>
/// Gets a collection containing the keys.
/// </summary>
new ICollection<string> Keys { get; }
}
}

View File

@ -0,0 +1,21 @@
// 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.Collections.Generic;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Http
{
/// <summary>
/// Represents request and response headers
/// </summary>
public interface IHeaderDictionary : IDictionary<string, StringValues>
{
/// <summary>
/// IHeaderDictionary has a different indexer contract than IDictionary, where it will return StringValues.Empty for missing entries.
/// </summary>
/// <param name="key"></param>
/// <returns>The stored value, or StringValues.Empty if the key is not present.</returns>
new StringValues this[string key] { get; set; }
}
}

View File

@ -1,9 +1,7 @@
// 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.Collections.Generic;
using System.IO;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Http.Features
{
@ -15,7 +13,7 @@ namespace Microsoft.AspNet.Http.Features
string PathBase { get; set; }
string Path { get; set; }
string QueryString { get; set; }
IDictionary<string, StringValues> Headers { get; set; }
IHeaderDictionary Headers { get; set; }
Stream Body { get; set; }
}
}

View File

@ -2,10 +2,8 @@
// 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 System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Http.Features
{
@ -13,7 +11,7 @@ namespace Microsoft.AspNet.Http.Features
{
int StatusCode { get; set; }
string ReasonPhrase { get; set; }
IDictionary<string, StringValues> Headers { get; set; }
IHeaderDictionary Headers { get; set; }
Stream Body { get; set; }
bool HasStarted { get; }
void OnStarting(Func<object, Task> callback, object state);

View File

@ -123,7 +123,7 @@ namespace Microsoft.AspNet.Http.Internal
public override IHeaderDictionary Headers
{
get { return new HeaderDictionary(HttpRequestFeature.Headers); }
get { return HttpRequestFeature.Headers; }
}
public override IReadableStringCollection Cookies

View File

@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Http.Internal
public override IHeaderDictionary Headers
{
get { return new HeaderDictionary(HttpResponseFeature.Headers); }
get { return HttpResponseFeature.Headers; }
}
public override Stream Body

View File

@ -1,10 +1,8 @@
// 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 System.IO;
using Microsoft.Extensions.Primitives;
using Microsoft.AspNet.Http.Internal;
namespace Microsoft.AspNet.Http.Features.Internal
{
@ -12,7 +10,7 @@ namespace Microsoft.AspNet.Http.Features.Internal
{
public HttpRequestFeature()
{
Headers = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase);
Headers = new HeaderDictionary();
Body = Stream.Null;
Protocol = string.Empty;
Scheme = string.Empty;
@ -28,7 +26,7 @@ namespace Microsoft.AspNet.Http.Features.Internal
public string PathBase { get; set; }
public string Path { get; set; }
public string QueryString { get; set; }
public IDictionary<string, StringValues> Headers { get; set; }
public IHeaderDictionary Headers { get; set; }
public Stream Body { get; set; }
}
}

View File

@ -2,10 +2,9 @@
// 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 System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Primitives;
using Microsoft.AspNet.Http.Internal;
namespace Microsoft.AspNet.Http.Features.Internal
{
@ -14,7 +13,7 @@ namespace Microsoft.AspNet.Http.Features.Internal
public HttpResponseFeature()
{
StatusCode = 200;
Headers = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase);
Headers = new HeaderDictionary();
Body = Stream.Null;
}
@ -22,7 +21,7 @@ namespace Microsoft.AspNet.Http.Features.Internal
public string ReasonPhrase { get; set; }
public IDictionary<string, StringValues> Headers { get; set; }
public IHeaderDictionary Headers { get; set; }
public Stream Body { get; set; }

View File

@ -4,18 +4,19 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Owin
{
internal class DictionaryStringArrayWrapper : IDictionary<string, string[]>
{
public DictionaryStringArrayWrapper(IDictionary<string, StringValues> inner)
public DictionaryStringArrayWrapper(IHeaderDictionary inner)
{
Inner = inner;
}
public readonly IDictionary<string, StringValues> Inner;
public readonly IHeaderDictionary Inner;
private KeyValuePair<string, StringValues> Convert(KeyValuePair<string, string[]> item) => new KeyValuePair<string, StringValues>(item.Key, item.Value);
@ -27,7 +28,7 @@ namespace Microsoft.AspNet.Owin
string[] IDictionary<string, string[]>.this[string key]
{
get { return Inner[key]; }
get { return ((IDictionary<string, StringValues>)Inner)[key]; }
set { Inner[key] = value; }
}

View File

@ -4,11 +4,12 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNet.Owin
{
internal class DictionaryStringValuesWrapper : IDictionary<string, StringValues>
internal class DictionaryStringValuesWrapper : IHeaderDictionary
{
public DictionaryStringValuesWrapper(IDictionary<string, string[]> inner)
{
@ -25,6 +26,16 @@ namespace Microsoft.AspNet.Owin
private string[] Convert(StringValues item) => item;
StringValues IHeaderDictionary.this[string key]
{
get
{
string[] values;
return Inner.TryGetValue(key, out values) ? values : null;
}
set { Inner[key] = value; }
}
StringValues IDictionary<string, StringValues>.this[string key]
{
get { return Inner[key]; }

View File

@ -56,13 +56,13 @@ namespace Microsoft.AspNet.Owin
{ OwinConstants.RequestPath, new FeatureMap<IHttpRequestFeature>(feature => feature.Path, () => string.Empty, (feature, value) => feature.Path = Convert.ToString(value)) },
{ OwinConstants.RequestQueryString, new FeatureMap<IHttpRequestFeature>(feature => Utilities.RemoveQuestionMark(feature.QueryString), () => string.Empty,
(feature, value) => feature.QueryString = Utilities.AddQuestionMark(Convert.ToString(value))) },
{ OwinConstants.RequestHeaders, new FeatureMap<IHttpRequestFeature>(feature => Utilities.MakeDictionaryStringArray(feature.Headers), (feature, value) => feature.Headers = Utilities.MakeDictionaryStringValues((IDictionary<string, string[]>)value)) },
{ OwinConstants.RequestHeaders, new FeatureMap<IHttpRequestFeature>(feature => Utilities.MakeDictionaryStringArray(feature.Headers), (feature, value) => feature.Headers = Utilities.MakeHeaderDictionary((IDictionary<string, string[]>)value)) },
{ OwinConstants.RequestBody, new FeatureMap<IHttpRequestFeature>(feature => feature.Body, () => Stream.Null, (feature, value) => feature.Body = (Stream)value) },
{ OwinConstants.RequestUser, new FeatureMap<IHttpAuthenticationFeature>(feature => feature.User, () => null, (feature, value) => feature.User = (ClaimsPrincipal)value) },
{ OwinConstants.ResponseStatusCode, new FeatureMap<IHttpResponseFeature>(feature => feature.StatusCode, () => 200, (feature, value) => feature.StatusCode = Convert.ToInt32(value)) },
{ OwinConstants.ResponseReasonPhrase, new FeatureMap<IHttpResponseFeature>(feature => feature.ReasonPhrase, (feature, value) => feature.ReasonPhrase = Convert.ToString(value)) },
{ OwinConstants.ResponseHeaders, new FeatureMap<IHttpResponseFeature>(feature => Utilities.MakeDictionaryStringArray(feature.Headers), (feature, value) => feature.Headers = Utilities.MakeDictionaryStringValues((IDictionary<string, string[]>)value)) },
{ OwinConstants.ResponseHeaders, new FeatureMap<IHttpResponseFeature>(feature => Utilities.MakeDictionaryStringArray(feature.Headers), (feature, value) => feature.Headers = Utilities.MakeHeaderDictionary((IDictionary<string, string[]>)value)) },
{ OwinConstants.ResponseBody, new FeatureMap<IHttpResponseFeature>(feature => feature.Body, () => Stream.Null, (feature, value) => feature.Body = (Stream)value) },
{ OwinConstants.CommonKeys.OnSendingHeaders, new FeatureMap<IHttpResponseFeature>(
feature => new Action<Action<object>, object>((cb, state) => {

View File

@ -106,9 +106,9 @@ namespace Microsoft.AspNet.Owin
set { Prop(OwinConstants.RequestQueryString, Utilities.RemoveQuestionMark(value)); }
}
IDictionary<string, StringValues> IHttpRequestFeature.Headers
IHeaderDictionary IHttpRequestFeature.Headers
{
get { return Utilities.MakeDictionaryStringValues(Prop<IDictionary<string, string[]>>(OwinConstants.RequestHeaders)); }
get { return Utilities.MakeHeaderDictionary(Prop<IDictionary<string, string[]>>(OwinConstants.RequestHeaders)); }
set { Prop(OwinConstants.RequestHeaders, Utilities.MakeDictionaryStringArray(value)); }
}
@ -136,9 +136,9 @@ namespace Microsoft.AspNet.Owin
set { Prop(OwinConstants.ResponseReasonPhrase, value); }
}
IDictionary<string, StringValues> IHttpResponseFeature.Headers
IHeaderDictionary IHttpResponseFeature.Headers
{
get { return Utilities.MakeDictionaryStringValues(Prop<IDictionary<string, string[]>>(OwinConstants.ResponseHeaders)); }
get { return Utilities.MakeHeaderDictionary(Prop<IDictionary<string, string[]>>(OwinConstants.ResponseHeaders)); }
set { Prop(OwinConstants.ResponseHeaders, Utilities.MakeDictionaryStringArray(value)); }
}

View File

@ -46,7 +46,7 @@ namespace Microsoft.AspNet.Owin
return new ClaimsPrincipal(principal);
}
internal static IDictionary<string, StringValues> MakeDictionaryStringValues(IDictionary<string, string[]> dictionary)
internal static IHeaderDictionary MakeHeaderDictionary(IDictionary<string, string[]> dictionary)
{
var wrapper = dictionary as DictionaryStringArrayWrapper;
if (wrapper != null)
@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Owin
return new DictionaryStringValuesWrapper(dictionary);
}
internal static IDictionary<string, string[]> MakeDictionaryStringArray(IDictionary<string, StringValues> dictionary)
internal static IDictionary<string, string[]> MakeDictionaryStringArray(IHeaderDictionary dictionary)
{
var wrapper = dictionary as DictionaryStringValuesWrapper;
if (wrapper != null)

View File

@ -44,7 +44,7 @@ namespace Microsoft.AspNet.Http.Extensions
public bool HasStarted { get { return true; } }
public IDictionary<string, StringValues> Headers { get; set; }
public IHeaderDictionary Headers { get; set; }
public string ReasonPhrase { get; set; }

View File

@ -65,7 +65,7 @@ namespace Microsoft.AspNet.Http.Internal
// Arrange
const string expected = "localhost:9001";
var headers = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase)
var headers = new HeaderDictionary()
{
{ "Host", expected },
};
@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Http.Internal
// Arrange
const string expected = "löcalhöst";
var headers = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase)
var headers = new HeaderDictionary()
{
{ "Host", "xn--lcalhst-90ae" },
};
@ -105,7 +105,7 @@ namespace Microsoft.AspNet.Http.Internal
// Arrange
const string expected = "xn--lcalhst-90ae";
var headers = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase);
var headers = new HeaderDictionary();
var request = CreateRequest(headers);
@ -188,7 +188,7 @@ namespace Microsoft.AspNet.Http.Internal
Assert.Equal(new[] { "name2=value2" }, cookieHeaders);
}
private static HttpRequest CreateRequest(IDictionary<string, StringValues> headers)
private static HttpRequest CreateRequest(IHeaderDictionary headers)
{
var context = new DefaultHttpContext();
context.Features.Get<IHttpRequestFeature>().Headers = headers;
@ -217,7 +217,7 @@ namespace Microsoft.AspNet.Http.Internal
private static HttpRequest GetRequestWithHeader(string headerName, string headerValue)
{
var headers = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase);
var headers = new HeaderDictionary();
if (headerValue != null)
{
headers.Add(headerName, headerValue);