[Fixes #1065] Need a way to specify "just type" with produces

This commit is contained in:
Kiran Challa 2015-02-02 16:43:28 -08:00
parent 45aae5956d
commit 4ecbe8c709
8 changed files with 114 additions and 29 deletions

View File

@ -17,6 +17,21 @@ namespace Microsoft.AspNet.Mvc
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ProducesAttribute : ResultFilterAttribute, IApiResponseMetadataProvider
{
/// <summary>
/// Initializes an instance of <see cref="ProducesAttribute"/>.
/// </summary>
/// <param name="type">The <see cref="Type"/> of object that is going to be written in the response.</param>
public ProducesAttribute([NotNull] Type type)
{
Type = type;
ContentTypes = new List<MediaTypeHeaderValue>();
}
/// <summary>
/// Initializes an instance of <see cref="ProducesAttribute"/> with allowed content types.
/// </summary>
/// <param name="contentType">The allowed content type for a response.</param>
/// <param name="additionalContentTypes">Additional allowed content types for a response.</param>
public ProducesAttribute([NotNull] string contentType, params string[] additionalContentTypes)
{
ContentTypes = GetContentTypes(contentType, additionalContentTypes);

View File

@ -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; }
}
}
}

View File

@ -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 = "<User xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" " +
"xmlns=\"http://schemas.datacontract.org/2004/07/ConnegWebSite\">" +
"<Address>One Microsoft Way</Address><Name>John</Name></User>";
// 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");

View File

@ -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-*",

View File

@ -15,7 +15,7 @@ namespace ApiExplorerWebSite
}
[HttpGet("Action")]
[ProducesType(typeof(Customer))]
[Produces(typeof(Customer))]
public object GetAction()
{
return null;

View File

@ -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;

View File

@ -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<MediaTypeHeaderValue> contentTypes)
{
}
}
}

View File

@ -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" };
}