Skip to content

Commit e45c2ef

Browse files
committed
Support setting content types in ProducesResponseTypeAttribute to close #34542
1 parent a8cd189 commit e45c2ef

File tree

1 file changed

+63
-2
lines changed

1 file changed

+63
-2
lines changed

src/Mvc/Mvc.Core/src/ProducesResponseTypeAttribute.cs

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using Microsoft.AspNetCore.Mvc.ApiExplorer;
66
using Microsoft.AspNetCore.Mvc.Formatters;
7+
using Microsoft.Net.Http.Headers;
78

89
namespace Microsoft.AspNetCore.Mvc
910
{
@@ -33,6 +34,37 @@ public ProducesResponseTypeAttribute(Type type, int statusCode)
3334
Type = type ?? throw new ArgumentNullException(nameof(type));
3435
StatusCode = statusCode;
3536
IsResponseTypeSetByDefault = false;
37+
ContentTypes = new();
38+
}
39+
40+
/// <summary>
41+
/// Initializes an instance of <see cref="ProducesResponseTypeAttribute"/>.
42+
/// </summary>
43+
/// <param name="type">The <see cref="Type"/> of object that is going to be written in the response.</param>
44+
/// <param name="statusCode">The HTTP response status code.</param>
45+
/// <param name="contentType">The content type associated with the response.</param>
46+
/// <param name="additionalContentTypes">Additional content types supported by the response.</param>
47+
public ProducesResponseTypeAttribute(Type type, int statusCode, string? contentType, params string[] additionalContentTypes)
48+
{
49+
Type = type ?? throw new ArgumentNullException(nameof(type));
50+
StatusCode = statusCode;
51+
IsResponseTypeSetByDefault = false;
52+
53+
if (!string.IsNullOrEmpty(contentType))
54+
{
55+
MediaTypeHeaderValue.Parse(contentType);
56+
for (var i = 0; i < additionalContentTypes.Length; i++)
57+
{
58+
MediaTypeHeaderValue.Parse(additionalContentTypes[i]);
59+
}
60+
61+
ContentTypes = GetContentTypes(contentType, additionalContentTypes);
62+
}
63+
else
64+
{
65+
ContentTypes = new();
66+
}
67+
3668
}
3769

3870
/// <summary>
@@ -45,6 +77,11 @@ public ProducesResponseTypeAttribute(Type type, int statusCode)
4577
/// </summary>
4678
public int StatusCode { get; set; }
4779

80+
/// <summary>
81+
/// Gets or sets the content types supported by the response.
82+
/// </summary>
83+
public MediaTypeCollection ContentTypes { get; set; }
84+
4885
/// <summary>
4986
/// Used to distinguish a `Type` set by default in the constructor versus
5087
/// one provided by the user.
@@ -58,9 +95,33 @@ public ProducesResponseTypeAttribute(Type type, int statusCode)
5895
internal bool IsResponseTypeSetByDefault { get; }
5996

6097
/// <inheritdoc />
61-
void IApiResponseMetadataProvider.SetContentTypes(MediaTypeCollection contentTypes)
98+
public void SetContentTypes(MediaTypeCollection contentTypes)
6299
{
63-
// Users are supposed to use the 'Produces' attribute to set the content types that an action can support.
100+
contentTypes.Clear();
101+
foreach (var contentType in ContentTypes)
102+
{
103+
contentTypes.Add(contentType);
104+
}
105+
}
106+
107+
private MediaTypeCollection GetContentTypes(string contentType, string[] additionalContentTypes)
108+
{
109+
List<string> completeContentTypes = new(additionalContentTypes.Length + 1);
110+
completeContentTypes.Add(contentType);
111+
completeContentTypes.AddRange(additionalContentTypes);
112+
MediaTypeCollection contentTypes = new();
113+
foreach (var type in completeContentTypes)
114+
{
115+
var mediaType = new MediaType(type);
116+
if (mediaType.HasWildcard)
117+
{
118+
throw new InvalidOperationException("Content types with wild cards are not supported.");
119+
}
120+
121+
contentTypes.Add(type);
122+
}
123+
124+
return contentTypes;
64125
}
65126
}
66127
}

0 commit comments

Comments
 (0)