diff --git a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/MediaTypeHeaderValue.cs b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/MediaTypeHeaderValue.cs
index c8011b52a4..a9b363a255 100644
--- a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/MediaTypeHeaderValue.cs
+++ b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/MediaTypeHeaderValue.cs
@@ -187,7 +187,7 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
return false;
}
- if (parameterValue2 == null || !parameterValue2.Equals(parameters1[parameterKey]))
+ if (!string.Equals(parameterValue2, parameters1[parameterKey], StringComparison.OrdinalIgnoreCase))
{
return false;
}
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs
index b955261d07..28e152c4f3 100644
--- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs
@@ -105,6 +105,33 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(HttpStatusCode.NotAcceptable, response.StatusCode);
}
+ [Theory]
+ [InlineData("ContactInfoUsingV3Format", "text/vcard; charset=utf-8; version=v3.0", "BEGIN:VCARD#FN:John Williams#END:VCARD#")]
+ [InlineData("ContactInfoUsingV4Format", "text/vcard; charset=utf-8; version=v4.0", "BEGIN:VCARD#FN:John Williams#GENDER:M#END:VCARD#")]
+ public async Task ProducesAttribute_WithMediaTypeHavingParameters_IsCaseInsensitiveMatch(
+ string action,
+ string expectedMediaType,
+ string expectedResponseBody)
+ {
+ // Arrange
+ var server = TestServer.Create(_provider, _app);
+ var client = server.CreateClient();
+ expectedResponseBody = expectedResponseBody.Replace("#", Environment.NewLine);
+
+ // Act
+ var response = await client.GetAsync("http://localhost/ProducesWithMediaTypeParameters/" + action);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.NotNull(response.Content);
+ var contentType = response.Content.Headers.ContentType;
+ Assert.NotNull(contentType);
+ Assert.Equal(expectedMediaType, contentType.ToString());
+
+ var actualResponseBody = await response.Content.ReadAsStringAsync();
+ Assert.Equal(expectedResponseBody, actualResponseBody);
+ }
+
[Fact]
public async Task ProducesContentAttribute_OnAction_OverridesTheValueOnClass()
{
diff --git a/test/Microsoft.AspNet.Mvc.HeaderValueAbstractions.Test/MediaTypeHeaderValueParsingTests.cs b/test/Microsoft.AspNet.Mvc.HeaderValueAbstractions.Test/MediaTypeHeaderValueParsingTests.cs
index 4e138a5725..f3b199835d 100644
--- a/test/Microsoft.AspNet.Mvc.HeaderValueAbstractions.Test/MediaTypeHeaderValueParsingTests.cs
+++ b/test/Microsoft.AspNet.Mvc.HeaderValueAbstractions.Test/MediaTypeHeaderValueParsingTests.cs
@@ -103,7 +103,12 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
[InlineData("text/plain;", "*/*;charset=utf-8;", true)]
[InlineData("text/plain;", "text/*;charset=utf-8;", true)]
[InlineData("text/plain;", "text/plain;charset=utf-8;", true)]
+ [InlineData("text/plain;version=v1", "text/plain;version=", false)]
+ [InlineData("text/plain;version=v1", "Text/plain;Version=v1", true)]
+ [InlineData("text/plain;version=v1", "tExT/plain;version=V1", true)]
+ [InlineData("text/plain;version=v1", "TEXT/PLAIN;VERSION=V1", true)]
[InlineData("text/plain;charset=utf-8;foo=bar;q=0.0", "text/plain;charset=utf-8;foo=bar;q=0.0", true)]
+ [InlineData("text/plain;charset=utf-8;foo=bar;q=0.0", "text/plain;foo=bar;q=0.0;charset=utf-8", true)] // different order of parameters
[InlineData("text/plain;charset=utf-8;foo=bar;q=0.0", "text/*;charset=utf-8;foo=bar;q=0.0", true)]
[InlineData("text/plain;charset=utf-8;foo=bar;q=0.0", "*/*;charset=utf-8;foo=bar;q=0.0", true)]
[InlineData("*/*;", "text/plain;charset=utf-8;foo=bar;q=0.0", false)]
@@ -111,8 +116,8 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
[InlineData("text/plain;missingparam=4;", "text/plain;charset=utf-8;foo=bar;q=0.0", false)]
[InlineData("text/plain;missingparam=4;", "text/*;charset=utf-8;foo=bar;q=0.0", false)]
[InlineData("text/plain;missingparam=4;", "*/*;charset=utf-8;foo=bar;q=0.0", false)]
- public void MediaTypeHeaderValue_IsSubTypeTests(string mediaType1,
- string mediaType2,
+ public void MediaTypeHeaderValue_IsSubTypeTests(string mediaType1, // Example: Formatter's supported media type
+ string mediaType2, // Example: Accept header media type
bool isMediaType1Subset)
{
// Arrange
@@ -132,6 +137,8 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions
[InlineData("text/plain;charset=utf-16;foo=bar", "text/json;charset=utf-16;foo=bar")]
[InlineData("text/plain;charset=utf-16;foo=bar", "application/plain;charset=utf-16;foo=bar")]
[InlineData("text/plain;charset=utf-16;foo=bar", "application/json;charset=utf-8;foo=bar1")]
+ [InlineData("text/plain; charset=utf-16; foo=bar", "application/json;charset=utf-8;foo=bar1")]
+ [InlineData("text/plain;charset = utf-16;foo = bar", "application/json;charset=utf-8;foo=bar1")]
public void MediaTypeHeaderValue_UpdateValue_RawValueGetsUpdated(string mediaTypeValue,
string expectedRawValue)
{
diff --git a/test/WebSites/ConnegWebSite/ConnegWebsite.kproj b/test/WebSites/ConnegWebSite/ConnegWebsite.kproj
index 5ecfd616de..7f20e114b8 100644
--- a/test/WebSites/ConnegWebSite/ConnegWebsite.kproj
+++ b/test/WebSites/ConnegWebSite/ConnegWebsite.kproj
@@ -1,4 +1,4 @@
-
+
14.0
@@ -11,4 +11,4 @@
..\..\..\artifacts\bin\$(MSBuildProjectName)\
-
+
\ No newline at end of file
diff --git a/test/WebSites/ConnegWebSite/Controllers/ProducesWithMediaTypeParametersController.cs b/test/WebSites/ConnegWebSite/Controllers/ProducesWithMediaTypeParametersController.cs
new file mode 100644
index 0000000000..e87db2ffa9
--- /dev/null
+++ b/test/WebSites/ConnegWebSite/Controllers/ProducesWithMediaTypeParametersController.cs
@@ -0,0 +1,42 @@
+// 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 ConnegWebsite.Models;
+using Microsoft.AspNet.Mvc;
+
+namespace ConnegWebsite
+{
+ public class ProducesWithMediaTypeParametersController : Controller
+ {
+ public override void OnActionExecuted(ActionExecutedContext context)
+ {
+ var result = context.Result as ObjectResult;
+
+ if (result != null)
+ {
+ result.Formatters.Add(new VCardFormatter_V3());
+ result.Formatters.Add(new VCardFormatter_V4());
+ }
+ }
+
+ [Produces("text/vcard;VERSION=V3.0")]
+ public Contact ContactInfoUsingV3Format()
+ {
+ return new Contact()
+ {
+ Name = "John Williams",
+ Gender = GenderType.Male
+ };
+ }
+
+ [Produces("text/vcard;VERSION=V4.0")]
+ public Contact ContactInfoUsingV4Format()
+ {
+ return new Contact()
+ {
+ Name = "John Williams",
+ Gender = GenderType.Male
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/WebSites/ConnegWebSite/Models/Contact.cs b/test/WebSites/ConnegWebSite/Models/Contact.cs
new file mode 100644
index 0000000000..287eb5e444
--- /dev/null
+++ b/test/WebSites/ConnegWebSite/Models/Contact.cs
@@ -0,0 +1,34 @@
+// 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.
+
+namespace ConnegWebsite.Models
+{
+ public class Contact
+ {
+ public int ContactId { get; set; }
+
+ public string Name { get; set; }
+
+ public GenderType Gender { get; set; }
+
+ public string Address { get; set; }
+
+ public string City { get; set; }
+
+ public string State { get; set; }
+
+ public string Zip { get; set; }
+
+ public string Email { get; set; }
+
+ public string Twitter { get; set; }
+
+ public string Self { get; set; }
+ }
+
+ public enum GenderType
+ {
+ Male,
+ Female
+ }
+}
\ No newline at end of file
diff --git a/test/WebSites/ConnegWebSite/VCardFormatter_V3.cs b/test/WebSites/ConnegWebSite/VCardFormatter_V3.cs
new file mode 100644
index 0000000000..fbcb6af7f2
--- /dev/null
+++ b/test/WebSites/ConnegWebSite/VCardFormatter_V3.cs
@@ -0,0 +1,48 @@
+// 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.IO;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using ConnegWebsite.Models;
+using Microsoft.AspNet.Mvc;
+using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
+
+namespace ConnegWebsite
+{
+ ///
+ /// Provides contact information of a person through VCard format.
+ ///
+ public class VCardFormatter_V3 : OutputFormatter
+ {
+ public VCardFormatter_V3()
+ {
+ SupportedEncodings.Add(Encoding.UTF8);
+ SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard;version=v3.0"));
+ }
+
+ protected override bool CanWriteType(Type declaredType, Type runtimeType)
+ {
+ return typeof(Contact).GetTypeInfo().IsAssignableFrom(runtimeType.GetTypeInfo());
+ }
+
+ public override async Task WriteResponseBodyAsync(OutputFormatterContext context)
+ {
+ var contact = (Contact)context.Object;
+
+ var builder = new StringBuilder();
+ builder.AppendLine("BEGIN:VCARD");
+ builder.AppendFormat("FN:{0}", contact.Name);
+ builder.AppendLine();
+ builder.AppendLine("END:VCARD");
+
+ var responseStream = new DelegatingStream(context.ActionContext.HttpContext.Response.Body);
+ using (var writer = new StreamWriter(responseStream, context.SelectedEncoding, bufferSize: 1024))
+ {
+ await writer.WriteAsync(builder.ToString());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/WebSites/ConnegWebSite/VCardFormatter_V4.cs b/test/WebSites/ConnegWebSite/VCardFormatter_V4.cs
new file mode 100644
index 0000000000..a77f02a176
--- /dev/null
+++ b/test/WebSites/ConnegWebSite/VCardFormatter_V4.cs
@@ -0,0 +1,51 @@
+// 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.IO;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using ConnegWebsite.Models;
+using Microsoft.AspNet.Mvc;
+using Microsoft.AspNet.Mvc.HeaderValueAbstractions;
+
+namespace ConnegWebsite
+{
+ ///
+ /// Provides contact information of a person through VCard format.
+ /// In version 4.0 of VCard format, Gender is a supported property.
+ ///
+ public class VCardFormatter_V4 : OutputFormatter
+ {
+ public VCardFormatter_V4()
+ {
+ SupportedEncodings.Add(Encoding.UTF8);
+ SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard;version=v4.0"));
+ }
+
+ protected override bool CanWriteType(Type declaredType, Type runtimeType)
+ {
+ return typeof(Contact).GetTypeInfo().IsAssignableFrom(runtimeType.GetTypeInfo());
+ }
+
+ public override async Task WriteResponseBodyAsync(OutputFormatterContext context)
+ {
+ var contact = (Contact)context.Object;
+
+ var builder = new StringBuilder();
+ builder.AppendLine("BEGIN:VCARD");
+ builder.AppendFormat("FN:{0}", contact.Name);
+ builder.AppendLine();
+ builder.AppendFormat("GENDER:{0}", (contact.Gender == GenderType.Male) ? "M" : "F");
+ builder.AppendLine();
+ builder.AppendLine("END:VCARD");
+
+ var responseStream = new DelegatingStream(context.ActionContext.HttpContext.Response.Body);
+ using (var writer = new StreamWriter(responseStream, context.SelectedEncoding, bufferSize: 1024))
+ {
+ await writer.WriteAsync(builder.ToString());
+ }
+ }
+ }
+}
\ No newline at end of file