Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
/// <summary>
/// A policy which <see cref="IInputFormatter"/>s can implement to indicate if they want the body model binder
/// to handle all exceptions. By default, all default <see cref="IInputFormatter"/>s implement this interface and
/// have a default value of <see cref="InputFormatterExceptionModelStatePolicy.MalformedInputExceptions"/>.
/// have a default value of <see cref="InputFormatterExceptionPolicy.MalformedInputExceptions"/>.
/// </summary>
public interface IInputFormatterExceptionPolicy
{
/// <summary>
/// Gets the flag to indicate if the body model binder should handle all exceptions. If an exception is handled,
/// the body model binder converts the exception into model state errors, else the exception is allowed to propagate.
/// </summary>
InputFormatterExceptionModelStatePolicy ExceptionPolicy { get; }
InputFormatterExceptionPolicy ExceptionPolicy { get; }
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;

namespace Microsoft.AspNetCore.Mvc.Formatters
{
/// <summary>
/// Defines the set of policies that determine how the model binding system interprets exceptions
/// thrown by an <see cref="IInputFormatter"/>. Applications should set
/// <c>MvcOptions.InputFormatterExceptionPolicy</c> to configure this setting.
/// </summary>
/// <remarks>
/// <para>
/// An <see cref="IInputFormatter"/> could throw an exception for several reasons, including:
/// <list type="bullet">
/// <item><description>malformed input</description></item>
/// <item><description>client disconnect or other I/O problem</description></item>
/// <item><description>
/// application configuration problems such as <see cref="TypeLoadException"/>
/// </description></item>
/// </list>
/// </para>
/// <para>
/// The policy associated with <see cref="InputFormatterExceptionPolicy.AllExceptions"/> treats
/// all such categories of problems as model state errors, and usually will be reported to the client as
/// an HTTP 400. This was the only policy supported by model binding in ASP.NET Core MVC 1.0, 1.1, and 2.0
/// and is still the default for historical reasons.
/// </para>
/// <para>
/// The policy associated with <see cref="InputFormatterExceptionPolicy.MalformedInputExceptions"/>
/// treats only <see cref="InputFormatterException"/> and its subclasses as model state errors. This means that
/// exceptions that are not related to the content of the HTTP request (such as a disconnect) will be rethrown,
/// which by default would cause an HTTP 500 response, unless there is exception-handling middleware enabled.
/// </para>
/// </remarks>
public enum InputFormatterExceptionPolicy
{
/// <summary>
/// This value indicates that all exceptions thrown by an <see cref="IInputFormatter"/> will be treated
/// as model state errors.
/// </summary>
AllExceptions = 0,

/// <summary>
/// This value indicates that only <see cref="InputFormatterException"/> and subclasses will be treated
/// as model state errors. All other exceptions types will be rethrown and can be handled by a higher
/// level exception handler, such as exception-handling middleware.
/// </summary>
MalformedInputExceptions = 1,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected override IReadOnlyDictionary<string, object> DefaultValues
if (Version >= CompatibilityVersion.Version_2_1)
{
values[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true;
values[nameof(MvcOptions.InputFormatterExceptionModelStatePolicy)] = InputFormatterExceptionModelStatePolicy.MalformedInputExceptions;
values[nameof(MvcOptions.InputFormatterExceptionPolicy)] = InputFormatterExceptionPolicy.MalformedInputExceptions;
}

return values;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,15 @@ public async Task BindModelAsync(ModelBindingContext bindingContext)

private bool ShouldHandleException(IInputFormatter formatter)
{
var policy = _options.InputFormatterExceptionModelStatePolicy;
var policy = _options.InputFormatterExceptionPolicy;

// Any explicit policy on the formatters takes precedence over the global policy on MvcOptions
if (formatter is IInputFormatterExceptionPolicy exceptionPolicy)
{
policy = exceptionPolicy.ExceptionPolicy;
}

return policy == InputFormatterExceptionModelStatePolicy.AllExceptions;
return policy == InputFormatterExceptionPolicy.AllExceptions;
}
}
}
55 changes: 37 additions & 18 deletions src/Microsoft.AspNetCore.Mvc.Core/MvcOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class MvcOptions : IEnumerable<ICompatibilitySwitch>
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;

// See CompatibilitySwitch.cs for guide on how to implement these.
private readonly CompatibilitySwitch<InputFormatterExceptionModelStatePolicy> _inputFormatterExceptionModelStatePolicy;
private readonly CompatibilitySwitch<InputFormatterExceptionPolicy> _inputFormatterExceptionPolicy;
private readonly CompatibilitySwitch<bool> _suppressBindingUndefinedValueToEnumType;
private readonly CompatibilitySwitch<bool> _suppressJsonDeserializationExceptionMessagesInModelState;
private readonly ICompatibilitySwitch[] _switches;
Expand All @@ -41,12 +41,12 @@ public MvcOptions()
ModelValidatorProviders = new List<IModelValidatorProvider>();
ValueProviderFactories = new List<IValueProviderFactory>();

_inputFormatterExceptionModelStatePolicy = new CompatibilitySwitch<InputFormatterExceptionModelStatePolicy>(nameof(InputFormatterExceptionModelStatePolicy), InputFormatterExceptionModelStatePolicy.AllExceptions);
_inputFormatterExceptionPolicy = new CompatibilitySwitch<InputFormatterExceptionPolicy>(nameof(InputFormatterExceptionPolicy), InputFormatterExceptionPolicy.AllExceptions);
_suppressBindingUndefinedValueToEnumType = new CompatibilitySwitch<bool>(nameof(SuppressBindingUndefinedValueToEnumType));
_suppressJsonDeserializationExceptionMessagesInModelState = new CompatibilitySwitch<bool>(nameof(SuppressJsonDeserializationExceptionMessagesInModelState));
_switches = new ICompatibilitySwitch[]
{
_inputFormatterExceptionModelStatePolicy,
_inputFormatterExceptionPolicy,
_suppressBindingUndefinedValueToEnumType,
_suppressJsonDeserializationExceptionMessagesInModelState,
};
Expand Down Expand Up @@ -87,6 +87,37 @@ public MvcOptions()
/// </summary>
public FormatterMappings FormatterMappings { get; }

/// <summary>
/// Gets or sets a value which determines how the model binding system interprets exceptions thrown by an <see cref="IInputFormatter"/>.
/// The default value of the property is <see cref="InputFormatterExceptionPolicy.AllExceptions"/>.
/// </summary>
/// <remarks>
/// <para>
/// This property is associated with a compatibility switch and can provide a different behavior depending on
/// the configured compatibility version for the application. See <see cref="CompatibilityVersion"/> for
/// guidance and examples of setting the application's compatibility version.
/// </para>
/// <para>
/// Configuring the desired value of the compatibility switch by calling this property's setter will take precedence
/// over the value implied by the application's <see cref="CompatibilityVersion"/>.
/// </para>
/// <para>
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_0"/> then
/// this setting will have the value <see cref="InputFormatterExceptionPolicy.AllExceptions"/> if
/// not explicitly configured.
/// </para>
/// <para>
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
/// higher then this setting will have the value
/// <see cref="InputFormatterExceptionPolicy.MalformedInputExceptions"/> if not explicitly configured.
/// </para>
/// </remarks>
public InputFormatterExceptionPolicy InputFormatterExceptionPolicy
{
get => _inputFormatterExceptionPolicy.Value;
set => _inputFormatterExceptionPolicy.Value = value;
}

/// <summary>
/// Gets a list of <see cref="IInputFormatter"/>s that are used by this application.
/// </summary>
Expand All @@ -103,16 +134,16 @@ public MvcOptions()
/// guidance and examples of setting the application's compatibility version.
/// </para>
/// <para>
/// Configuring the desired of the value compatibility switch by calling this property's setter will take precedence
/// Configuring the desired value of the compatibility switch by calling this property's setter will take precedence
/// over the value implied by the application's <see cref="CompatibilityVersion"/>.
/// </para>
/// <para>
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_0"/> then
/// this setting will have value <c>false</c> if not explicitly configured.
/// this setting will have the value <c>false</c> if not explicitly configured.
/// </para>
/// <para>
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
/// higher then this setting will have value <c>true</c> if not explicitly configured.
/// higher then this setting will have the value <c>true</c> if not explicitly configured.
/// </para>
/// </remarks>
public bool SuppressBindingUndefinedValueToEnumType
Expand Down Expand Up @@ -211,18 +242,6 @@ public int MaxModelValidationErrors
public bool RequireHttpsPermanent { get; set; }


/// <summary>
/// Gets or sets the option to determine if model binding should convert all exceptions (including ones not related to bad input)
/// that occur during deserialization in <see cref="IInputFormatter"/>s into model state errors.
/// This option applies only to custom <see cref="IInputFormatter"/>s.
/// Default is <see cref="InputFormatterExceptionModelStatePolicy.AllExceptions"/>.
/// </summary>
public InputFormatterExceptionModelStatePolicy InputFormatterExceptionModelStatePolicy
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm alphabetizing these things as I go. There's a ton of them so it seems worth doing. I'll another PR at the end to cover the rest.

{
get => _inputFormatterExceptionModelStatePolicy.Value;
set => _inputFormatterExceptionModelStatePolicy.Value = value;
}

/// <summary>
/// Gets or sets a flag to determine whether, if an action receives invalid JSON in
/// the request body, the JSON deserialization exception message should be replaced
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,15 +191,15 @@ public JsonInputFormatter(
}

/// <inheritdoc />
public virtual InputFormatterExceptionModelStatePolicy ExceptionPolicy
public virtual InputFormatterExceptionPolicy ExceptionPolicy
{
get
{
if (GetType() == typeof(JsonInputFormatter))
{
return InputFormatterExceptionModelStatePolicy.MalformedInputExceptions;
return InputFormatterExceptionPolicy.MalformedInputExceptions;
}
return InputFormatterExceptionModelStatePolicy.AllExceptions;
return InputFormatterExceptionPolicy.AllExceptions;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ public JsonPatchInputFormatter(
}

/// <inheritdoc />
public override InputFormatterExceptionModelStatePolicy ExceptionPolicy
public override InputFormatterExceptionPolicy ExceptionPolicy
{
get
{
if (GetType() == typeof(JsonPatchInputFormatter))
{
return InputFormatterExceptionModelStatePolicy.MalformedInputExceptions;
return InputFormatterExceptionPolicy.MalformedInputExceptions;
}
return InputFormatterExceptionModelStatePolicy.AllExceptions;
return InputFormatterExceptionPolicy.AllExceptions;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,15 @@ public DataContractSerializerSettings SerializerSettings
}

/// <inheritdoc />
public virtual InputFormatterExceptionModelStatePolicy ExceptionPolicy
public virtual InputFormatterExceptionPolicy ExceptionPolicy
{
get
{
if (GetType() == typeof(XmlDataContractSerializerInputFormatter))
{
return InputFormatterExceptionModelStatePolicy.MalformedInputExceptions;
return InputFormatterExceptionPolicy.MalformedInputExceptions;
}
return InputFormatterExceptionModelStatePolicy.AllExceptions;
return InputFormatterExceptionPolicy.AllExceptions;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ public int MaxDepth
public XmlDictionaryReaderQuotas XmlDictionaryReaderQuotas => _readerQuotas;

/// <inheritdoc />
public virtual InputFormatterExceptionModelStatePolicy ExceptionPolicy
public virtual InputFormatterExceptionPolicy ExceptionPolicy
{
get
{
if (GetType() == typeof(XmlSerializerInputFormatter))
{
return InputFormatterExceptionModelStatePolicy.MalformedInputExceptions;
return InputFormatterExceptionPolicy.MalformedInputExceptions;
}
return InputFormatterExceptionModelStatePolicy.AllExceptions;
return InputFormatterExceptionPolicy.AllExceptions;
}
}

Expand Down
Loading