diff --git a/src/Microsoft.AspNet.Mvc.Core/Filters/ProducesAttribute.cs b/src/Microsoft.AspNet.Mvc.Core/Filters/ProducesAttribute.cs
index 2e89971978..8d7bddaa75 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Filters/ProducesAttribute.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Filters/ProducesAttribute.cs
@@ -17,6 +17,21 @@ namespace Microsoft.AspNet.Mvc
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ProducesAttribute : ResultFilterAttribute, IApiResponseMetadataProvider
{
+ ///
+ /// Initializes an instance of .
+ ///
+ /// The of object that is going to be written in the response.
+ public ProducesAttribute([NotNull] Type type)
+ {
+ Type = type;
+ ContentTypes = new List();
+ }
+
+ ///
+ /// Initializes an instance of with allowed content types.
+ ///
+ /// The allowed content type for a response.
+ /// Additional allowed content types for a response.
public ProducesAttribute([NotNull] string contentType, params string[] additionalContentTypes)
{
ContentTypes = GetContentTypes(contentType, additionalContentTypes);
diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Filters/ProducesAttributeTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Filters/ProducesAttributeTests.cs
index d056dbd575..5fa9d9c948 100644
--- a/test/Microsoft.AspNet.Mvc.Core.Test/Filters/ProducesAttributeTests.cs
+++ b/test/Microsoft.AspNet.Mvc.Core.Test/Filters/ProducesAttributeTests.cs
@@ -128,6 +128,29 @@ namespace Microsoft.AspNet.Mvc.Test
ex.Message);
}
+ [Fact]
+ public void ProducesAttribute_WithTypeOnly_SetsTypeProperty()
+ {
+ // Arrange
+ var personType = typeof(Person);
+ var producesAttribute = new ProducesAttribute(personType);
+
+ // Act and Assert
+ Assert.NotNull(producesAttribute.Type);
+ Assert.Same(personType, producesAttribute.Type);
+ }
+
+ [Fact]
+ public void ProducesAttribute_WithTypeOnly_DoesNotSetContentTypes()
+ {
+ // Arrange
+ var producesAttribute = new ProducesAttribute(typeof(Person));
+
+ // Act and Assert
+ Assert.NotNull(producesAttribute.ContentTypes);
+ Assert.Empty(producesAttribute.ContentTypes);
+ }
+
private static void ValidateMediaType(MediaTypeHeaderValue expectedMediaType, MediaTypeHeaderValue actualMediaType)
{
Assert.Equal(expectedMediaType.MediaType, actualMediaType.MediaType);
@@ -160,5 +183,12 @@ namespace Microsoft.AspNet.Mvc.Test
{
return new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
}
+
+ private class Person
+ {
+ public int Id { get; set; }
+
+ public string Name { get; set; }
+ }
}
}
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs
index 2e560c4e18..61a09e159b 100644
--- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs
@@ -2,14 +2,19 @@
// 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.Net;
using System.Net.Http;
using System.Net.Http.Headers;
+using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
+using System.Xml;
+using System.Xml.Serialization;
using ConnegWebSite;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.TestHost;
+using Microsoft.AspNet.Mvc.Xml;
using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests
@@ -90,6 +95,48 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
}
+ [Fact]
+ public async Task ProducesAttributeWithTypeOnly_RunsRegularContentNegotiation()
+ {
+ // Arrange
+ var server = TestServer.Create(_provider, _app);
+ var client = server.CreateClient();
+ client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ var expectedContentType = MediaTypeHeaderValue.Parse("application/json;charset=utf-8");
+ var expectedOutput = "{\"Name\":\"John\",\"Address\":\"One Microsoft Way\"}";
+
+ // Act
+ var response = await client.GetAsync("http://localhost/Home/UserInfo_ProducesWithTypeOnly");
+
+ // Assert
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
+ var actual = await response.Content.ReadAsStringAsync();
+ Assert.Equal(expectedOutput, actual);
+ }
+
+ [Fact]
+ public async Task ProducesAttribute_WithTypeAndContentType_UsesContentType()
+ {
+ // Arrange
+ var server = TestServer.Create(_provider, _app);
+ var client = server.CreateClient();
+ client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
+ var expectedContentType = MediaTypeHeaderValue.Parse("application/xml;charset=utf-8");
+ var expectedOutput = "" +
+ "One Microsoft WayJohn";
+
+ // Act
+ var response = await client.GetAsync("http://localhost/Home/UserInfo_ProducesWithTypeAndContentType");
+
+ // Assert
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal(expectedContentType, response.Content.Headers.ContentType);
+ var actual = await response.Content.ReadAsStringAsync();
+ XmlAssert.Equal(expectedOutput, actual);
+ }
+
[Fact]
public async Task NoMatchingFormatter_ForTheGivenContentType_Returns406()
{
@@ -426,7 +473,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
{
// Arrange
var server = TestServer.Create(_provider, _app);
- var client = server.CreateClient();
+ var client = server.CreateClient();
// Act
var response = await client.GetAsync("http://localhost/FormatFilter/MethodWithFormatFilter");
diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json
index dd286a5276..ead5aa95ad 100644
--- a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json
+++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json
@@ -46,6 +46,7 @@
"WebApiCompatShimWebSite": "1.0.0",
"Microsoft.AspNet.TestHost": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
+ "Microsoft.AspNet.Mvc.Xml": "6.0.0-*",
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
"MvcTagHelpersWebSite": "1.0.0",
"Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*",
diff --git a/test/WebSites/ApiExplorerWebSite/Controllers/ApiExplorerResponseTypeOverrideOnActionController.cs b/test/WebSites/ApiExplorerWebSite/Controllers/ApiExplorerResponseTypeOverrideOnActionController.cs
index e32179b916..b5de7a6bd6 100644
--- a/test/WebSites/ApiExplorerWebSite/Controllers/ApiExplorerResponseTypeOverrideOnActionController.cs
+++ b/test/WebSites/ApiExplorerWebSite/Controllers/ApiExplorerResponseTypeOverrideOnActionController.cs
@@ -15,7 +15,7 @@ namespace ApiExplorerWebSite
}
[HttpGet("Action")]
- [ProducesType(typeof(Customer))]
+ [Produces(typeof(Customer))]
public object GetAction()
{
return null;
diff --git a/test/WebSites/ApiExplorerWebSite/Controllers/ApiExplorerResponseTypeWithAttributeController.cs b/test/WebSites/ApiExplorerWebSite/Controllers/ApiExplorerResponseTypeWithAttributeController.cs
index 6608d4c792..ffee8f0769 100644
--- a/test/WebSites/ApiExplorerWebSite/Controllers/ApiExplorerResponseTypeWithAttributeController.cs
+++ b/test/WebSites/ApiExplorerWebSite/Controllers/ApiExplorerResponseTypeWithAttributeController.cs
@@ -10,7 +10,7 @@ namespace ApiExplorerWebSite
public class ApiExplorerResponseTypeWithAttributeController : Controller
{
[HttpGet]
- [ProducesType(typeof(Customer))]
+ [Produces(typeof(Customer))]
public void GetVoid()
{
}
@@ -37,7 +37,7 @@ namespace ApiExplorerWebSite
}
[HttpGet]
- [ProducesType(typeof(Customer))] // It's possible to lie about what type you return
+ [Produces(typeof(Customer))] // It's possible to lie about what type you return
public Product GetProduct()
{
return null;
diff --git a/test/WebSites/ApiExplorerWebSite/ProducesTypeAttribute.cs b/test/WebSites/ApiExplorerWebSite/ProducesTypeAttribute.cs
deleted file mode 100644
index 24bbb8b5ea..0000000000
--- a/test/WebSites/ApiExplorerWebSite/ProducesTypeAttribute.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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 Microsoft.AspNet.Mvc;
-using Microsoft.AspNet.Mvc.Description;
-using Microsoft.Net.Http.Headers;
-
-namespace ApiExplorerWebSite
-{
- public class ProducesTypeAttribute : ResultFilterAttribute, IApiResponseMetadataProvider
- {
- public ProducesTypeAttribute(Type type)
- {
- Type = type;
- }
-
- public Type Type { get; private set; }
-
- public void SetContentTypes(IList contentTypes)
- {
- }
- }
-}
\ No newline at end of file
diff --git a/test/WebSites/ConnegWebSite/Controllers/HomeController.cs b/test/WebSites/ConnegWebSite/Controllers/HomeController.cs
index e54e8e8ad0..6788a39f1c 100644
--- a/test/WebSites/ConnegWebSite/Controllers/HomeController.cs
+++ b/test/WebSites/ConnegWebSite/Controllers/HomeController.cs
@@ -13,6 +13,23 @@ namespace ConnegWebSite
}
public User UserInfo()
+ {
+ return CreateUser();
+ }
+
+ [Produces(typeof(User))]
+ public IActionResult UserInfo_ProducesWithTypeOnly()
+ {
+ return new ObjectResult(CreateUser());
+ }
+
+ [Produces("application/xml", Type = typeof(User))]
+ public IActionResult UserInfo_ProducesWithTypeAndContentType()
+ {
+ return new ObjectResult(CreateUser());
+ }
+
+ private User CreateUser()
{
return new User() { Name = "John", Address = "One Microsoft Way" };
}