diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Formatters/HttpResponseMessageOutputFormatter.cs b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Formatters/HttpResponseMessageOutputFormatter.cs new file mode 100644 index 0000000000..3dd743b842 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Formatters/HttpResponseMessageOutputFormatter.cs @@ -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 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(); + 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); + } + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Properties/Resources.Designer.cs index ee2edffaaf..cb10994d90 100644 --- a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Properties/Resources.Designer.cs @@ -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); + /// + /// The {0} only supports writing objects of type {1}. + /// + internal static string HttpResponseMessageFormatter_UnsupportedType + { + get { return GetString("HttpResponseMessageFormatter_UnsupportedType"); } + } + + /// + /// The {0} only supports writing objects of type {1}. + /// + internal static string FormatHttpResponseMessageFormatter_UnsupportedType(object p0, object p1) + { + return string.Format(CultureInfo.CurrentCulture, GetString("HttpResponseMessageFormatter_UnsupportedType"), p0, p1); + } + /// /// The key is invalid JQuery syntax because it is missing a closing bracket. /// diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Resources.resx b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Resources.resx index 00afe5899e..a86ebf7b9a 100644 --- a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Resources.resx +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Resources.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + The {0} only supports writing objects of type {1}. + The key is invalid JQuery syntax because it is missing a closing bracket. diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/WebApiCompatShimOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/WebApiCompatShimOptionsSetup.cs index 22d6a3f230..142a66d2ad 100644 --- a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/WebApiCompatShimOptionsSetup.cs +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/WebApiCompatShimOptionsSetup.cs @@ -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) diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs index 31985a71e0..ae897181bd 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/WebApiCompatShimBasicTest.cs @@ -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 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 values; + Assert.True(response.Headers.TryGetValues("X-Test", out values)); + Assert.Equal(new string[] { "Hello!" }, values); + Assert.Equal(true, response.Headers.TransferEncodingChunked); + } } } #endif \ No newline at end of file diff --git a/test/WebSites/WebApiCompatShimWebSite/Controllers/HttpRequestMessage/HttpRequestMessageController.cs b/test/WebSites/WebApiCompatShimWebSite/Controllers/HttpRequestMessage/HttpRequestMessageController.cs index 7a28eb21e6..c4b654c5ee 100644 --- a/test/WebSites/WebApiCompatShimWebSite/Controllers/HttpRequestMessage/HttpRequestMessageController.cs +++ b/test/WebSites/WebApiCompatShimWebSite/Controllers/HttpRequestMessage/HttpRequestMessageController.cs @@ -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 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 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(