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

Commit eda4b16

Browse files
kichallaKiran Challa
authored and
Kiran Challa
committed
[Fixes #1836]SupportedMediaTypes for output formatters are incorrectly updated with charset data during requests
1 parent a2d1266 commit eda4b16

File tree

5 files changed

+97
-2
lines changed

5 files changed

+97
-2
lines changed

src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ public virtual void WriteResponseHeaders([NotNull] OutputFormatterContext contex
177177
throw new InvalidOperationException(Resources.FormatOutputFormatterNoMediaType(GetType().FullName));
178178
}
179179

180+
// Clone the media type as we don't want it to affect the next request
181+
selectedMediaType = MediaTypeHeaderValue.Parse(selectedMediaType.ToString());
182+
180183
var selectedEncoding = SelectCharacterEncoding(context);
181184
if (selectedEncoding == null)
182185
{

test/Microsoft.AspNet.Mvc.Core.Test/Formatters/OutputFormatterTests.cs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,29 @@ public void WriteResponseContentHeaders_NoSelectedContentType_SetsOutputFormatte
120120
formatterContext.SelectedContentType.ToString());
121121
}
122122

123+
[Fact]
124+
public async Task WriteResponseHeaders_ClonesMediaType()
125+
{
126+
// Arrange
127+
var formatter = new PngImageFormatter();
128+
formatter.SupportedMediaTypes.Clear();
129+
var mediaType = new MediaTypeHeaderValue("image/png");
130+
formatter.SupportedMediaTypes.Add(mediaType);
131+
var formatterContext = new OutputFormatterContext();
132+
formatterContext.ActionContext = new ActionContext(
133+
new DefaultHttpContext(),
134+
new RouteData(),
135+
new ActionDescriptor());
136+
137+
// Act
138+
await formatter.WriteAsync(formatterContext);
139+
140+
// Assert
141+
Assert.NotSame(mediaType, formatterContext.SelectedContentType);
142+
Assert.Null(mediaType.Charset);
143+
Assert.Equal("image/png; charset=utf-8", formatterContext.SelectedContentType.ToString());
144+
}
145+
123146
[Fact]
124147
public void CanWriteResult_ForNullContentType_UsesFirstEntryInSupportedContentTypes()
125148
{
@@ -294,7 +317,7 @@ public DoesNotSetContext()
294317
public override bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType)
295318
{
296319
// Do not set the selected media Type.
297-
// The WriteResponseContentHeader should do it for you.
320+
// The WriteResponseHeaders should do it for you.
298321
return true;
299322
}
300323

@@ -303,5 +326,19 @@ public override Task WriteResponseBodyAsync(OutputFormatterContext context)
303326
return Task.FromResult(true);
304327
}
305328
}
329+
330+
private class PngImageFormatter : OutputFormatter
331+
{
332+
public PngImageFormatter()
333+
{
334+
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("image/png"));
335+
SupportedEncodings.Add(Encoding.UTF8);
336+
}
337+
338+
public override Task WriteResponseBodyAsync([NotNull] OutputFormatterContext context)
339+
{
340+
return Task.FromResult(true);
341+
}
342+
}
306343
}
307344
}

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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,50 @@ public async Task JsonResult_UsesDefaultJsonFormatter_IfNoMatchingFormatterIsFou
296296
Assert.Equal(expectedBody, body);
297297
}
298298

299+
[Fact]
300+
public async Task JsonFormatter_SupportedMediaType_DoesNotChangeAcrossRequests()
301+
{
302+
// Arrange
303+
var server = TestServer.Create(_provider, _app);
304+
var client = server.CreateClient();
305+
var expectedContentType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8");
306+
var expectedBody = "{\"MethodName\":\"ReturnJsonResult\"}";
307+
308+
for (int i = 0; i < 5; i++)
309+
{
310+
// Act and Assert
311+
var response = await client.GetAsync("http://localhost/JsonResult/ReturnJsonResult");
312+
313+
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
314+
var body = await response.Content.ReadAsStringAsync();
315+
Assert.Equal(expectedBody, body);
316+
}
317+
}
318+
319+
[Fact]
320+
public async Task XmlFormatter_SupportedMediaType_DoesNotChangeAcrossRequests()
321+
{
322+
// Arrange
323+
var server = TestServer.Create(_provider, _app);
324+
var client = server.CreateClient();
325+
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
326+
client.DefaultRequestHeaders.AcceptCharset.Add(new StringWithQualityHeaderValue("utf-8"));
327+
var expectedContentType = MediaTypeHeaderValue.Parse("application/xml;charset=utf-8");
328+
var expectedBody = @"<User xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"" " +
329+
@"xmlns=""http://schemas.datacontract.org/2004/07/ConnegWebSite""><Address>"
330+
+ @"One Microsoft Way</Address><Name>John</Name></User>";
331+
332+
for (int i = 0; i < 5; i++)
333+
{
334+
// Act and Assert
335+
var response = await client.GetAsync("http://localhost/Home/UserInfo");
336+
337+
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
338+
var body = await response.Content.ReadAsStringAsync();
339+
Assert.Equal(expectedBody, body);
340+
}
341+
}
342+
299343
[Theory]
300344
[InlineData("UseTheFallback_WithDefaultFormatters")]
301345
[InlineData("UseTheFallback_UsingCustomFormatters")]

test/WebSites/ConnegWebSite/Controllers/HomeController.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,10 @@ public IActionResult Index()
1111
{
1212
return new JsonResult("Index Method");
1313
}
14+
15+
public User UserInfo()
16+
{
17+
return new User() { Name = "John", Address = "One Microsoft Way" };
18+
}
1419
}
1520
}

test/WebSites/ConnegWebSite/Startup.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using Microsoft.AspNet.Builder;
5+
using Microsoft.AspNet.Mvc;
56
using Microsoft.AspNet.Routing;
67
using Microsoft.Framework.DependencyInjection;
78

@@ -18,8 +19,13 @@ public void Configure(IApplicationBuilder app)
1819
{
1920
// Add MVC services to the services container
2021
services.AddMvc(configuration);
21-
});
2222

23+
services.Configure<MvcOptions>(options =>
24+
{
25+
options.AddXmlDataContractSerializerFormatter();
26+
});
27+
});
28+
2329
// Add MVC to the request pipeline
2430
app.UseMvc(routes =>
2531
{

0 commit comments

Comments
 (0)