[Fixes #4050] Throw an exception on CanRead/Write and GetSupportedContentTypes when the list of media types is empty
This commit is contained in:
parent
7337f50112
commit
910f0139f9
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.Core;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||
{
|
||||
|
|
@ -43,6 +44,15 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
/// <inheritdoc />
|
||||
public virtual bool CanRead(InputFormatterContext context)
|
||||
{
|
||||
if (SupportedMediaTypes.Count == 0)
|
||||
{
|
||||
var message = Resources.FormatFormatter_NoMediaTypes(
|
||||
GetType().FullName,
|
||||
nameof(SupportedMediaTypes));
|
||||
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (!CanReadType(context.ModelType))
|
||||
{
|
||||
return false;
|
||||
|
|
@ -111,6 +121,15 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
/// <inheritdoc />
|
||||
public virtual IReadOnlyList<string> GetSupportedContentTypes(string contentType, Type objectType)
|
||||
{
|
||||
if (SupportedMediaTypes.Count == 0)
|
||||
{
|
||||
var message = Resources.FormatFormatter_NoMediaTypes(
|
||||
GetType().FullName,
|
||||
nameof(SupportedMediaTypes));
|
||||
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (!CanReadType(objectType))
|
||||
{
|
||||
return null;
|
||||
|
|
@ -119,7 +138,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
if (contentType == null)
|
||||
{
|
||||
// If contentType is null, then any type we support is valid.
|
||||
return SupportedMediaTypes.Count > 0 ? SupportedMediaTypes : null;
|
||||
return SupportedMediaTypes;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.Core;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Formatters
|
||||
|
|
@ -14,19 +15,11 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
/// </summary>
|
||||
public abstract class OutputFormatter : IOutputFormatter, IApiResponseFormatMetadataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OutputFormatter"/> class.
|
||||
/// </summary>
|
||||
protected OutputFormatter()
|
||||
{
|
||||
SupportedMediaTypes = new MediaTypeCollection();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mutable collection of media type elements supported by
|
||||
/// this <see cref="OutputFormatter"/>.
|
||||
/// </summary>
|
||||
public MediaTypeCollection SupportedMediaTypes { get; }
|
||||
public MediaTypeCollection SupportedMediaTypes { get; } = new MediaTypeCollection();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether or not the given type can be written by this serializer.
|
||||
|
|
@ -43,6 +36,15 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
string contentType,
|
||||
Type objectType)
|
||||
{
|
||||
if (SupportedMediaTypes.Count == 0)
|
||||
{
|
||||
var message = Resources.FormatFormatter_NoMediaTypes(
|
||||
GetType().FullName,
|
||||
nameof(SupportedMediaTypes));
|
||||
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (!CanWriteType(objectType))
|
||||
{
|
||||
return null;
|
||||
|
|
@ -51,7 +53,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
if (contentType == null)
|
||||
{
|
||||
// If contentType is null, then any type we support is valid.
|
||||
return SupportedMediaTypes.Count > 0 ? SupportedMediaTypes : null;
|
||||
return SupportedMediaTypes;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -87,6 +89,15 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (SupportedMediaTypes.Count == 0)
|
||||
{
|
||||
var message = Resources.FormatFormatter_NoMediaTypes(
|
||||
GetType().FullName,
|
||||
nameof(SupportedMediaTypes));
|
||||
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
if (!CanWriteType(context.ObjectType))
|
||||
{
|
||||
return false;
|
||||
|
|
@ -96,15 +107,8 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
{
|
||||
// If the desired content type is set to null, then the current formatter can write anything
|
||||
// it wants.
|
||||
if (SupportedMediaTypes.Count > 0)
|
||||
{
|
||||
context.ContentType = new StringSegment(SupportedMediaTypes[0]);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
context.ContentType = new StringSegment(SupportedMediaTypes[0]);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1146,6 +1146,22 @@ namespace Microsoft.AspNetCore.Mvc.Core
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("TextOutpurFormatter_WriteResponseBodyAsynNotSupported"), p0, p1, p2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No media types found in '{0}.{1}'. Add at least one media type to the list of supported media types.
|
||||
/// </summary>
|
||||
internal static string Formatter_NoMediaTypes
|
||||
{
|
||||
get { return GetString("Formatter_NoMediaTypes"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No media types found in '{0}.{1}'. Add at least one media type to the list of supported media types.
|
||||
/// </summary>
|
||||
internal static string FormatFormatter_NoMediaTypes(object p0, object p1)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("Formatter_NoMediaTypes"), p0, p1);
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -340,4 +340,7 @@
|
|||
<data name="TextOutpurFormatter_WriteResponseBodyAsynNotSupported" xml:space="preserve">
|
||||
<value>'{0}' is not supported by '{1}'. Use '{2}' instead.</value>
|
||||
</data>
|
||||
<data name="Formatter_NoMediaTypes" xml:space="preserve">
|
||||
<value>No media types found in '{0}.{1}'. Add at least one media type to the list of supported media types.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http.Internal;
|
||||
|
|
@ -382,6 +383,41 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
Assert.Collection(results, c => Assert.Equal("text/xml", c));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanRead_ThrowsInvalidOperationException_IfMediaTypesListIsEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new BadConfigurationFormatter();
|
||||
var context = new InputFormatterContext(
|
||||
new DefaultHttpContext(),
|
||||
"",
|
||||
new ModelStateDictionary(),
|
||||
new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
|
||||
(s, e) => new StreamReader(s, e));
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() => formatter.CanRead(context));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSupportedContentTypes_ThrowsInvalidOperationException_IfMediaTypesListIsEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new BadConfigurationFormatter();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => formatter.GetSupportedContentTypes("application/json", typeof(object)));
|
||||
}
|
||||
|
||||
private class BadConfigurationFormatter : InputFormatter
|
||||
{
|
||||
public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class TestFormatter : InputFormatter
|
||||
{
|
||||
public IList<Type> SupportedTypes { get; } = new List<Type>();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
|
@ -138,24 +139,6 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
Assert.Null(contentTypes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSupportedContentTypes_ReturnsAllContentTypes_ReturnsNullWithNoSupportedContentTypes()
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new TestOutputFormatter();
|
||||
|
||||
// Intentionally empty
|
||||
formatter.SupportedMediaTypes.Clear();
|
||||
|
||||
// Act
|
||||
var contentTypes = formatter.GetSupportedContentTypes(
|
||||
contentType: null,
|
||||
objectType: typeof(int));
|
||||
|
||||
// Assert
|
||||
Assert.Null(contentTypes);
|
||||
}
|
||||
|
||||
private class TypeSpecificFormatter : OutputFormatter
|
||||
{
|
||||
public List<Type> SupportedTypes { get; } = new List<Type>();
|
||||
|
|
@ -171,6 +154,35 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanWrite_ThrowsInvalidOperationException_IfMediaTypesListIsEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new TestOutputFormatter();
|
||||
formatter.SupportedMediaTypes.Clear();
|
||||
|
||||
var context = new OutputFormatterWriteContext(
|
||||
new DefaultHttpContext(),
|
||||
(s, e) => new StreamWriter(s, e),
|
||||
typeof(object),
|
||||
new object());
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() => formatter.CanWriteResult(context));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetSupportedContentTypes_ThrowsInvalidOperationException_IfMediaTypesListIsEmpty()
|
||||
{
|
||||
// Arrange
|
||||
var formatter = new TestOutputFormatter();
|
||||
formatter.SupportedMediaTypes.Clear();
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => formatter.GetSupportedContentTypes("application/json", typeof(object)));
|
||||
}
|
||||
|
||||
private class TestOutputFormatter : OutputFormatter
|
||||
{
|
||||
public TestOutputFormatter()
|
||||
|
|
|
|||
Loading…
Reference in New Issue