#274 Reorganize the strong header type extensions. Remove SendAsync extensions.

This commit is contained in:
Chris Ross 2015-04-22 11:43:12 -07:00
parent d4132d98fd
commit 25aed6f88e
6 changed files with 108 additions and 293 deletions

View File

@ -23,12 +23,14 @@ namespace Microsoft.AspNet.Http
return new ResponseHeaders(response.Headers);
}
public static DateTimeOffset? GetDate([NotNull] this IHeaderDictionary headers, [NotNull] string name)
// These are all shared helpers used by both RequestHeaders and ResponseHeaders
internal static DateTimeOffset? GetDate([NotNull] this IHeaderDictionary headers, [NotNull] string name)
{
return headers.Get<DateTimeOffset?>(name);
}
public static void Set([NotNull] this IHeaderDictionary headers, [NotNull] string name, object value)
internal static void Set([NotNull] this IHeaderDictionary headers, [NotNull] string name, object value)
{
if (value == null)
{
@ -40,7 +42,7 @@ namespace Microsoft.AspNet.Http
}
}
public static void SetList<T>([NotNull] this IHeaderDictionary headers, [NotNull] string name, IList<T> values)
internal static void SetList<T>([NotNull] this IHeaderDictionary headers, [NotNull] string name, IList<T> values)
{
if (values == null || values.Count == 0)
{
@ -52,7 +54,7 @@ namespace Microsoft.AspNet.Http
}
}
public static void SetDate([NotNull] this IHeaderDictionary headers, [NotNull] string name, DateTimeOffset? value)
internal static void SetDate([NotNull] this IHeaderDictionary headers, [NotNull] string name, DateTimeOffset? value)
{
if (value.HasValue)
{
@ -64,16 +66,6 @@ namespace Microsoft.AspNet.Http
}
}
public static void Append([NotNull] this IHeaderDictionary headers, [NotNull] string name, [NotNull] object value)
{
headers.Append(name, value.ToString());
}
public static void AppendList<T>([NotNull] this IHeaderDictionary headers, [NotNull] string name, [NotNull] IList<T> values)
{
headers.AppendValues(name, values.Select(value => value.ToString()).ToArray());
}
private static IDictionary<Type, object> KnownParsers = new Dictionary<Type, object>()
{
{ typeof(CacheControlHeaderValue), new Func<string, CacheControlHeaderValue>(value => { CacheControlHeaderValue result; return CacheControlHeaderValue.TryParse(value, out result) ? result : null; }) },
@ -96,7 +88,7 @@ namespace Microsoft.AspNet.Http
{ typeof(SetCookieHeaderValue), new Func<IList<string>, IList<SetCookieHeaderValue>>(value => { IList<SetCookieHeaderValue> result; return SetCookieHeaderValue.TryParseList(value, out result) ? result : null; }) },
};
public static T Get<T>([NotNull] this IHeaderDictionary headers, string name)
internal static T Get<T>([NotNull] this IHeaderDictionary headers, string name)
{
object temp;
if (KnownParsers.TryGetValue(typeof(T), out temp))
@ -114,7 +106,7 @@ namespace Microsoft.AspNet.Http
return GetViaReflection<T>(value);
}
public static IList<T> GetList<T>([NotNull] this IHeaderDictionary headers, string name)
internal static IList<T> GetList<T>([NotNull] this IHeaderDictionary headers, string name)
{
object temp;
if (KnownListParsers.TryGetValue(typeof(T), out temp))

View File

@ -1,153 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Http
{
/// <summary>
/// Convenience methods for writing to the response.
/// </summary>
public static class HttpResponseSendingExtensions
{
/// <summary>
/// Sends a response with the given Content-Type and body. UTF-8 encoding will be used, and the Content-Length header will be set accordingly.
/// </summary>
/// <param name="response"></param>
/// <param name="text"></param>
/// <param name="contentType"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task SendAsync([NotNull] this HttpResponse response, [NotNull] string text, [NotNull] string contentType, CancellationToken cancellationToken = default(CancellationToken))
{
return response.SendAsync(text, Encoding.UTF8, contentType, cancellationToken);
}
/// <summary>
/// Sends a response with the given Content-Type, encoding, and body. The Content-Length header will be set accordingly.
/// </summary>
/// <param name="response"></param>
/// <param name="text"></param>
/// <param name="encoding"></param>
/// <param name="contentType"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task SendAsync([NotNull] this HttpResponse response, [NotNull] string text, [NotNull] Encoding encoding, [NotNull] string contentType, CancellationToken cancellationToken = default(CancellationToken))
{
if (string.IsNullOrEmpty(contentType))
{
throw new ArgumentException("Empty Content-Type is not allowed.");
}
if (contentType.IndexOf("charset=", StringComparison.OrdinalIgnoreCase) < 0)
{
contentType += "; charset=" + encoding.WebName;
}
response.ContentType = contentType;
return response.SendAsync(text, encoding, cancellationToken);
}
/// <summary>
/// Sends a response with the given body. UTF-8 encoding will be used, and the Content-Length header will be set accordingly.
/// </summary>
/// <param name="response"></param>
/// <param name="text"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task SendAsync([NotNull] this HttpResponse response, [NotNull] string text, CancellationToken cancellationToken = default(CancellationToken))
{
return response.SendAsync(text, Encoding.UTF8, cancellationToken);
}
/// <summary>
/// Sends a response with the given encoding and body. The Content-Length header will be set accordingly.
/// </summary>
/// <param name="response"></param>
/// <param name="text"></param>
/// <param name="encoding"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task SendAsync([NotNull] this HttpResponse response, [NotNull] string text, [NotNull] Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))
{
byte[] data = encoding.GetBytes(text);
return response.SendAsync(data, cancellationToken);
}
/// <summary>
/// Sends a response with the given Content-Type and body. The Content-Length header will be set accordingly.
/// </summary>
/// <param name="response"></param>
/// <param name="data"></param>
/// <param name="contentType"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task SendAsync([NotNull] this HttpResponse response, [NotNull] byte[] data, [NotNull] string contentType, CancellationToken cancellationToken = default(CancellationToken))
{
return response.SendAsync(new ArraySegment<byte>(data), contentType, cancellationToken);
}
/// <summary>
/// Sends a response with the given Content-Type and body. The Content-Length header will be set accordingly.
/// </summary>
/// <param name="response"></param>
/// <param name="data"></param>
/// <param name="contentType"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task SendAsync([NotNull] this HttpResponse response, ArraySegment<byte> data, [NotNull] string contentType, CancellationToken cancellationToken = default(CancellationToken))
{
if (string.IsNullOrEmpty(contentType))
{
throw new ArgumentException("Empty Content-Type is not allowed.");
}
response.ContentType = contentType;
return response.SendAsync(data, cancellationToken);
}
/// <summary>
/// Sends a response with the given body. The Content-Length header will be set accordingly.
/// </summary>
/// <param name="response"></param>
/// <param name="data"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task SendAsync([NotNull] this HttpResponse response, [NotNull] byte[] data, CancellationToken cancellationToken = default(CancellationToken))
{
return response.SendAsync(new ArraySegment<byte>(data), cancellationToken);
}
/// <summary>
/// Sends a response with the given body. The Content-Length header will be set accordingly.
/// </summary>
/// <param name="response"></param>
/// <param name="data"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task SendAsync([NotNull] this HttpResponse response, [NotNull] byte[] data, int offset, int count, CancellationToken cancellationToken = default(CancellationToken))
{
return response.SendAsync(new ArraySegment<byte>(data, offset, count), cancellationToken);
}
/// <summary>
/// Sends a response with the given body. The Content-Length header will be set accordingly.
/// </summary>
/// <param name="response"></param>
/// <param name="data"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task SendAsync([NotNull] this HttpResponse response, ArraySegment<byte> data, CancellationToken cancellationToken = default(CancellationToken))
{
if (data.Array == null)
{
throw new ArgumentException("The Array cannot be null.", "data"); // TODO: LOC
}
response.ContentLength = data.Count;
return response.Body.WriteAsync(data.Array, data.Offset, data.Count, cancellationToken);
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Framework.Internal;
using Microsoft.Net.Http.Headers;
@ -256,5 +257,35 @@ namespace Microsoft.AspNet.Http.Headers
Headers.Set(HeaderNames.Range, value);
}
}
public T Get<T>(string name)
{
return Headers.Get<T>(name);
}
public IList<T> GetList<T>(string name)
{
return Headers.GetList<T>(name);
}
public void Set([NotNull] string name, object value)
{
Headers.Set(name, value);
}
public void SetList<T>([NotNull] string name, IList<T> values)
{
Headers.SetList<T>(name, values);
}
public void Append([NotNull] string name, [NotNull] object value)
{
Headers.Append(name, value.ToString());
}
public void AppendList<T>([NotNull] string name, [NotNull] IList<T> values)
{
Headers.AppendValues(name, values.Select(value => value.ToString()).ToArray());
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Http.Extensions;
using Microsoft.Framework.Internal;
using Microsoft.Net.Http.Headers;
@ -153,5 +154,35 @@ namespace Microsoft.AspNet.Http.Headers
Headers.SetList(HeaderNames.SetCookie, value);
}
}
public T Get<T>(string name)
{
return Headers.Get<T>(name);
}
public IList<T> GetList<T>(string name)
{
return Headers.GetList<T>(name);
}
public void Set([NotNull] string name, object value)
{
Headers.Set(name, value);
}
public void SetList<T>([NotNull] string name, IList<T> values)
{
Headers.SetList<T>(name, values);
}
public void Append([NotNull] string name, [NotNull] object value)
{
Headers.Append(name, value.ToString());
}
public void AppendList<T>([NotNull] string name, [NotNull] IList<T> values)
{
Headers.AppendValues(name, values.Select(value => value.ToString()).ToArray());
}
}
}

View File

@ -15,10 +15,10 @@ namespace Microsoft.AspNet.Http.Headers
[Fact]
public void GetT_KnownTypeWithValidValue_Success()
{
var headers = new HeaderDictionary();
headers[HeaderNames.ContentType] = "text/plain";
var context = new DefaultHttpContext();
context.Request.Headers[HeaderNames.ContentType] = "text/plain";
var result = headers.Get<MediaTypeHeaderValue>(HeaderNames.ContentType);
var result = context.Request.GetTypedHeaders().Get<MediaTypeHeaderValue>(HeaderNames.ContentType);
var expected = new MediaTypeHeaderValue("text/plain");
Assert.Equal(expected, result);
@ -27,9 +27,9 @@ namespace Microsoft.AspNet.Http.Headers
[Fact]
public void GetT_KnownTypeWithMissingValue_Null()
{
var headers = new HeaderDictionary();
var context = new DefaultHttpContext();
var result = headers.Get<MediaTypeHeaderValue>(HeaderNames.ContentType);
var result = context.Request.GetTypedHeaders().Get<MediaTypeHeaderValue>(HeaderNames.ContentType);
Assert.Null(result);
}
@ -37,10 +37,10 @@ namespace Microsoft.AspNet.Http.Headers
[Fact]
public void GetT_KnownTypeWithInvalidValue_Null()
{
var headers = new HeaderDictionary();
headers[HeaderNames.ContentType] = "invalid";
var context = new DefaultHttpContext();
context.Request.Headers[HeaderNames.ContentType] = "invalid";
var result = headers.Get<MediaTypeHeaderValue>(HeaderNames.ContentType);
var result = context.Request.GetTypedHeaders().Get<MediaTypeHeaderValue>(HeaderNames.ContentType);
Assert.Null(result);
}
@ -48,48 +48,48 @@ namespace Microsoft.AspNet.Http.Headers
[Fact]
public void GetT_UnknownTypeWithTryParseAndValidValue_Success()
{
var headers = new HeaderDictionary();
headers["custom"] = "valid";
var context = new DefaultHttpContext();
context.Request.Headers["custom"] = "valid";
var result = headers.Get<TestHeaderValue>("custom");
var result = context.Request.GetTypedHeaders().Get<TestHeaderValue>("custom");
Assert.NotNull(result);
}
[Fact]
public void GetT_UnknownTypeWithTryParseAndInvalidValue_Null()
{
var headers = new HeaderDictionary();
headers["custom"] = "invalid";
var context = new DefaultHttpContext();
context.Request.Headers["custom"] = "invalid";
var result = headers.Get<TestHeaderValue>("custom");
var result = context.Request.GetTypedHeaders().Get<TestHeaderValue>("custom");
Assert.Null(result);
}
[Fact]
public void GetT_UnknownTypeWithTryParseAndMissingValue_Null()
{
var headers = new HeaderDictionary();
var context = new DefaultHttpContext();
var result = headers.Get<TestHeaderValue>("custom");
var result = context.Request.GetTypedHeaders().Get<TestHeaderValue>("custom");
Assert.Null(result);
}
[Fact]
public void GetT_UnknownTypeWithoutTryParse_Throws()
{
var headers = new HeaderDictionary();
headers["custom"] = "valid";
var context = new DefaultHttpContext();
context.Request.Headers["custom"] = "valid";
Assert.Throws<NotSupportedException>(() => headers.Get<object>("custom"));
Assert.Throws<NotSupportedException>(() => context.Request.GetTypedHeaders().Get<object>("custom"));
}
[Fact]
public void GetListT_KnownTypeWithValidValue_Success()
{
var headers = new HeaderDictionary();
headers[HeaderNames.Accept] = "text/plain; q=0.9, text/other, */*";
var context = new DefaultHttpContext();
context.Request.Headers[HeaderNames.Accept] = "text/plain; q=0.9, text/other, */*";
var result = headers.GetList<MediaTypeHeaderValue>(HeaderNames.Accept);
var result = context.Request.GetTypedHeaders().GetList<MediaTypeHeaderValue>(HeaderNames.Accept);
var expected = new[] {
new MediaTypeHeaderValue("text/plain", 0.9),
@ -102,9 +102,9 @@ namespace Microsoft.AspNet.Http.Headers
[Fact]
public void GetListT_KnownTypeWithMissingValue_Null()
{
var headers = new HeaderDictionary();
var context = new DefaultHttpContext();
var result = headers.GetList<MediaTypeHeaderValue>(HeaderNames.Accept);
var result = context.Request.GetTypedHeaders().GetList<MediaTypeHeaderValue>(HeaderNames.Accept);
Assert.Null(result);
}
@ -112,10 +112,10 @@ namespace Microsoft.AspNet.Http.Headers
[Fact]
public void GetListT_KnownTypeWithInvalidValue_Null()
{
var headers = new HeaderDictionary();
headers[HeaderNames.Accept] = "invalid";
var context = new DefaultHttpContext();
context.Request.Headers[HeaderNames.Accept] = "invalid";
var result = headers.GetList<MediaTypeHeaderValue>(HeaderNames.Accept);
var result = context.Request.GetTypedHeaders().GetList<MediaTypeHeaderValue>(HeaderNames.Accept);
Assert.Null(result);
}
@ -123,10 +123,10 @@ namespace Microsoft.AspNet.Http.Headers
[Fact]
public void GetListT_UnknownTypeWithTryParseListAndValidValue_Success()
{
var headers = new HeaderDictionary();
headers["custom"] = "valid";
var context = new DefaultHttpContext();
context.Request.Headers["custom"] = "valid";
var results = headers.GetList<TestHeaderValue>("custom");
var results = context.Request.GetTypedHeaders().GetList<TestHeaderValue>("custom");
Assert.NotNull(results);
Assert.Equal(new[] { new TestHeaderValue() }.ToList(), results);
}
@ -134,29 +134,29 @@ namespace Microsoft.AspNet.Http.Headers
[Fact]
public void GetListT_UnknownTypeWithTryParseListAndInvalidValue_Null()
{
var headers = new HeaderDictionary();
headers["custom"] = "invalid";
var context = new DefaultHttpContext();
context.Request.Headers["custom"] = "invalid";
var results = headers.GetList<TestHeaderValue>("custom");
var results = context.Request.GetTypedHeaders().GetList<TestHeaderValue>("custom");
Assert.Null(results);
}
[Fact]
public void GetListT_UnknownTypeWithTryParseListAndMissingValue_Null()
{
var headers = new HeaderDictionary();
var context = new DefaultHttpContext();
var results = headers.GetList<TestHeaderValue>("custom");
var results = context.Request.GetTypedHeaders().GetList<TestHeaderValue>("custom");
Assert.Null(results);
}
[Fact]
public void GetListT_UnknownTypeWithoutTryParseList_Throws()
{
var headers = new HeaderDictionary();
headers["custom"] = "valid";
var context = new DefaultHttpContext();
context.Request.Headers["custom"] = "valid";
Assert.Throws<NotSupportedException>(() => headers.GetList<object>("custom"));
Assert.Throws<NotSupportedException>(() => context.Request.GetTypedHeaders().GetList<object>("custom"));
}
public class TestHeaderValue

View File

@ -1,86 +0,0 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNet.Http.Extensions
{
public class HttpResponseSendingExtensionsTests
{
[Fact]
public async Task SendData_SendBytes()
{
HttpContext context = CreateRequest();
await context.Response.SendAsync(new byte[10]);
Assert.Equal(10, context.Response.Body.Length);
Assert.Equal(10, context.Response.ContentLength);
Assert.Null(context.Response.ContentType);
}
[Fact]
public async Task SendData_SendBytesAndContentType()
{
HttpContext context = CreateRequest();
await context.Response.SendAsync(new byte[10], "text/html");
Assert.Equal(10, context.Response.Body.Length);
Assert.Equal(10, context.Response.ContentLength);
Assert.Equal("text/html", context.Response.ContentType);
}
[Fact]
public async Task SendData_SendText()
{
HttpContext context = CreateRequest();
await context.Response.SendAsync("Hello World");
Assert.Equal(11, context.Response.Body.Length);
Assert.Equal(11, context.Response.ContentLength);
Assert.Null(context.Response.ContentType);
}
[Fact]
public async Task SendData_SendTextWithContentType()
{
HttpContext context = CreateRequest();
await context.Response.SendAsync("Hello World", "text/html");
Assert.Equal(11, context.Response.Body.Length);
Assert.Equal(11, context.Response.ContentLength);
Assert.Equal("text/html; charset=utf-8", context.Response.ContentType);
}
[Fact]
public async Task SendData_SendTextWithEncoding()
{
HttpContext context = CreateRequest();
await context.Response.SendAsync("Hello World", Encoding.UTF32);
Assert.Equal(44, context.Response.Body.Length);
Assert.Equal(44, context.Response.ContentLength);
Assert.Null(context.Response.ContentType);
}
[Fact]
public async Task SendData_SendTextWithContentTypeAndEncoding()
{
HttpContext context = CreateRequest();
await context.Response.SendAsync("Hello World", Encoding.UTF32, "text/html");
Assert.Equal(44, context.Response.Body.Length);
Assert.Equal(44, context.Response.ContentLength);
Assert.Equal("text/html; charset=utf-32", context.Response.ContentType);
}
private HttpContext CreateRequest()
{
HttpContext context = new DefaultHttpContext();
context.Response.Body = new MemoryStream();
return context;
}
}
}