Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Commit 434ddf3

Browse files
committed
Fix issue #1280 - Add HttpResponseMessageFormatter
Adds a formatter that can convert an HttpResponseMessage returned from an action into HttpContext.Response output.
1 parent 4227215 commit 434ddf3

File tree

6 files changed

+168
-0
lines changed

6 files changed

+168
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Net.Http;
8+
using System.Threading.Tasks;
9+
using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
10+
11+
namespace Microsoft.AspNet.Mvc.WebApiCompatShim
12+
{
13+
public class HttpResponseMessageOutputFormatter : IOutputFormatter
14+
{
15+
public bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType)
16+
{
17+
return context.Object is HttpResponseMessage;
18+
}
19+
20+
public IReadOnlyList<MediaTypeHeaderValue> GetSupportedContentTypes(
21+
Type declaredType,
22+
Type runtimeType,
23+
MediaTypeHeaderValue contentType)
24+
{
25+
return null;
26+
}
27+
28+
public async Task WriteAsync(OutputFormatterContext context)
29+
{
30+
var liveResponse = context.ActionContext.HttpContext.Response;
31+
32+
var response = context.Object as HttpResponseMessage;
33+
if (response == null)
34+
{
35+
var message = Resources.FormatHttpResponseMessageFormatter_UnsupportedType(
36+
nameof(HttpResponseMessageOutputFormatter),
37+
nameof(HttpResponseMessage));
38+
39+
throw new InvalidOperationException(message);
40+
}
41+
42+
var contentHeaders = response.Content?.Headers;
43+
if (contentHeaders != null)
44+
{
45+
foreach (var header in contentHeaders)
46+
{
47+
liveResponse.Headers.AppendValues(header.Key, header.Value.ToArray());
48+
}
49+
}
50+
51+
var resonseHeaders = response.Headers;
52+
foreach (var header in resonseHeaders)
53+
{
54+
liveResponse.Headers.AppendValues(header.Key, header.Value.ToArray());
55+
}
56+
57+
liveResponse.StatusCode = (int)response.StatusCode;
58+
59+
if (response.Content != null)
60+
{
61+
await response.Content.CopyToAsync(liveResponse.Body);
62+
}
63+
}
64+
}
65+
}

src/Microsoft.AspNet.Mvc.WebApiCompatShim/Properties/Resources.Designer.cs

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Microsoft.AspNet.Mvc.WebApiCompatShim/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@
117117
<resheader name="writer">
118118
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119119
</resheader>
120+
<data name="HttpResponseMessageFormatter_UnsupportedType" xml:space="preserve">
121+
<value>The {0} only supports writing objects of type {1}.</value>
122+
</data>
120123
<data name="JQuerySyntaxMissingClosingBracket" xml:space="preserve">
121124
<value>The key is invalid JQuery syntax because it is missing a closing bracket.</value>
122125
</data>

src/Microsoft.AspNet.Mvc.WebApiCompatShim/WebApiCompatShimOptionsSetup.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ public void Invoke(MvcOptions options)
2424

2525
// Add a model binder to be able to bind HttpRequestMessage
2626
options.ModelBinders.Insert(0, new HttpRequestMessageModelBinder());
27+
28+
// Add a formatter to write out an HttpResponseMessage to the response
29+
options.OutputFormatters.Add(new HttpResponseMessageOutputFormatter());
2730
}
2831

2932
public void Invoke(WebApiCompatShimOptions options)

test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Microsoft.AspNet.TestHost;
1212
using Newtonsoft.Json;
1313
using Xunit;
14+
using System.Collections.Generic;
1415

1516
namespace Microsoft.AspNet.Mvc.FunctionalTests
1617
{
@@ -123,6 +124,58 @@ public async Task ApiController_RequestParameter()
123124
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
124125
Assert.Equal(expected, content);
125126
}
127+
128+
[Fact]
129+
public async Task ApiController_ResponseReturned()
130+
{
131+
// Arrange
132+
var server = TestServer.Create(_provider, _app);
133+
var client = server.CreateClient();
134+
135+
var expected =
136+
"POST Hello, HttpResponseMessage world!";
137+
138+
// Act
139+
var response = await client.PostAsync(
140+
"http://localhost/api/Blog/HttpRequestMessage/EchoWithResponseMessage",
141+
new StringContent("Hello, HttpResponseMessage world!"));
142+
var content = await response.Content.ReadAsStringAsync();
143+
144+
// Assert
145+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
146+
Assert.Equal(expected, content);
147+
148+
IEnumerable<string> values;
149+
Assert.True(response.Headers.TryGetValues("X-Test", out values));
150+
Assert.Equal(new string[] { "Hello!" }, values);
151+
Assert.Equal(38, response.Content.Headers.ContentLength);
152+
}
153+
154+
[Fact]
155+
public async Task ApiController_ResponseReturned_Chunked()
156+
{
157+
// Arrange
158+
var server = TestServer.Create(_provider, _app);
159+
var client = server.CreateClient();
160+
161+
var expected =
162+
"POST Hello, HttpResponseMessage world!";
163+
164+
// Act
165+
var response = await client.PostAsync(
166+
"http://localhost/api/Blog/HttpRequestMessage/EchoWithResponseMessageChunked",
167+
new StringContent("Hello, HttpResponseMessage world!"));
168+
var content = await response.Content.ReadAsStringAsync();
169+
170+
// Assert
171+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
172+
Assert.Equal(expected, content);
173+
174+
IEnumerable<string> values;
175+
Assert.True(response.Headers.TryGetValues("X-Test", out values));
176+
Assert.Equal(new string[] { "Hello!" }, values);
177+
Assert.Equal(true, response.Headers.TransferEncodingChunked);
178+
}
126179
}
127180
}
128181
#endif

test/WebSites/WebApiCompatShimWebSite/Controllers/HttpRequestMessage/HttpRequestMessageController.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Web.Http;
88
using Microsoft.AspNet.Http;
99
using Microsoft.AspNet.Mvc;
10+
using System.Net;
1011

1112
namespace WebApiCompatShimWebSite
1213
{
@@ -29,6 +30,33 @@ public async Task<IActionResult> EchoParameter(HttpRequestMessage request)
2930
return new EmptyResult();
3031
}
3132

33+
public async Task<HttpResponseMessage> EchoWithResponseMessage(HttpRequestMessage request)
34+
{
35+
var message = string.Format(
36+
"{0} {1}",
37+
request.Method.ToString(),
38+
await request.Content.ReadAsStringAsync());
39+
40+
var response = request.CreateResponse(HttpStatusCode.OK);
41+
response.Content = new StringContent(message);
42+
response.Headers.TryAddWithoutValidation("X-Test", "Hello!");
43+
return response;
44+
}
45+
46+
public async Task<HttpResponseMessage> EchoWithResponseMessageChunked(HttpRequestMessage request)
47+
{
48+
var message = string.Format(
49+
"{0} {1}",
50+
request.Method.ToString(),
51+
await request.Content.ReadAsStringAsync());
52+
53+
var response = request.CreateResponse(HttpStatusCode.OK);
54+
response.Content = new StringContent(message);
55+
response.Headers.TransferEncodingChunked = true;
56+
response.Headers.TryAddWithoutValidation("X-Test", "Hello!");
57+
return response;
58+
}
59+
3260
private async Task Echo(HttpRequestMessage request)
3361
{
3462
var message = string.Format(

0 commit comments

Comments
 (0)