diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBinderProviderContext.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBinderProviderContext.cs
index 2d01d6acb9..eb2136e413 100644
--- a/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBinderProviderContext.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/ModelBinding/ModelBinderProviderContext.cs
@@ -1,6 +1,8 @@
// 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.ModelBinding
{
///
@@ -29,5 +31,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// Gets the .
///
public abstract IModelMetadataProvider MetadataProvider { get; }
+
+ ///
+ /// Gets the .
+ ///
+ public virtual IServiceProvider Services { get; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs
index 03ffe21330..86c4a1968c 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs
@@ -20,6 +20,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
@@ -236,10 +237,11 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton(s =>
{
var options = s.GetRequiredService>().Value;
+ var loggerFactory = s.GetRequiredService();
var metadataProvider = s.GetRequiredService();
var modelBinderFactory = s.GetRequiredService();
var modelValidatorProvider = new CompositeModelValidatorProvider(options.ModelValidatorProviders);
- return new ParameterBinder(metadataProvider, modelBinderFactory, modelValidatorProvider);
+ return new ParameterBinder(metadataProvider, modelBinderFactory, modelValidatorProvider, loggerFactory);
});
//
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreLoggerExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreLoggerExtensions.cs
index 4cc0f8f900..d65da95d40 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreLoggerExtensions.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreLoggerExtensions.cs
@@ -11,10 +11,12 @@ using System.Security.Claims;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
+using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Formatters.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
@@ -98,7 +100,30 @@ namespace Microsoft.AspNetCore.Mvc.Internal
private static readonly Action _inferredParameterSource;
private static readonly Action _unableToInferParameterSources;
-
+ private static readonly Action _registeredModelBinderProviders;
+ private static readonly Action _foundNoValueForPropertyInRequest;
+ private static readonly Action _foundNoValueInRequest;
+ private static readonly Action _noPublicSettableProperties;
+ private static readonly Action _cannotBindToComplexType;
+ private static readonly Action _cannotBindToFilesCollectionDueToUnsupportedContentType;
+ private static readonly Action _cannotCreateHeaderModelBinder;
+ private static readonly Action _noFilesFoundInRequest;
+ private static readonly Action _noNonIndexBasedFormatFoundForCollection;
+ private static readonly Action _attemptingToBindCollectionUsingIndices;
+ private static readonly Action _attemptingToBindCollectionOfKeyValuePair;
+ private static readonly Action _noKeyValueFormatForDictionaryModelBinder;
+ private static readonly Action _attemptingToBindPropertyModel;
+ private static readonly Action _doneAttemptingToBindPropertyModel;
+ private static readonly Action _attemptingToBindModel;
+ private static readonly Action _doneAttemptingToBindModel;
+ private static readonly Action _attemptingToBindParameter;
+ private static readonly Action _doneAttemptingToBindParameter;
+ private static readonly Action _attemptingToBindProperty;
+ private static readonly Action _doneAttemptingToBindProperty;
+ private static readonly Action _attemptingToValidateProperty;
+ private static readonly Action _doneAttemptingToValidateProperty;
+ private static readonly Action _attemptingToValidateParameter;
+ private static readonly Action _doneAttemptingToValidateParameter;
private static readonly Action _unsupportedFormatFilterContentType;
private static readonly Action _actionDoesNotSupportFormatFilterContentType;
private static readonly Action _cannotApplyFormatFilterContentType;
@@ -417,35 +442,161 @@ namespace Microsoft.AspNetCore.Mvc.Internal
11,
"List of registered output formatters, in the following order: {OutputFormatters}");
- _ifMatchPreconditionFailed = LoggerMessage.Define(
- LogLevel.Debug,
- 12,
- "Current request's If-Match header check failed as the file's current etag '{CurrentETag}' does not match with any of the supplied etags.");
-
- _ifUnmodifiedSincePreconditionFailed = LoggerMessage.Define(
- LogLevel.Debug,
- 13,
- "Current request's If-Unmodified-Since header check failed as the file was modified (at '{lastModified}') after the If-Unmodified-Since date '{IfUnmodifiedSinceDate}'.");
-
- _ifRangeLastModifiedPreconditionFailed = LoggerMessage.Define(
- LogLevel.Debug,
- 14,
- "Could not serve range as the file was modified (at {LastModified}) after the if-Range's last modified date '{IfRangeLastModified}'.");
-
- _ifRangeETagPreconditionFailed = LoggerMessage.Define(
- LogLevel.Debug,
- 15,
- "Could not serve range as the file's current etag '{CurrentETag}' does not match the If-Range etag '{IfRangeETag}'.");
-
- _notEnabledForRangeProcessing = LoggerMessage.Define(
- LogLevel.Debug,
- 16,
- $"The file result has not been enabled for processing range requests. To enable it, set the property '{nameof(FileResult.EnableRangeProcessing)}' on the result to 'true'.");
-
_writingRangeToBody = LoggerMessage.Define(
LogLevel.Debug,
17,
"Writing the requested range of bytes to the body...");
+
+ _registeredModelBinderProviders = LoggerMessage.Define(
+ LogLevel.Debug,
+ 12,
+ "Registered model binder providers, in the following order: {ModelBinderProviders}");
+
+ _attemptingToBindPropertyModel = LoggerMessage.Define(
+ LogLevel.Debug,
+ 13,
+ "Attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}' using the name '{ModelName}' in request data ...");
+
+ _doneAttemptingToBindPropertyModel = LoggerMessage.Define(
+ LogLevel.Debug,
+ 14,
+ "Done attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}'.");
+
+ _foundNoValueForPropertyInRequest = LoggerMessage.Define(
+ LogLevel.Debug,
+ 15,
+ "Could not find a value in the request with name '{ModelName}' for binding property '{PropertyContainerType}.{ModelFieldName}' of type '{ModelType}'.");
+
+ _foundNoValueInRequest = LoggerMessage.Define(
+ LogLevel.Debug,
+ 16,
+ "Could not find a value in the request with name '{ModelName}' for binding parameter '{ModelFieldName}' of type '{ModelType}'.");
+
+ _noPublicSettableProperties = LoggerMessage.Define(
+ LogLevel.Debug,
+ 17,
+ "Could not bind to model with name '{ModelName}' and type '{ModelType}' as the type has no public settable properties.");
+
+ _cannotBindToComplexType = LoggerMessage.Define(
+ LogLevel.Debug,
+ 18,
+ "Could not bind to model of type '{ModelType}' as there were no values in the request for any of the properties.");
+
+ _cannotBindToFilesCollectionDueToUnsupportedContentType = LoggerMessage.Define(
+ LogLevel.Debug,
+ 19,
+ "Could not bind to model with name '{ModelName}' and type '{ModelType}' as the request did not have a content type of either 'application/x-www-form-urlencoded' or 'multipart/form-data'.");
+
+ _cannotCreateHeaderModelBinder = LoggerMessage.Define(
+ LogLevel.Debug,
+ 20,
+ "Could not create a binder for type '{ModelType}' as this binder only supports 'System.String' type or a collection of 'System.String'.");
+
+ _noFilesFoundInRequest = LoggerMessage.Define(
+ LogLevel.Debug,
+ 21,
+ "No files found in the request to bind the model to.");
+
+ _attemptingToBindParameter = LoggerMessage.Define(
+ LogLevel.Debug,
+ 22,
+ "Attempting to bind parameter '{ParameterName}' of type '{ModelType}' ...");
+
+ _doneAttemptingToBindParameter = LoggerMessage.Define(
+ LogLevel.Debug,
+ 23,
+ "Done attempting to bind parameter '{ParameterName}' of type '{ModelType}'.");
+
+ _attemptingToBindModel = LoggerMessage.Define(
+ LogLevel.Debug,
+ 24,
+ "Attempting to bind model of type '{ModelType}' using the name '{ModelName}' in request data ...");
+
+ _doneAttemptingToBindModel = LoggerMessage.Define(
+ LogLevel.Debug,
+ 25,
+ "Done attempting to bind model of type '{ModelType}' using the name '{ModelName}'.");
+
+ _attemptingToValidateParameter = LoggerMessage.Define(
+ LogLevel.Debug,
+ 26,
+ "Attempting to validate the bound parameter '{ParameterName}' of type '{ModelType}' ...");
+
+ _doneAttemptingToValidateParameter = LoggerMessage.Define(
+ LogLevel.Debug,
+ 27,
+ "Done attempting to validate the bound parameter '{ParameterName}' of type '{ModelType}'.");
+
+ _noNonIndexBasedFormatFoundForCollection = LoggerMessage.Define(
+ LogLevel.Debug,
+ 28,
+ "Could not bind to collection using a format like {ModelName}=value1&{ModelName}=value2");
+
+ _attemptingToBindCollectionUsingIndices = LoggerMessage.Define(
+ LogLevel.Debug,
+ 29,
+ "Attempting to bind model using indices. Example formats include: " +
+ "[0]=value1&[1]=value2, " +
+ "{ModelName}[0]=value1&{ModelName}[1]=value2, " +
+ "{ModelName}.index=zero&{ModelName}.index=one&{ModelName}[zero]=value1&{ModelName}[one]=value2");
+
+ _attemptingToBindCollectionOfKeyValuePair = LoggerMessage.Define(
+ LogLevel.Debug,
+ 30,
+ "Attempting to bind collection of KeyValuePair. Example formats include: " +
+ "[0].Key=key1&[0].Value=value1&[1].Key=key2&[1].Value=value2, " +
+ "{ModelName}[0].Key=key1&{ModelName}[0].Value=value1&{ModelName}[1].Key=key2&{ModelName}[1].Value=value2, " +
+ "{ModelName}[key1]=value1&{ModelName}[key2]=value2");
+
+ _noKeyValueFormatForDictionaryModelBinder = LoggerMessage.Define(
+ LogLevel.Debug,
+ 33,
+ "Attempting to bind model with name '{ModelName}' using the format {ModelName}[key1]=value1&{ModelName}[key2]=value2");
+
+ _ifMatchPreconditionFailed = LoggerMessage.Define(
+ LogLevel.Debug,
+ 34,
+ "Current request's If-Match header check failed as the file's current etag '{CurrentETag}' does not match with any of the supplied etags.");
+
+ _ifUnmodifiedSincePreconditionFailed = LoggerMessage.Define(
+ LogLevel.Debug,
+ 35,
+ "Current request's If-Unmodified-Since header check failed as the file was modified (at '{lastModified}') after the If-Unmodified-Since date '{IfUnmodifiedSinceDate}'.");
+
+ _ifRangeLastModifiedPreconditionFailed = LoggerMessage.Define(
+ LogLevel.Debug,
+ 36,
+ "Could not serve range as the file was modified (at {LastModified}) after the if-Range's last modified date '{IfRangeLastModified}'.");
+
+ _ifRangeETagPreconditionFailed = LoggerMessage.Define(
+ LogLevel.Debug,
+ 37,
+ "Could not serve range as the file's current etag '{CurrentETag}' does not match the If-Range etag '{IfRangeETag}'.");
+
+ _notEnabledForRangeProcessing = LoggerMessage.Define(
+ LogLevel.Debug,
+ 38,
+ $"The file result has not been enabled for processing range requests. To enable it, set the property '{nameof(FileResult.EnableRangeProcessing)}' on the result to 'true'.");
+
+ _attemptingToBindProperty = LoggerMessage.Define(
+ LogLevel.Debug,
+ 39,
+ "Attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}' ...");
+
+ _doneAttemptingToBindProperty = LoggerMessage.Define(
+ LogLevel.Debug,
+ 40,
+ "Done attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}'.");
+
+ _attemptingToValidateProperty = LoggerMessage.Define(
+ LogLevel.Debug,
+ 41,
+ "Attempting to validate the bound property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}' ...");
+
+ _doneAttemptingToValidateProperty = LoggerMessage.Define(
+ LogLevel.Debug,
+ 42,
+ "Done attempting to validate the bound property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}'.");
}
public static void RegisteredOutputFormatters(this ILogger logger, IEnumerable outputFormatters)
@@ -967,6 +1118,200 @@ namespace Microsoft.AspNetCore.Mvc.Internal
_ifRangeETagPreconditionFailed(logger, currentETag, ifRangeTag, null);
}
+ public static void RegisteredModelBinderProviders(this ILogger logger, IModelBinderProvider[] providers)
+ {
+ _registeredModelBinderProviders(logger, providers, null);
+ }
+
+ public static void FoundNoValueInRequest(this ILogger logger, ModelBindingContext bindingContext)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ var modelMetadata = bindingContext.ModelMetadata;
+ var isProperty = modelMetadata.ContainerType != null;
+
+ if (isProperty)
+ {
+ _foundNoValueForPropertyInRequest(
+ logger,
+ bindingContext.ModelName,
+ modelMetadata.ContainerType,
+ modelMetadata.PropertyName,
+ bindingContext.ModelType,
+ null);
+ }
+ else
+ {
+ _foundNoValueInRequest(
+ logger,
+ bindingContext.ModelName,
+ modelMetadata.PropertyName,
+ bindingContext.ModelType,
+ null);
+ }
+ }
+
+ public static void NoPublicSettableProperties(this ILogger logger, ModelBindingContext bindingContext)
+ {
+ _noPublicSettableProperties(logger, bindingContext.ModelName, bindingContext.ModelType, null);
+ }
+
+ public static void CannotBindToComplexType(this ILogger logger, ModelBindingContext bindingContext)
+ {
+ _cannotBindToComplexType(logger, bindingContext.ModelType, null);
+ }
+
+ public static void CannotBindToFilesCollectionDueToUnsupportedContentType(this ILogger logger, ModelBindingContext bindingContext)
+ {
+ _cannotBindToFilesCollectionDueToUnsupportedContentType(logger, bindingContext.ModelName, bindingContext.ModelType, null);
+ }
+
+ public static void CannotCreateHeaderModelBinder(this ILogger logger, Type modelType)
+ {
+ _cannotCreateHeaderModelBinder(logger, modelType, null);
+ }
+
+ public static void NoFilesFoundInRequest(this ILogger logger)
+ {
+ _noFilesFoundInRequest(logger, null);
+ }
+
+ public static void AttemptingToBindModel(this ILogger logger, ModelBindingContext bindingContext)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ var modelMetadata = bindingContext.ModelMetadata;
+ var isProperty = modelMetadata.ContainerType != null;
+
+ if (isProperty)
+ {
+ _attemptingToBindPropertyModel(
+ logger,
+ modelMetadata.ContainerType,
+ modelMetadata.PropertyName,
+ modelMetadata.ModelType,
+ bindingContext.ModelName,
+ null);
+ }
+ else
+ {
+ _attemptingToBindModel(logger, bindingContext.ModelType, bindingContext.ModelName, null);
+ }
+ }
+
+ public static void DoneAttemptingToBindModel(this ILogger logger, ModelBindingContext bindingContext)
+ {
+ var modelMetadata = bindingContext.ModelMetadata;
+ var isProperty = modelMetadata.ContainerType != null;
+
+ if (isProperty)
+ {
+ _doneAttemptingToBindPropertyModel(
+ logger,
+ modelMetadata.ContainerType,
+ modelMetadata.PropertyName,
+ modelMetadata.ModelType,
+ null);
+ }
+ else
+ {
+ _doneAttemptingToBindModel(logger, bindingContext.ModelType, bindingContext.ModelName, null);
+ }
+ }
+
+ public static void AttemptingToBindParameterOrProperty(this ILogger logger, ParameterDescriptor parameter, ModelBindingContext bindingContext)
+ {
+ if (parameter is ControllerBoundPropertyDescriptor propertyDescriptor)
+ {
+ _attemptingToBindProperty(logger, propertyDescriptor.PropertyInfo.DeclaringType, parameter.Name, bindingContext.ModelType, null);
+ }
+ else
+ {
+ _attemptingToBindParameter(logger, parameter.Name, bindingContext.ModelType, null);
+ }
+ }
+
+ public static void DoneAttemptingToBindParameterOrProperty(this ILogger logger, ParameterDescriptor parameter, ModelBindingContext bindingContext)
+ {
+ if (parameter is ControllerBoundPropertyDescriptor propertyDescriptor)
+ {
+ _doneAttemptingToBindProperty(logger, propertyDescriptor.PropertyInfo.DeclaringType, parameter.Name, bindingContext.ModelType, null);
+ }
+ else
+ {
+ _doneAttemptingToBindParameter(logger, parameter.Name, bindingContext.ModelType, null);
+ }
+ }
+
+ public static void AttemptingToValidateParameterOrProperty(this ILogger logger, ParameterDescriptor parameter, ModelBindingContext bindingContext)
+ {
+ if (parameter is ControllerBoundPropertyDescriptor propertyDescriptor)
+ {
+ _attemptingToValidateProperty(logger, propertyDescriptor.PropertyInfo.DeclaringType, parameter.Name, bindingContext.ModelType, null);
+ }
+ else
+ {
+ _attemptingToValidateParameter(logger, parameter.Name, bindingContext.ModelType, null);
+ }
+ }
+
+ public static void DoneAttemptingToValidateParameterOrProperty(this ILogger logger, ParameterDescriptor parameter, ModelBindingContext bindingContext)
+ {
+ if (parameter is ControllerBoundPropertyDescriptor propertyDescriptor)
+ {
+ _doneAttemptingToValidateProperty(logger, propertyDescriptor.PropertyInfo.DeclaringType, parameter.Name, bindingContext.ModelType, null);
+ }
+ else
+ {
+ _doneAttemptingToValidateParameter(logger, parameter.Name, bindingContext.ModelType, null);
+ }
+ }
+
+ public static void NoNonIndexBasedFormatFoundForCollection(this ILogger logger, ModelBindingContext bindingContext)
+ {
+ var modelName = bindingContext.ModelName;
+ _noNonIndexBasedFormatFoundForCollection(logger, modelName, modelName, null);
+ }
+
+ public static void AttemptingToBindCollectionUsingIndices(this ILogger logger, ModelBindingContext bindingContext)
+ {
+ if (!logger.IsEnabled(LogLevel.Debug))
+ {
+ return;
+ }
+
+ var modelName = bindingContext.ModelName;
+
+ var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(bindingContext.ModelType, typeof(IEnumerable<>));
+ if (enumerableType != null)
+ {
+ var elementType = enumerableType.GenericTypeArguments[0];
+ if (elementType.IsGenericType && elementType.GetGenericTypeDefinition().GetTypeInfo() == typeof(KeyValuePair<,>).GetTypeInfo())
+ {
+ _attemptingToBindCollectionOfKeyValuePair(logger, modelName, modelName, modelName, modelName, modelName, modelName, null);
+ return;
+ }
+ }
+
+ _attemptingToBindCollectionUsingIndices(logger, modelName, modelName, modelName, modelName, modelName, modelName, null);
+ }
+
+ public static void NoKeyValueFormatForDictionaryModelBinder(this ILogger logger, ModelBindingContext bindingContext)
+ {
+ _noKeyValueFormatForDictionaryModelBinder(
+ logger,
+ bindingContext.ModelName,
+ bindingContext.ModelName,
+ bindingContext.ModelName,
+ null);
+ }
+
private static void LogFilterExecutionPlan(
ILogger logger,
string filterType,
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreMvcOptionsSetup.cs b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreMvcOptionsSetup.cs
index e898cd6b1f..d33813cd1e 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreMvcOptionsSetup.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcCoreMvcOptionsSetup.cs
@@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.Internal
@@ -23,8 +24,9 @@ namespace Microsoft.AspNetCore.Mvc.Internal
private readonly IHttpRequestStreamReaderFactory _readerFactory;
private readonly ILoggerFactory _loggerFactory;
+ // Used in tests
public MvcCoreMvcOptionsSetup(IHttpRequestStreamReaderFactory readerFactory)
- : this(readerFactory, loggerFactory: null)
+ : this(readerFactory, NullLoggerFactory.Instance)
{
}
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Microsoft.AspNetCore.Mvc.Core.csproj b/src/Microsoft.AspNetCore.Mvc.Core/Microsoft.AspNetCore.Mvc.Core.csproj
index b753fbd806..5861db1584 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Microsoft.AspNetCore.Mvc.Core.csproj
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Microsoft.AspNetCore.Mvc.Core.csproj
@@ -28,6 +28,7 @@ Microsoft.AspNetCore.Mvc.RouteAttribute
+
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ArrayModelBinder.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ArrayModelBinder.cs
index c88625f490..96c6a31288 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ArrayModelBinder.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ArrayModelBinder.cs
@@ -5,6 +5,8 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@@ -14,14 +16,30 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
/// Type of elements in the array.
public class ArrayModelBinder : CollectionModelBinder
{
+ ///
+ /// This constructor is obsolete and will be removed in a future version. The recommended alternative
+ /// is the overload that also takes an .
+ /// Creates a new .
+ ///
+ ///
+ /// The for binding .
+ ///
+ [Obsolete("This constructor is obsolete and will be removed in a future version. The recommended alternative"
+ + " is the overload that also takes an " + nameof(ILoggerFactory) + ".")]
+ public ArrayModelBinder(IModelBinder elementBinder)
+ : this(elementBinder, NullLoggerFactory.Instance)
+ {
+ }
+
///
/// Creates a new .
///
///
/// The for binding .
///
- public ArrayModelBinder(IModelBinder elementBinder)
- : base(elementBinder)
+ /// The .
+ public ArrayModelBinder(IModelBinder elementBinder, ILoggerFactory loggerFactory)
+ : base(elementBinder, loggerFactory)
{
}
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ArrayModelBinderProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ArrayModelBinderProvider.cs
index 33267fd069..190390b9c7 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ArrayModelBinderProvider.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ArrayModelBinderProvider.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@@ -24,7 +26,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var elementBinder = context.CreateBinder(context.Metadata.ElementMetadata);
var binderType = typeof(ArrayModelBinder<>).MakeGenericType(elementType);
- return (IModelBinder)Activator.CreateInstance(binderType, elementBinder);
+ var loggerFactory = context.Services.GetRequiredService();
+ return (IModelBinder)Activator.CreateInstance(binderType, elementBinder, loggerFactory);
}
return null;
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/BodyModelBinder.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/BodyModelBinder.cs
index f33deed4cc..8e0744cfda 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/BodyModelBinder.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/BodyModelBinder.cs
@@ -100,6 +100,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
+ _logger?.AttemptingToBindModel(bindingContext);
+
// Special logic for body, treat the model name as string.Empty for the top level
// object, but allow an override via BinderModelName. The purpose of this is to try
// and be similar to the behavior for POCOs bound via traditional model binding.
@@ -147,6 +149,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var message = Resources.FormatUnsupportedContentType(httpContext.Request.ContentType);
var exception = new UnsupportedContentTypeException(message);
bindingContext.ModelState.AddModelError(modelBindingKey, exception, bindingContext.ModelMetadata);
+ _logger?.DoneAttemptingToBindModel(bindingContext);
return;
}
@@ -157,6 +160,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
if (result.HasError)
{
// Formatter encountered an error. Do not use the model it returned.
+ _logger?.DoneAttemptingToBindModel(bindingContext);
return;
}
@@ -183,6 +187,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
bindingContext.ModelState.AddModelError(modelBindingKey, exception, bindingContext.ModelMetadata);
}
+
+ _logger?.DoneAttemptingToBindModel(bindingContext);
}
private bool ShouldHandleException(IInputFormatter formatter)
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ByteArrayModelBinder.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ByteArrayModelBinder.cs
index ff7b81704f..99461f9ec9 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ByteArrayModelBinder.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ByteArrayModelBinder.cs
@@ -3,6 +3,9 @@
using System;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc.Internal;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@@ -11,6 +14,34 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
///
public class ByteArrayModelBinder : IModelBinder
{
+ private readonly ILogger _logger;
+
+ ///
+ /// This constructor is obsolete and will be removed in a future version. The recommended alternative
+ /// is the overload that takes an .
+ /// Initializes a new instance of .
+ ///
+ [Obsolete("This constructor is obsolete and will be removed in a future version. The recommended alternative"
+ + " is the overload that takes an " + nameof(ILoggerFactory) + ".")]
+ public ByteArrayModelBinder()
+ : this(NullLoggerFactory.Instance)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The .
+ public ByteArrayModelBinder(ILoggerFactory loggerFactory)
+ {
+ if (loggerFactory == null)
+ {
+ throw new ArgumentNullException(nameof(loggerFactory));
+ }
+
+ _logger = loggerFactory.CreateLogger();
+ }
+
///
public Task BindModelAsync(ModelBindingContext bindingContext)
{
@@ -19,10 +50,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
+ _logger.AttemptingToBindModel(bindingContext);
+
// Check for missing data case 1: There was no element containing this data.
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == ValueProviderResult.None)
{
+ _logger.FoundNoValueInRequest(bindingContext);
+ _logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
@@ -32,6 +67,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var value = valueProviderResult.FirstValue;
if (string.IsNullOrEmpty(value))
{
+ _logger.FoundNoValueInRequest(bindingContext);
+ _logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
@@ -39,7 +76,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
var model = Convert.FromBase64String(value);
bindingContext.Result = ModelBindingResult.Success(model);
- return Task.CompletedTask;
}
catch (Exception exception)
{
@@ -47,8 +83,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bindingContext.ModelName,
exception,
bindingContext.ModelMetadata);
- return Task.CompletedTask;
}
+
+ _logger.DoneAttemptingToBindModel(bindingContext);
+ return Task.CompletedTask;
}
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ByteArrayModelBinderProvider.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ByteArrayModelBinderProvider.cs
index 1253b44705..402f796640 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ByteArrayModelBinderProvider.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/ByteArrayModelBinderProvider.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@@ -20,7 +22,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
if (context.Metadata.ModelType == typeof(byte[]))
{
- return new ByteArrayModelBinder();
+ var loggerFactory = context.Services.GetRequiredService();
+ return new ByteArrayModelBinder(loggerFactory);
}
return null;
diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/CollectionModelBinder.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/CollectionModelBinder.cs
index 2e551e5867..d219519e4f 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/CollectionModelBinder.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/CollectionModelBinder.cs
@@ -12,6 +12,8 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@@ -23,18 +25,38 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
private Func