Fix issue #1280 - Add HttpResponseMessageFormatter

Adds a formatter that can convert an HttpResponseMessage returned from an
action into HttpContext.Response output.
This commit is contained in:
Ryan Nowak 2014-10-08 14:59:28 -07:00
parent aad3ae42ca
commit 22869b41c0
6 changed files with 172 additions and 0 deletions

View File

@ -0,0 +1,69 @@
// 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.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
using Microsoft.AspNet.HttpFeature;
namespace Microsoft.AspNet.Mvc.WebApiCompatShim
{
public class HttpResponseMessageOutputFormatter : IOutputFormatter
{
public bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType)
{
return context.Object is HttpResponseMessage;
}
public IReadOnlyList<MediaTypeHeaderValue> GetSupportedContentTypes(
Type declaredType,
Type runtimeType,
MediaTypeHeaderValue contentType)
{
return null;
}
public async Task WriteAsync(OutputFormatterContext context)
{
var response = context.ActionContext.HttpContext.Response;
var responseMessage = context.Object as HttpResponseMessage;
if (responseMessage == null)
{
var message = Resources.FormatHttpResponseMessageFormatter_UnsupportedType(
nameof(HttpResponseMessageOutputFormatter),
nameof(HttpResponseMessage));
throw new InvalidOperationException(message);
}
response.StatusCode = (int)responseMessage.StatusCode;
var responseFeature = context.ActionContext.HttpContext.GetFeature<IHttpResponseFeature>();
if (responseFeature != null)
{
responseFeature.ReasonPhrase = responseMessage.ReasonPhrase;
}
var responseHeaders = responseMessage.Headers;
foreach (var header in responseHeaders)
{
response.Headers.AppendValues(header.Key, header.Value.ToArray());
}
if (responseMessage.Content != null)
{
var contentHeaders = responseMessage.Content.Headers;
foreach (var header in contentHeaders)
{
response.Headers.AppendValues(header.Key, header.Value.ToArray());
}
await responseMessage.Content.CopyToAsync(response.Body);
}
}
}
}

View File

@ -10,6 +10,22 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNet.Mvc.WebApiCompatShim.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// The {0} only supports writing objects of type {1}.
/// </summary>
internal static string HttpResponseMessageFormatter_UnsupportedType
{
get { return GetString("HttpResponseMessageFormatter_UnsupportedType"); }
}
/// <summary>
/// The {0} only supports writing objects of type {1}.
/// </summary>
internal static string FormatHttpResponseMessageFormatter_UnsupportedType(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("HttpResponseMessageFormatter_UnsupportedType"), p0, p1);
}
/// <summary>
/// The key is invalid JQuery syntax because it is missing a closing bracket.
/// </summary>

View File

@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="HttpResponseMessageFormatter_UnsupportedType" xml:space="preserve">
<value>The {0} only supports writing objects of type {1}.</value>
</data>
<data name="JQuerySyntaxMissingClosingBracket" xml:space="preserve">
<value>The key is invalid JQuery syntax because it is missing a closing bracket.</value>
</data>

View File

@ -24,6 +24,9 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim
// Add a model binder to be able to bind HttpRequestMessage
options.ModelBinders.Insert(0, new HttpRequestMessageModelBinder());
// Add a formatter to write out an HttpResponseMessage to the response
options.OutputFormatters.Insert(0, new HttpResponseMessageOutputFormatter());
}
public void Invoke(WebApiCompatShimOptions options)

View File

@ -3,6 +3,7 @@
#if ASPNET50
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
@ -123,6 +124,58 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expected, content);
}
[Fact]
public async Task ApiController_ResponseReturned()
{
// Arrange
var server = TestServer.Create(_provider, _app);
var client = server.CreateClient();
var expected =
"POST Hello, HttpResponseMessage world!";
// Act
var response = await client.PostAsync(
"http://localhost/api/Blog/HttpRequestMessage/EchoWithResponseMessage",
new StringContent("Hello, HttpResponseMessage world!"));
var content = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expected, content);
IEnumerable<string> values;
Assert.True(response.Headers.TryGetValues("X-Test", out values));
Assert.Equal(new string[] { "Hello!" }, values);
Assert.Equal(38, response.Content.Headers.ContentLength);
}
[Fact]
public async Task ApiController_ResponseReturned_Chunked()
{
// Arrange
var server = TestServer.Create(_provider, _app);
var client = server.CreateClient();
var expected =
"POST Hello, HttpResponseMessage world!";
// Act
var response = await client.PostAsync(
"http://localhost/api/Blog/HttpRequestMessage/EchoWithResponseMessageChunked",
new StringContent("Hello, HttpResponseMessage world!"));
var content = await response.Content.ReadAsStringAsync();
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(expected, content);
IEnumerable<string> values;
Assert.True(response.Headers.TryGetValues("X-Test", out values));
Assert.Equal(new string[] { "Hello!" }, values);
Assert.Equal(true, response.Headers.TransferEncodingChunked);
}
}
}
#endif

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using System.Net;
namespace WebApiCompatShimWebSite
{
@ -29,6 +30,33 @@ namespace WebApiCompatShimWebSite
return new EmptyResult();
}
public async Task<HttpResponseMessage> EchoWithResponseMessage(HttpRequestMessage request)
{
var message = string.Format(
"{0} {1}",
request.Method.ToString(),
await request.Content.ReadAsStringAsync());
var response = request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(message);
response.Headers.TryAddWithoutValidation("X-Test", "Hello!");
return response;
}
public async Task<HttpResponseMessage> EchoWithResponseMessageChunked(HttpRequestMessage request)
{
var message = string.Format(
"{0} {1}",
request.Method.ToString(),
await request.Content.ReadAsStringAsync());
var response = request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(message);
response.Headers.TransferEncodingChunked = true;
response.Headers.TryAddWithoutValidation("X-Test", "Hello!");
return response;
}
private async Task Echo(HttpRequestMessage request)
{
var message = string.Format(