Improving logging - model binding

Related to issue #6498: When enabling "Trace" logging for MVC loggers, I should be buried in log messages
This commit is contained in:
Kiran Challa 2017-12-18 16:35:44 -08:00
parent f9b246e7ab
commit c922b0b90d
64 changed files with 1438 additions and 267 deletions

View File

@ -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
{
/// <summary>
@ -29,5 +31,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// Gets the <see cref="IModelMetadataProvider"/>.
/// </summary>
public abstract IModelMetadataProvider MetadataProvider { get; }
/// <summary>
/// Gets the <see cref="IServiceProvider"/>.
/// </summary>
public virtual IServiceProvider Services { get; }
}
}

View File

@ -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<ParameterBinder>(s =>
{
var options = s.GetRequiredService<IOptions<MvcOptions>>().Value;
var loggerFactory = s.GetRequiredService<ILoggerFactory>();
var metadataProvider = s.GetRequiredService<IModelMetadataProvider>();
var modelBinderFactory = s.GetRequiredService<IModelBinderFactory>();
var modelValidatorProvider = new CompositeModelValidatorProvider(options.ModelValidatorProviders);
return new ParameterBinder(metadataProvider, modelBinderFactory, modelValidatorProvider);
return new ParameterBinder(metadataProvider, modelBinderFactory, modelValidatorProvider, loggerFactory);
});
//

View File

@ -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<ILogger, MethodInfo, string, string, Exception> _inferredParameterSource;
private static readonly Action<ILogger, MethodInfo, Exception> _unableToInferParameterSources;
private static readonly Action<ILogger, IModelBinderProvider[], Exception> _registeredModelBinderProviders;
private static readonly Action<ILogger, string, Type, string, Type, Exception> _foundNoValueForPropertyInRequest;
private static readonly Action<ILogger, string, string, Type, Exception> _foundNoValueInRequest;
private static readonly Action<ILogger, string, Type, Exception> _noPublicSettableProperties;
private static readonly Action<ILogger, Type, Exception> _cannotBindToComplexType;
private static readonly Action<ILogger, string, Type, Exception> _cannotBindToFilesCollectionDueToUnsupportedContentType;
private static readonly Action<ILogger, Type, Exception> _cannotCreateHeaderModelBinder;
private static readonly Action<ILogger, Exception> _noFilesFoundInRequest;
private static readonly Action<ILogger, string, string, Exception> _noNonIndexBasedFormatFoundForCollection;
private static readonly Action<ILogger, string, string, string, string, string, string, Exception> _attemptingToBindCollectionUsingIndices;
private static readonly Action<ILogger, string, string, string, string, string, string, Exception> _attemptingToBindCollectionOfKeyValuePair;
private static readonly Action<ILogger, string, string, string, Exception> _noKeyValueFormatForDictionaryModelBinder;
private static readonly Action<ILogger, Type, string, Type, string, Exception> _attemptingToBindPropertyModel;
private static readonly Action<ILogger, Type, string, Type, Exception> _doneAttemptingToBindPropertyModel;
private static readonly Action<ILogger, Type, string, Exception> _attemptingToBindModel;
private static readonly Action<ILogger, Type, string, Exception> _doneAttemptingToBindModel;
private static readonly Action<ILogger, string, Type, Exception> _attemptingToBindParameter;
private static readonly Action<ILogger, string, Type, Exception> _doneAttemptingToBindParameter;
private static readonly Action<ILogger, Type, string, Type, Exception> _attemptingToBindProperty;
private static readonly Action<ILogger, Type, string, Type, Exception> _doneAttemptingToBindProperty;
private static readonly Action<ILogger, Type, string, Type, Exception> _attemptingToValidateProperty;
private static readonly Action<ILogger, Type, string, Type, Exception> _doneAttemptingToValidateProperty;
private static readonly Action<ILogger, string, Type, Exception> _attemptingToValidateParameter;
private static readonly Action<ILogger, string, Type, Exception> _doneAttemptingToValidateParameter;
private static readonly Action<ILogger, string, Exception> _unsupportedFormatFilterContentType;
private static readonly Action<ILogger, string, MediaTypeCollection, Exception> _actionDoesNotSupportFormatFilterContentType;
private static readonly Action<ILogger, string, Exception> _cannotApplyFormatFilterContentType;
@ -417,35 +442,161 @@ namespace Microsoft.AspNetCore.Mvc.Internal
11,
"List of registered output formatters, in the following order: {OutputFormatters}");
_ifMatchPreconditionFailed = LoggerMessage.Define<EntityTagHeaderValue>(
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<DateTimeOffset?, DateTimeOffset?>(
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<DateTimeOffset?, DateTimeOffset?>(
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<EntityTagHeaderValue, EntityTagHeaderValue>(
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<IModelBinderProvider[]>(
LogLevel.Debug,
12,
"Registered model binder providers, in the following order: {ModelBinderProviders}");
_attemptingToBindPropertyModel = LoggerMessage.Define<Type, string, Type, string>(
LogLevel.Debug,
13,
"Attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}' using the name '{ModelName}' in request data ...");
_doneAttemptingToBindPropertyModel = LoggerMessage.Define<Type, string, Type>(
LogLevel.Debug,
14,
"Done attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}'.");
_foundNoValueForPropertyInRequest = LoggerMessage.Define<string, Type, string, Type>(
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<string, string, Type>(
LogLevel.Debug,
16,
"Could not find a value in the request with name '{ModelName}' for binding parameter '{ModelFieldName}' of type '{ModelType}'.");
_noPublicSettableProperties = LoggerMessage.Define<string, Type>(
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<Type>(
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<string, Type>(
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<Type>(
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<string, Type>(
LogLevel.Debug,
22,
"Attempting to bind parameter '{ParameterName}' of type '{ModelType}' ...");
_doneAttemptingToBindParameter = LoggerMessage.Define<string, Type>(
LogLevel.Debug,
23,
"Done attempting to bind parameter '{ParameterName}' of type '{ModelType}'.");
_attemptingToBindModel = LoggerMessage.Define<Type, string>(
LogLevel.Debug,
24,
"Attempting to bind model of type '{ModelType}' using the name '{ModelName}' in request data ...");
_doneAttemptingToBindModel = LoggerMessage.Define<Type, string>(
LogLevel.Debug,
25,
"Done attempting to bind model of type '{ModelType}' using the name '{ModelName}'.");
_attemptingToValidateParameter = LoggerMessage.Define<string, Type>(
LogLevel.Debug,
26,
"Attempting to validate the bound parameter '{ParameterName}' of type '{ModelType}' ...");
_doneAttemptingToValidateParameter = LoggerMessage.Define<string, Type>(
LogLevel.Debug,
27,
"Done attempting to validate the bound parameter '{ParameterName}' of type '{ModelType}'.");
_noNonIndexBasedFormatFoundForCollection = LoggerMessage.Define<string, string>(
LogLevel.Debug,
28,
"Could not bind to collection using a format like {ModelName}=value1&{ModelName}=value2");
_attemptingToBindCollectionUsingIndices = LoggerMessage.Define<string, string, string, string, string, string>(
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<string, string, string, string, string, string>(
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<string, string, string>(
LogLevel.Debug,
33,
"Attempting to bind model with name '{ModelName}' using the format {ModelName}[key1]=value1&{ModelName}[key2]=value2");
_ifMatchPreconditionFailed = LoggerMessage.Define<EntityTagHeaderValue>(
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<DateTimeOffset?, DateTimeOffset?>(
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<DateTimeOffset?, DateTimeOffset?>(
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<EntityTagHeaderValue, EntityTagHeaderValue>(
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<Type, string, Type>(
LogLevel.Debug,
39,
"Attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}' ...");
_doneAttemptingToBindProperty = LoggerMessage.Define<Type, string, Type>(
LogLevel.Debug,
40,
"Done attempting to bind property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}'.");
_attemptingToValidateProperty = LoggerMessage.Define<Type, string, Type>(
LogLevel.Debug,
41,
"Attempting to validate the bound property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}' ...");
_doneAttemptingToValidateProperty = LoggerMessage.Define<Type, string, Type>(
LogLevel.Debug,
42,
"Done attempting to validate the bound property '{PropertyContainerType}.{PropertyName}' of type '{ModelType}'.");
}
public static void RegisteredOutputFormatters(this ILogger logger, IEnumerable<IOutputFormatter> 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,

View File

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

View File

@ -28,6 +28,7 @@ Microsoft.AspNetCore.Mvc.RouteAttribute</Description>
<PackageReference Include="Microsoft.AspNetCore.ResponseCaching.Abstractions" Version="$(MicrosoftAspNetCoreResponseCachingAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="$(MicrosoftAspNetCoreRoutingPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="$(MicrosoftExtensionsFileProvidersAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.HashCodeCombiner.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHashCodeCombinerSourcesPackageVersion)" />

View File

@ -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
/// <typeparam name="TElement">Type of elements in the array.</typeparam>
public class ArrayModelBinder<TElement> : CollectionModelBinder<TElement>
{
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Creates a new <see cref="ArrayModelBinder{TElement}"/>.</para>
/// </summary>
/// <param name="elementBinder">
/// The <see cref="IModelBinder"/> for binding <typeparamref name="TElement"/>.
/// </param>
[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)
{
}
/// <summary>
/// Creates a new <see cref="ArrayModelBinder{TElement}"/>.
/// </summary>
/// <param name="elementBinder">
/// The <see cref="IModelBinder"/> for binding <typeparamref name="TElement"/>.
/// </param>
public ArrayModelBinder(IModelBinder elementBinder)
: base(elementBinder)
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public ArrayModelBinder(IModelBinder elementBinder, ILoggerFactory loggerFactory)
: base(elementBinder, loggerFactory)
{
}

View File

@ -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<ILoggerFactory>();
return (IModelBinder)Activator.CreateInstance(binderType, elementBinder, loggerFactory);
}
return null;

View File

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

View File

@ -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
/// </summary>
public class ByteArrayModelBinder : IModelBinder
{
private readonly ILogger _logger;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Initializes a new instance of <see cref="ByteArrayModelBinder"/>.</para>
/// </summary>
[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)
{
}
/// <summary>
/// Initializes a new instance of <see cref="ByteArrayModelBinder"/>.
/// </summary>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public ByteArrayModelBinder(ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger<ByteArrayModelBinder>();
}
/// <inheritdoc />
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 <input ... /> 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;
}
}
}

View File

@ -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<ILoggerFactory>();
return new ByteArrayModelBinder(loggerFactory);
}
return null;

View File

@ -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<object> _modelCreator;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Creates a new <see cref="CollectionModelBinder{TElement}"/>.</para>
/// </summary>
/// <param name="elementBinder">The <see cref="IModelBinder"/> for binding elements.</param>
[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 CollectionModelBinder(IModelBinder elementBinder)
: this(elementBinder, NullLoggerFactory.Instance)
{
}
/// <summary>
/// Creates a new <see cref="CollectionModelBinder{TElement}"/>.
/// </summary>
/// <param name="elementBinder">The <see cref="IModelBinder"/> for binding elements.</param>
public CollectionModelBinder(IModelBinder elementBinder)
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public CollectionModelBinder(IModelBinder elementBinder, ILoggerFactory loggerFactory)
{
if (elementBinder == null)
{
throw new ArgumentNullException(nameof(elementBinder));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
ElementBinder = elementBinder;
Logger = loggerFactory.CreateLogger(GetType());
}
/// <summary>
@ -42,6 +64,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
/// </summary>
protected IModelBinder ElementBinder { get; }
/// <summary>
/// The <see cref="ILogger"/> used for logging in this binder.
/// </summary>
protected ILogger Logger { get; }
/// <inheritdoc />
public virtual async Task BindModelAsync(ModelBindingContext bindingContext)
{
@ -50,9 +77,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
Logger.AttemptingToBindModel(bindingContext);
var model = bindingContext.Model;
if (!bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
{
Logger.FoundNoValueInRequest(bindingContext);
// If we failed to find data for a top-level model, then generate a
// default 'empty' model (or use existing Model) and return it.
if (bindingContext.IsTopLevelObject)
@ -65,6 +96,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bindingContext.Result = ModelBindingResult.Success(model);
}
Logger.DoneAttemptingToBindModel(bindingContext);
return;
}
@ -73,6 +105,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
CollectionResult result;
if (valueProviderResult == ValueProviderResult.None)
{
Logger.NoNonIndexBasedFormatFoundForCollection(bindingContext);
result = await BindComplexCollection(bindingContext);
}
else
@ -110,6 +143,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
}
bindingContext.Result = ModelBindingResult.Success(model);
Logger.DoneAttemptingToBindModel(bindingContext);
}
/// <inheritdoc />
@ -207,6 +241,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Used when the ValueProvider contains the collection to be bound as multiple elements, e.g. foo[0], foo[1].
private Task<CollectionResult> BindComplexCollection(ModelBindingContext bindingContext)
{
Logger.AttemptingToBindCollectionUsingIndices(bindingContext);
var indexPropertyName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, "index");
var valueProviderResultIndex = bindingContext.ValueProvider.GetValue(indexPropertyName);
var indexNames = GetIndexNamesFromValueProviderResult(valueProviderResultIndex);
@ -273,7 +309,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// If we're working with a fixed set of indexes then this is the format like:
//
// ?parameter.index=zero,one,two&parameter[zero]=0&&parameter[one]=1&parameter[two]=2...
// ?parameter.index=zero&parameter.index=one&parameter.index=two&parameter[zero]=0&parameter[one]=1&parameter[two]=2...
//
// We need to provide this data to the validation system so it can 'replay' the keys.
// But we can't just set ValidationState here, because it needs the 'real' model.

View File

@ -4,7 +4,9 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -29,6 +31,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
return null;
}
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
// If the model type is ICollection<> then we can call its Add method, so we can always support it.
var collectionType = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(ICollection<>));
if (collectionType != null)
@ -37,7 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var elementBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(elementType));
var binderType = typeof(CollectionModelBinder<>).MakeGenericType(collectionType.GenericTypeArguments);
return (IModelBinder)Activator.CreateInstance(binderType, elementBinder);
return (IModelBinder)Activator.CreateInstance(binderType, elementBinder, loggerFactory);
}
// If the model type is IEnumerable<> then we need to know if we can assign a List<> to it, since
@ -53,7 +57,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var elementBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(elementType));
var binderType = typeof(CollectionModelBinder<>).MakeGenericType(enumerableType.GenericTypeArguments);
return (IModelBinder)Activator.CreateInstance(binderType, elementBinder);
return (IModelBinder)Activator.CreateInstance(binderType, elementBinder, loggerFactory);
}
}

View File

@ -7,6 +7,9 @@ using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -16,22 +19,47 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public class ComplexTypeModelBinder : IModelBinder
{
private readonly IDictionary<ModelMetadata, IModelBinder> _propertyBinders;
private readonly ILogger _logger;
private Func<object> _modelCreator;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Creates a new <see cref="ComplexTypeModelBinder"/>.</para>
/// </summary>
/// <param name="propertyBinders">
/// The <see cref="IDictionary{TKey, TValue}"/> of binders to use for binding properties.
/// </param>
[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 ComplexTypeModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders)
: this(propertyBinders, NullLoggerFactory.Instance)
{
}
/// <summary>
/// Creates a new <see cref="ComplexTypeModelBinder"/>.
/// </summary>
/// <param name="propertyBinders">
/// The <see cref="IDictionary{TKey, TValue}"/> of binders to use for binding properties.
/// </param>
public ComplexTypeModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders)
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public ComplexTypeModelBinder(
IDictionary<ModelMetadata, IModelBinder> propertyBinders,
ILoggerFactory loggerFactory)
{
if (propertyBinders == null)
{
throw new ArgumentNullException(nameof(propertyBinders));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_propertyBinders = propertyBinders;
_logger = loggerFactory.CreateLogger<ComplexTypeModelBinder>();
}
/// <inheritdoc />
@ -42,6 +70,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
_logger.AttemptingToBindModel(bindingContext);
if (!CanCreateModel(bindingContext))
{
return Task.CompletedTask;
@ -106,6 +136,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
}
bindingContext.Result = ModelBindingResult.Success(bindingContext.Model);
_logger.DoneAttemptingToBindModel(bindingContext);
}
/// <summary>
@ -199,6 +230,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// level object. So we return false.
if (bindingContext.ModelMetadata.Properties.Count == 0)
{
_logger.NoPublicSettableProperties(bindingContext);
return false;
}
@ -272,6 +304,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
return true;
}
_logger.CannotBindToComplexType(bindingContext);
return false;
}
@ -307,7 +341,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
return true;
}
/// <summary>
/// Creates suitable <see cref="object"/> for given <paramref name="bindingContext"/>.
/// </summary>

View File

@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -28,7 +30,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
propertyBinders.Add(property, context.CreateBinder(property));
}
return new ComplexTypeModelBinder(propertyBinders);
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new ComplexTypeModelBinder(propertyBinders, loggerFactory);
}
return null;

View File

@ -5,6 +5,9 @@ using System;
using System.Globalization;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -15,10 +18,35 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public class DecimalModelBinder : IModelBinder
{
private readonly NumberStyles _supportedStyles;
private readonly ILogger _logger;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Initializes a new instance of <see cref="DecimalModelBinder"/>.</para>
/// </summary>
/// <param name="supportedStyles">The <see cref="NumberStyles"/>.</param>
[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 DecimalModelBinder(NumberStyles supportedStyles)
: this(supportedStyles, NullLoggerFactory.Instance)
{
}
/// <summary>
/// Initializes a new instance of <see cref="DecimalModelBinder"/>.
/// </summary>
/// <param name="supportedStyles">The <see cref="NumberStyles"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public DecimalModelBinder(NumberStyles supportedStyles, ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_supportedStyles = supportedStyles;
_logger = loggerFactory.CreateLogger<DecimalModelBinder>();
}
/// <inheritdoc />
@ -29,11 +57,16 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
_logger.AttemptingToBindModel(bindingContext);
var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
_logger.FoundNoValueInRequest(bindingContext);
// no entry
_logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
@ -72,13 +105,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
modelName,
metadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
valueProviderResult.ToString()));
return Task.CompletedTask;
}
else
{
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
catch (Exception exception)
@ -94,8 +124,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
modelState.TryAddModelError(modelName, exception, metadata);
// Conversion failed.
return Task.CompletedTask;
}
_logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
}
}

View File

@ -9,6 +9,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
{
@ -21,13 +23,28 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
private readonly IModelBinder _valueBinder;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Creates a new <see cref="DictionaryModelBinder{TKey, TValue}"/>.</para>
/// </summary>
/// <param name="keyBinder">The <see cref="IModelBinder"/> for <typeparamref name="TKey"/>.</param>
/// <param name="valueBinder">The <see cref="IModelBinder"/> for <typeparamref name="TValue"/>.</param>
[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 DictionaryModelBinder(IModelBinder keyBinder, IModelBinder valueBinder)
: this(keyBinder, valueBinder, NullLoggerFactory.Instance)
{
}
/// <summary>
/// Creates a new <see cref="DictionaryModelBinder{TKey, TValue}"/>.
/// </summary>
/// <param name="keyBinder">The <see cref="IModelBinder"/> for <typeparamref name="TKey"/>.</param>
/// <param name="valueBinder">The <see cref="IModelBinder"/> for <typeparamref name="TValue"/>.</param>
public DictionaryModelBinder(IModelBinder keyBinder, IModelBinder valueBinder)
: base(new KeyValuePairModelBinder<TKey, TValue>(keyBinder, valueBinder))
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public DictionaryModelBinder(IModelBinder keyBinder, IModelBinder valueBinder, ILoggerFactory loggerFactory)
: base(new KeyValuePairModelBinder<TKey, TValue>(keyBinder, valueBinder, loggerFactory), loggerFactory)
{
if (valueBinder == null)
{
@ -62,6 +79,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
return;
}
Logger.NoKeyValueFormatForDictionaryModelBinder(bindingContext);
var enumerableValueProvider = bindingContext.ValueProvider as IEnumerableValueProvider;
if (enumerableValueProvider == null)
{

View File

@ -3,7 +3,9 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -31,7 +33,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var valueBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(valueType));
var binderType = typeof(DictionaryModelBinder<,>).MakeGenericType(dictionaryType.GenericTypeArguments);
return (IModelBinder)Activator.CreateInstance(binderType, keyBinder, valueBinder);
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return (IModelBinder)Activator.CreateInstance(binderType, keyBinder, valueBinder, loggerFactory);
}
return null;

View File

@ -5,6 +5,9 @@ using System;
using System.Globalization;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -15,10 +18,35 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public class DoubleModelBinder : IModelBinder
{
private readonly NumberStyles _supportedStyles;
private readonly ILogger _logger;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Initializes a new instance of <see cref="DoubleModelBinder"/>.</para>
/// </summary>
/// <param name="supportedStyles">The <see cref="NumberStyles"/>.</param>
[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 DoubleModelBinder(NumberStyles supportedStyles)
: this(supportedStyles, NullLoggerFactory.Instance)
{
}
/// <summary>
/// Initializes a new instance of <see cref="DoubleModelBinder"/>.
/// </summary>
/// <param name="supportedStyles">The <see cref="NumberStyles"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public DoubleModelBinder(NumberStyles supportedStyles, ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_supportedStyles = supportedStyles;
_logger = loggerFactory.CreateLogger<DoubleModelBinder>();
}
/// <inheritdoc />
@ -29,11 +57,16 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
_logger.AttemptingToBindModel(bindingContext);
var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
_logger.FoundNoValueInRequest(bindingContext);
// no entry
_logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
@ -72,13 +105,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
modelName,
metadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
valueProviderResult.ToString()));
return Task.CompletedTask;
}
else
{
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
catch (Exception exception)
@ -94,8 +124,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
modelState.TryAddModelError(modelName, exception, metadata);
// Conversion failed.
return Task.CompletedTask;
}
_logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Globalization;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -13,15 +14,31 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
private readonly bool _suppressBindingUndefinedValueToEnumType;
public EnumTypeModelBinder(bool supressBindingUndefinedValueToEnumType, Type modelType)
: base(modelType)
/// <summary>
/// Initializes a new instance of <see cref="EnumTypeModelBinder"/>.
/// </summary>
/// <param name="suppressBindingUndefinedValueToEnumType">
/// Flag to determine if binding to undefined should be suppressed or not.
/// </param>
/// <param name="modelType">The mdoel type.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>,</param>
public EnumTypeModelBinder(
bool suppressBindingUndefinedValueToEnumType,
Type modelType,
ILoggerFactory loggerFactory)
: base(modelType, loggerFactory)
{
if (modelType == null)
{
throw new ArgumentNullException(nameof(modelType));
}
_suppressBindingUndefinedValueToEnumType = supressBindingUndefinedValueToEnumType;
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_suppressBindingUndefinedValueToEnumType = suppressBindingUndefinedValueToEnumType;
}
protected override void CheckModel(

View File

@ -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
{
@ -12,6 +14,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
private readonly MvcOptions _options;
/// <summary>
/// Initializes a new instance of <see cref="EnumTypeModelBinderProvider"/>.
/// </summary>
/// <param name="options">The <see cref="MvcOptions"/>.</param>
public EnumTypeModelBinderProvider(MvcOptions options)
{
_options = options;
@ -27,9 +33,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
if (context.Metadata.IsEnum)
{
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new EnumTypeModelBinder(
_options.SuppressBindingUndefinedValueToEnumType,
context.Metadata.UnderlyingOrModelType);
context.Metadata.UnderlyingOrModelType,
loggerFactory);
}
return null;

View File

@ -5,6 +5,9 @@ using System;
using System.Globalization;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -15,10 +18,35 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public class FloatModelBinder : IModelBinder
{
private readonly NumberStyles _supportedStyles;
private readonly ILogger _logger;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Initializes a new instance of <see cref="FloatModelBinder"/>.</para>
/// </summary>
/// <param name="supportedStyles">The <see cref="NumberStyles"/>.</param>
[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 FloatModelBinder(NumberStyles supportedStyles)
: this(supportedStyles, NullLoggerFactory.Instance)
{
}
/// <summary>
/// Initializes a new instance of <see cref="FloatModelBinder"/>.
/// </summary>
/// <param name="supportedStyles">The <see cref="NumberStyles"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public FloatModelBinder(NumberStyles supportedStyles, ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_supportedStyles = supportedStyles;
_logger = loggerFactory.CreateLogger<FloatModelBinder>();
}
/// <inheritdoc />
@ -29,11 +57,16 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
_logger.AttemptingToBindModel(bindingContext);
var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
_logger.FoundNoValueInRequest(bindingContext);
// no entry
_logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
@ -72,13 +105,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
modelName,
metadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(
valueProviderResult.ToString()));
return Task.CompletedTask;
}
else
{
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
catch (Exception exception)
@ -94,8 +124,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
modelState.TryAddModelError(modelName, exception, metadata);
// Conversion failed.
return Task.CompletedTask;
}
_logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
}
}

View File

@ -3,6 +3,8 @@
using System;
using System.Globalization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -25,19 +27,20 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
}
var modelType = context.Metadata.UnderlyingOrModelType;
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
if (modelType == typeof(decimal))
{
return new DecimalModelBinder(SupportedStyles);
return new DecimalModelBinder(SupportedStyles, loggerFactory);
}
if (modelType == typeof(double))
{
return new DoubleModelBinder(SupportedStyles);
return new DoubleModelBinder(SupportedStyles, loggerFactory);
}
if (modelType == typeof(float))
{
return new FloatModelBinder(SupportedStyles);
return new FloatModelBinder(SupportedStyles, loggerFactory);
}
return null;

View File

@ -7,6 +7,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Primitives;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
@ -16,6 +19,34 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
/// </summary>
public class FormCollectionModelBinder : IModelBinder
{
private readonly ILogger _logger;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Initializes a new instance of <see cref="FormCollectionModelBinder"/>.</para>
/// </summary>
[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 FormCollectionModelBinder()
: this(NullLoggerFactory.Instance)
{
}
/// <summary>
/// Initializes a new instance of <see cref="FormCollectionModelBinder"/>.
/// </summary>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public FormCollectionModelBinder(ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger<FormCollectionModelBinder>();
}
/// <inheritdoc />
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
@ -24,6 +55,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
_logger.AttemptingToBindModel(bindingContext);
object model;
var request = bindingContext.HttpContext.Request;
if (request.HasFormContentType)
@ -33,10 +66,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
}
else
{
_logger.CannotBindToFilesCollectionDueToUnsupportedContentType(bindingContext);
model = new EmptyFormCollection();
}
bindingContext.Result = ModelBindingResult.Success(model);
_logger.DoneAttemptingToBindModel(bindingContext);
}
private class EmptyFormCollection : IFormCollection

View File

@ -5,6 +5,8 @@ using System;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -34,7 +36,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
if (modelType == typeof(IFormCollection))
{
return new FormCollectionModelBinder();
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new FormCollectionModelBinder(loggerFactory);
}
return null;

View File

@ -8,8 +8,11 @@ using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
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
{
@ -18,6 +21,34 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
/// </summary>
public class FormFileModelBinder : IModelBinder
{
private readonly ILogger _logger;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Initializes a new instance of <see cref="FormFileModelBinder"/>.</para>
/// </summary>
[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 FormFileModelBinder()
: this(NullLoggerFactory.Instance)
{
}
/// <summary>
/// Initializes a new instance of <see cref="FormFileModelBinder"/>.
/// </summary>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public FormFileModelBinder(ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger<FormFileModelBinder>();
}
/// <inheritdoc />
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
@ -26,6 +57,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
_logger.AttemptingToBindModel(bindingContext);
var createFileCollection = bindingContext.ModelType == typeof(IFormFileCollection);
if (!createFileCollection && !ModelBindingHelper.CanGetCompatibleCollection<IFormFile>(bindingContext))
{
@ -58,6 +91,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
if (postedFiles.Count == 0)
{
// Silently fail if the named file does not exist in the request.
_logger.DoneAttemptingToBindModel(bindingContext);
return;
}
@ -69,6 +103,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
// Silently fail if no files match. Will bind to an empty collection (treat empty as a success
// case and not reach here) if binding to a top-level object.
_logger.DoneAttemptingToBindModel(bindingContext);
return;
}
@ -103,6 +138,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
attemptedValue: null);
bindingContext.Result = ModelBindingResult.Success(value);
_logger.DoneAttemptingToBindModel(bindingContext);
}
private async Task GetFormFilesAsync(
@ -128,6 +164,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
postedFiles.Add(file);
}
}
if (postedFiles.Count == 0)
{
_logger.NoFilesFoundInRequest();
}
}
else
{
_logger.CannotBindToFilesCollectionDueToUnsupportedContentType(bindingContext);
}
}

View File

@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -27,7 +29,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
modelType == typeof(IFormFileCollection) ||
typeof(IEnumerable<IFormFile>).IsAssignableFrom(modelType))
{
return new FormFileModelBinder();
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new FormFileModelBinder(loggerFactory);
}
return null;

View File

@ -4,7 +4,10 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -14,6 +17,34 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
/// </summary>
public class HeaderModelBinder : IModelBinder
{
private readonly ILogger _logger;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Initializes a new instance of <see cref="HeaderModelBinder"/>.</para>
/// </summary>
[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 HeaderModelBinder()
: this(NullLoggerFactory.Instance)
{
}
/// <summary>
/// Initializes a new instance of <see cref="HeaderModelBinder"/>.
/// </summary>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public HeaderModelBinder(ILoggerFactory loggerFactory)
{
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger<HeaderModelBinder>();
}
/// <inheritdoc />
public Task BindModelAsync(ModelBindingContext bindingContext)
{
@ -27,6 +58,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Property name can be null if the model metadata represents a type (rather than a property or parameter).
var headerName = bindingContext.FieldName;
_logger.AttemptingToBindModel(bindingContext);
if (!request.Headers.ContainsKey(headerName))
{
_logger.FoundNoValueInRequest(bindingContext);
}
object model;
if (bindingContext.ModelType == typeof(string))
{
@ -62,6 +100,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bindingContext.Result = ModelBindingResult.Success(model);
}
_logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}

View File

@ -2,6 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -21,12 +24,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
if (context.BindingInfo.BindingSource != null &&
context.BindingInfo.BindingSource.CanAcceptDataFrom(BindingSource.Header))
{
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<HeaderModelBinderProvider>();
// We only support strings and collections of strings. Some cases can fail
// at runtime due to collections we can't modify.
if (context.Metadata.ModelType == typeof(string) ||
context.Metadata.ElementType == typeof(string))
{
return new HeaderModelBinder();
return new HeaderModelBinder(loggerFactory);
}
else
{
logger.CannotCreateHeaderModelBinder(context.Metadata.ModelType);
}
}

View File

@ -4,7 +4,10 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -17,13 +20,29 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
private readonly IModelBinder _keyBinder;
private readonly IModelBinder _valueBinder;
private readonly ILogger _logger;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Creates a new <see cref="KeyValuePair{TKey, TValue}"/>.</para>
/// </summary>
/// <param name="keyBinder">The <see cref="IModelBinder"/> for <typeparamref name="TKey"/>.</param>
/// <param name="valueBinder">The <see cref="IModelBinder"/> for <typeparamref name="TValue"/>.</param>
[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 KeyValuePairModelBinder(IModelBinder keyBinder, IModelBinder valueBinder)
: this(keyBinder, valueBinder, NullLoggerFactory.Instance)
{
}
/// <summary>
/// Creates a new <see cref="KeyValuePair{TKey, TValue}"/>.
/// </summary>
/// <param name="keyBinder">The <see cref="IModelBinder"/> for <typeparamref name="TKey"/>.</param>
/// <param name="valueBinder">The <see cref="IModelBinder"/> for <typeparamref name="TValue"/>.</param>
public KeyValuePairModelBinder(IModelBinder keyBinder, IModelBinder valueBinder)
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public KeyValuePairModelBinder(IModelBinder keyBinder, IModelBinder valueBinder, ILoggerFactory loggerFactory)
{
if (keyBinder == null)
{
@ -35,8 +54,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(valueBinder));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_keyBinder = keyBinder;
_valueBinder = valueBinder;
_logger = loggerFactory.CreateLogger<KeyValuePairModelBinder<TKey, TValue>>();
}
/// <inheritdoc />
@ -47,6 +72,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
throw new ArgumentNullException(nameof(bindingContext));
}
_logger.AttemptingToBindModel(bindingContext);
var keyModelName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, "Key");
var keyResult = await TryBindStrongModel<TKey>(bindingContext, _keyBinder, "Key", keyModelName);
@ -60,6 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
ModelBindingHelper.CastOrDefault<TValue>(valueResult.Model));
bindingContext.Result = ModelBindingResult.Success(model);
_logger.DoneAttemptingToBindModel(bindingContext);
return;
}
@ -68,6 +96,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bindingContext.ModelState.TryAddModelError(
keyModelName,
bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingKeyOrValueAccessor());
_logger.DoneAttemptingToBindModel(bindingContext);
return;
}
@ -76,6 +105,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bindingContext.ModelState.TryAddModelError(
valueModelName,
bindingContext.ModelMetadata.ModelBindingMessageProvider.MissingKeyOrValueAccessor());
_logger.DoneAttemptingToBindModel(bindingContext);
return;
}
@ -86,6 +116,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var model = new KeyValuePair<TKey, TValue>();
bindingContext.Result = ModelBindingResult.Success(model);
}
_logger.DoneAttemptingToBindModel(bindingContext);
}
internal async Task<ModelBindingResult> TryBindStrongModel<TModel>(

View File

@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -21,7 +23,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
}
var modelTypeInfo = context.Metadata.ModelType.GetTypeInfo();
if (modelTypeInfo.IsGenericType &&
if (modelTypeInfo.IsGenericType &&
modelTypeInfo.GetGenericTypeDefinition().GetTypeInfo() == typeof(KeyValuePair<,>).GetTypeInfo())
{
var typeArguments = modelTypeInfo.GenericTypeArguments;
@ -33,7 +35,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var valueBinder = context.CreateBinder(valueMetadata);
var binderType = typeof(KeyValuePairModelBinder<,>).MakeGenericType(typeArguments);
return (IModelBinder)Activator.CreateInstance(binderType, keyBinder, valueBinder);
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return (IModelBinder)Activator.CreateInstance(binderType, keyBinder, valueBinder, loggerFactory);
}
return null;

View File

@ -5,6 +5,9 @@ using System;
using System.ComponentModel;
using System.Runtime.ExceptionServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -14,15 +17,40 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public class SimpleTypeModelBinder : IModelBinder
{
private readonly TypeConverter _typeConverter;
private readonly ILogger _logger;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Initializes a new instance of <see cref="SimpleTypeModelBinder"/>.</para>
/// </summary>
/// <param name="type">The type to create binder for.</param>
[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 SimpleTypeModelBinder(Type type)
: this(type, NullLoggerFactory.Instance)
{
}
/// <summary>
/// Initializes a new instance of <see cref="SimpleTypeModelBinder"/>.
/// </summary>
/// <param name="type">The type to create binder for.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public SimpleTypeModelBinder(Type type, ILoggerFactory loggerFactory)
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_typeConverter = TypeDescriptor.GetConverter(type);
_logger = loggerFactory.CreateLogger<SimpleTypeModelBinder>();
}
/// <inheritdoc />
@ -36,10 +64,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (valueProviderResult == ValueProviderResult.None)
{
_logger.FoundNoValueInRequest(bindingContext);
// no entry
_logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
_logger.AttemptingToBindModel(bindingContext);
bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);
try
@ -74,6 +107,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
CheckModel(bindingContext, valueProviderResult, model);
_logger.DoneAttemptingToBindModel(bindingContext);
return Task.CompletedTask;
}
catch (Exception exception)

View File

@ -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.IsComplexType)
{
return new SimpleTypeModelBinder(context.Metadata.ModelType);
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new SimpleTypeModelBinder(context.Metadata.ModelType, loggerFactory);
}
return null;

View File

@ -10,7 +10,10 @@ using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
@ -22,20 +25,42 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
private readonly IModelMetadataProvider _metadataProvider;
private readonly IModelBinderProvider[] _providers;
private readonly ConcurrentDictionary<Key, IModelBinder> _cache;
private readonly IServiceProvider _serviceProvider;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="IServiceProvider"/>.</para>
/// <para>Creates a new <see cref="ModelBinderFactory"/>.</para>
/// </summary>
/// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
/// <param name="options">The <see cref="IOptions{TOptions}"/> for <see cref="MvcOptions"/>.</param>
[Obsolete("This constructor is obsolete and will be removed in a future version. The recommended alternative"
+ " is the overload that also takes an " + nameof(IServiceProvider) + ".")]
public ModelBinderFactory(IModelMetadataProvider metadataProvider, IOptions<MvcOptions> options)
: this(metadataProvider, options, GetDefaultServices())
{
}
/// <summary>
/// Creates a new <see cref="ModelBinderFactory"/>.
/// </summary>
/// <param name="metadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
/// <param name="options">The <see cref="IOptions{TOptions}"/> for <see cref="MvcOptions"/>.</param>
public ModelBinderFactory(IModelMetadataProvider metadataProvider, IOptions<MvcOptions> options)
/// <param name="serviceProvider">The <see cref="IServiceProvider"/>.</param>
public ModelBinderFactory(
IModelMetadataProvider metadataProvider,
IOptions<MvcOptions> options,
IServiceProvider serviceProvider)
{
_metadataProvider = metadataProvider;
_providers = options.Value.ModelBinderProviders.ToArray();
_serviceProvider = serviceProvider;
_cache = new ConcurrentDictionary<Key, IModelBinder>();
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<ModelBinderFactory>();
logger.RegisteredModelBinderProviders(_providers);
}
/// <inheritdoc />
@ -195,6 +220,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return _cache.TryGetValue(new Key(metadata, cacheToken), out binder);
}
private static IServiceProvider GetDefaultServices()
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
return services.BuildServiceProvider();
}
private class DefaultModelBinderProviderContext : ModelBinderProviderContext
{
private readonly ModelBinderFactory _factory;
@ -245,6 +277,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public Dictionary<Key, IModelBinder> Visited { get; }
public override IServiceProvider Services => _factory._serviceProvider;
public override IModelBinder CreateBinder(ModelMetadata metadata)
{
if (metadata == null)

View File

@ -6,6 +6,8 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
@ -20,17 +22,47 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
private readonly IModelValidatorProvider _validatorProvider;
private readonly ValidatorCache _validatorCache;
/// <summary>
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="ILoggerFactory"/>.</para>
/// <para>Initializes a new instance of <see cref="ParameterBinder"/>.</para>
/// </summary>
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
/// <param name="modelBinderFactory">The <see cref="IModelBinderFactory"/>.</param>
/// <param name="validatorProvider">The <see cref="IModelValidatorProvider"/>.</param>
[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 ParameterBinder(
IModelMetadataProvider modelMetadataProvider,
IModelBinderFactory modelBinderFactory,
IModelValidatorProvider validatorProvider)
: this(
modelMetadataProvider,
modelBinderFactory,
validatorProvider,
validatorForBackCompatOnly: null,
loggerFactory: NullLoggerFactory.Instance)
{
}
/// <summary>
/// Initializes a new instance of <see cref="ParameterBinder"/>.
/// </summary>
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
/// <param name="modelBinderFactory">The <see cref="IModelBinderFactory"/>.</param>
/// <param name="validatorProvider">The <see cref="IModelValidatorProvider"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
public ParameterBinder(
IModelMetadataProvider modelMetadataProvider,
IModelBinderFactory modelBinderFactory,
IModelValidatorProvider validatorProvider)
: this(modelMetadataProvider, modelBinderFactory, validatorProvider, null)
IModelValidatorProvider validatorProvider,
ILoggerFactory loggerFactory)
: this(
modelMetadataProvider,
modelBinderFactory,
validatorProvider,
validatorForBackCompatOnly: null,
loggerFactory: loggerFactory)
{
if (validatorProvider == null)
{
@ -39,17 +71,27 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
/// <summary>
/// Initializes a new instance of <see cref="ParameterBinder"/>.
/// <para>This constructor is obsolete and will be removed in a future version. The recommended alternative
/// is the overload that also takes an <see cref="IModelValidatorProvider"/> and <see cref="ILoggerFactory"/>
/// instead of an <see cref="IObjectModelValidator"/>.</para>
/// <para>Initializes a new instance of <see cref="ParameterBinder"/>.</para>
/// </summary>
/// <param name="modelMetadataProvider">The <see cref="IModelMetadataProvider"/>.</param>
/// <param name="modelBinderFactory">The <see cref="IModelBinderFactory"/>.</param>
/// <param name="validator">The <see cref="IObjectModelValidator"/>.</param>
[Obsolete("This constructor is obsolete and will be removed in a future version. The recommended alternative is the overload that takes a " + nameof(IModelValidatorProvider) + " instead of a " + nameof(IObjectModelValidator) + ".")]
[Obsolete("This constructor is obsolete and will be removed in a future version. The recommended alternative"
+ " is the overload that takes an " + nameof(IModelValidatorProvider) + " and " + nameof(ILoggerFactory)
+ " instead of an " + nameof(IObjectModelValidator) + ".")]
public ParameterBinder(
IModelMetadataProvider modelMetadataProvider,
IModelBinderFactory modelBinderFactory,
IObjectModelValidator validator)
: this(modelMetadataProvider, modelBinderFactory, null, validator)
: this(
modelMetadataProvider,
modelBinderFactory,
validatorProvider: null,
validatorForBackCompatOnly: validator,
loggerFactory: NullLoggerFactory.Instance)
{
// Note: When this obsolete constructor overload is removed, also remember
// to remove the validatorForBackCompatOnly field.
@ -64,7 +106,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
IModelMetadataProvider modelMetadataProvider,
IModelBinderFactory modelBinderFactory,
IModelValidatorProvider validatorProvider,
IObjectModelValidator validatorForBackCompatOnly)
IObjectModelValidator validatorForBackCompatOnly,
ILoggerFactory loggerFactory)
{
if (modelMetadataProvider == null)
{
@ -76,13 +119,24 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
throw new ArgumentNullException(nameof(modelBinderFactory));
}
if (loggerFactory == null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_modelMetadataProvider = modelMetadataProvider;
_modelBinderFactory = modelBinderFactory;
_validatorProvider = validatorProvider;
_validatorForBackCompatOnly = validatorForBackCompatOnly;
_validatorCache = new ValidatorCache();
Logger = loggerFactory.CreateLogger(GetType());
}
/// <summary>
/// The <see cref="ILogger"/> used for logging in this binder.
/// </summary>
protected ILogger Logger { get; }
/// <summary>
/// Initializes and binds a model specified by <paramref name="parameter"/>.
/// </summary>
@ -200,6 +254,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
parameter.Name);
modelBindingContext.Model = value;
Logger.AttemptingToBindParameterOrProperty(parameter, modelBindingContext);
var parameterModelName = parameter.BindingInfo?.BinderModelName ?? metadata.BinderModelName;
if (parameterModelName != null)
{
@ -219,6 +275,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
await modelBinder.BindModelAsync(modelBindingContext);
Logger.DoneAttemptingToBindParameterOrProperty(parameter, modelBindingContext);
var modelBindingResult = modelBindingContext.Result;
if (_validatorForBackCompatOnly != null)
@ -237,11 +295,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
else
{
Logger.AttemptingToValidateParameterOrProperty(parameter, modelBindingContext);
EnforceBindRequiredAndValidate(
actionContext,
metadata,
modelBindingContext,
modelBindingResult);
Logger.DoneAttemptingToValidateParameterOrProperty(parameter, modelBindingContext);
}
return modelBindingResult;

View File

@ -18,6 +18,9 @@ using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.TestCommon;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Moq;
@ -2832,7 +2835,13 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test
private static ControllerBase GetController(IModelBinder binder, IValueProvider valueProvider)
{
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
var httpContext = new DefaultHttpContext();
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
var httpContext = new DefaultHttpContext()
{
RequestServices = services.BuildServiceProvider()
};
var validatorProviders = new[]
{

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
@ -108,7 +109,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
new ParameterBinder(
modelMetadataProvider,
modelBinderFactory,
Mock.Of<IModelValidatorProvider>()),
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance),
modelBinderFactory,
modelMetadataProvider,
filterProviders,

View File

@ -17,6 +17,9 @@ using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
@ -1032,10 +1035,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
return Task.FromResult(result);
});
var controllerContext = new ControllerContext
{
ActionDescriptor = actionDescriptor,
};
var controllerContext = GetControllerContext(actionDescriptor);
var arguments = new Dictionary<string, object>(StringComparer.Ordinal);
var modelState = controllerContext.ModelState;
@ -1063,10 +1063,16 @@ namespace Microsoft.AspNetCore.Mvc.Internal
private static ControllerContext GetControllerContext(ControllerActionDescriptor descriptor = null)
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
var context = new ControllerContext()
{
ActionDescriptor = descriptor ?? GetActionDescriptor(),
HttpContext = new DefaultHttpContext(),
HttpContext = new DefaultHttpContext()
{
RequestServices = services.BuildServiceProvider()
},
RouteData = new RouteData(),
};
@ -1140,7 +1146,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
return new ParameterBinder(
modelMetadataProvider ?? TestModelMetadataProvider.CreateDefaultProvider(),
factory,
validatorProvider.Object);
validatorProvider.Object,
NullLoggerFactory.Instance);
}
private static Mock<IModelValidator> CreateMockValidator()

View File

@ -448,7 +448,8 @@ namespace Microsoft.AspNetCore.Mvc.Internal
: base(
new EmptyModelMetadataProvider(),
TestModelBinderFactory.CreateDefault(),
Mock.Of<IModelValidatorProvider>())
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance)
{
_actionParameters = actionParameters;
}

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
@ -27,7 +28,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
typeof(ModelWithIntArrayProperty),
nameof(ModelWithIntArrayProperty.ArrayProperty));
var binder = new ArrayModelBinder<int>(new SimpleTypeModelBinder(typeof(int)));
var binder = new ArrayModelBinder<int>(
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -43,7 +46,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task ArrayModelBinder_CreatesEmptyCollection_IfIsTopLevelObject()
{
// Arrange
var binder = new ArrayModelBinder<string>(new SimpleTypeModelBinder(typeof(string)));
var binder = new ArrayModelBinder<string>(
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.IsTopLevelObject = true;
@ -70,7 +75,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task ArrayModelBinder_DoesNotCreateCollection_IfNotIsTopLevelObject(string prefix)
{
// Arrange
var binder = new ArrayModelBinder<string>(new SimpleTypeModelBinder(typeof(string)));
var binder = new ArrayModelBinder<string>(
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.ModelName = ModelNames.CreatePropertyModelName(prefix, "ArrayProperty");
@ -126,7 +133,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
typeof(ModelWithIntArrayProperty),
nameof(ModelWithIntArrayProperty.ArrayProperty));
var binder = new ArrayModelBinder<int>(new SimpleTypeModelBinder(typeof(int)));
var binder = new ArrayModelBinder<int>(
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);

View File

@ -648,8 +648,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
await binder.BindModelAsync(bindingContext);
// Assert
Assert.Equal($"Rejected input formatter '{typeof(TestInputFormatter)}' for content type 'application/json'.", sink.Writes[0].State.ToString());
Assert.Equal($"Selected input formatter '{typeof(TestInputFormatter)}' for content type 'application/json'.", sink.Writes[1].State.ToString());
Assert.Equal($"Attempting to bind model of type '{typeof(Person)}' using the name 'someName' in request data ...", sink.Writes[0].State.ToString());
Assert.Equal($"Rejected input formatter '{typeof(TestInputFormatter)}' for content type 'application/json'.", sink.Writes[1].State.ToString());
Assert.Equal($"Selected input formatter '{typeof(TestInputFormatter)}' for content type 'application/json'.", sink.Writes[2].State.ToString());
}
[Fact]
@ -677,6 +678,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Assert
Assert.Collection(
sink.Writes,
write => Assert.Equal(
$"Attempting to bind model of type '{typeof(Person)}' using the name 'someName' in request data ...", write.State.ToString()),
write => Assert.Equal(
$"Rejected input formatter '{typeof(TestInputFormatter)}' for content type 'multipart/form-data'.", write.State.ToString()),
write => Assert.Equal(
@ -684,7 +687,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
write => Assert.Equal(
"No input formatter was found to support the content type 'multipart/form-data' for use with the [FromBody] attribute.", write.State.ToString()),
write => Assert.Equal(
$"To use model binding, remove the [FromBody] attribute from the property or parameter named '{bindingContext.ModelName}' with model type '{bindingContext.ModelType}'.", write.State.ToString()));
$"To use model binding, remove the [FromBody] attribute from the property or parameter named '{bindingContext.ModelName}' with model type '{bindingContext.ModelType}'.", write.State.ToString()),
write => Assert.Equal(
$"Done attempting to bind model of type '{typeof(Person)}' using the name 'someName'.", write.State.ToString()));
}
[Fact]

View File

@ -3,6 +3,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
@ -21,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
};
var bindingContext = GetBindingContext(valueProvider, typeof(byte[]));
var binder = new ByteArrayModelBinder();
var binder = new ByteArrayModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -45,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
};
var bindingContext = GetBindingContext(valueProvider, typeof(byte[]));
var binder = new ByteArrayModelBinder();
var binder = new ByteArrayModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -68,7 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
};
var bindingContext = GetBindingContext(valueProvider, typeof(byte[]));
var binder = new ByteArrayModelBinder();
var binder = new ByteArrayModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -90,7 +91,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
};
var bindingContext = GetBindingContext(valueProvider, typeof(byte[]));
var binder = new ByteArrayModelBinder();
var binder = new ByteArrayModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
@ -26,7 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "someName[baz]", "200" }
};
var bindingContext = GetModelBindingContext(valueProvider);
var binder = new CollectionModelBinder<int>(CreateIntBinder());
var binder = new CollectionModelBinder<int>(CreateIntBinder(), NullLoggerFactory.Instance);
// Act
var collectionResult = await binder.BindComplexCollectionFromIndexes(
@ -52,7 +53,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "someName[3]", "400" }
};
var bindingContext = GetModelBindingContext(valueProvider);
var binder = new CollectionModelBinder<int>(CreateIntBinder());
var binder = new CollectionModelBinder<int>(CreateIntBinder(), NullLoggerFactory.Instance);
// Act
var boundCollection = await binder.BindComplexCollectionFromIndexes(bindingContext, indexNames: null);
@ -79,7 +80,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
};
var bindingContext = GetModelBindingContext(valueProvider, isReadOnly);
var modelState = bindingContext.ModelState;
var binder = new CollectionModelBinder<int>(CreateIntBinder());
var binder = new CollectionModelBinder<int>(CreateIntBinder(), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -110,7 +111,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var modelState = bindingContext.ModelState;
var list = new List<int>();
bindingContext.Model = list;
var binder = new CollectionModelBinder<int>(CreateIntBinder());
var binder = new CollectionModelBinder<int>(CreateIntBinder(), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -136,7 +137,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
};
var bindingContext = GetModelBindingContext(valueProvider, isReadOnly);
var modelState = bindingContext.ModelState;
var binder = new CollectionModelBinder<int>(CreateIntBinder());
var binder = new CollectionModelBinder<int>(CreateIntBinder(), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -162,7 +163,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var modelState = bindingContext.ModelState;
var list = new List<int>();
bindingContext.Model = list;
var binder = new CollectionModelBinder<int>(CreateIntBinder());
var binder = new CollectionModelBinder<int>(CreateIntBinder(), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -178,7 +179,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task BindModelAsync_SimpleCollectionWithNullValue_Succeeds()
{
// Arrange
var binder = new CollectionModelBinder<int>(CreateIntBinder());
var binder = new CollectionModelBinder<int>(CreateIntBinder(), NullLoggerFactory.Instance);
var valueProvider = new SimpleValueProvider
{
{ "someName", null },
@ -199,7 +200,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task BindSimpleCollection_RawValueIsEmptyCollection_ReturnsEmptyList()
{
// Arrange
var binder = new CollectionModelBinder<int>(CreateIntBinder());
var binder = new CollectionModelBinder<int>(CreateIntBinder(), NullLoggerFactory.Instance);
var context = GetModelBindingContext(new SimpleValueProvider());
// Act
@ -214,7 +215,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task CollectionModelBinder_CreatesEmptyCollection_IfIsTopLevelObject()
{
// Arrange
var binder = new CollectionModelBinder<string>(new StubModelBinder(result: ModelBindingResult.Failed()));
var binder = new CollectionModelBinder<string>(
new StubModelBinder(result: ModelBindingResult.Failed()),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.IsTopLevelObject = true;
@ -241,7 +244,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task CollectionModelBinder_DoesNotCreateEmptyCollection_IfModelNonNull()
{
// Arrange
var binder = new CollectionModelBinder<string>(new StubModelBinder(result: ModelBindingResult.Failed()));
var binder = new CollectionModelBinder<string>(
new StubModelBinder(result: ModelBindingResult.Failed()),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.IsTopLevelObject = true;
@ -272,7 +277,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task CollectionModelBinder_DoesNotCreateCollection_IfNotIsTopLevelObject(string prefix)
{
// Arrange
var binder = new CollectionModelBinder<string>(new StubModelBinder(result: ModelBindingResult.Failed()));
var binder = new CollectionModelBinder<string>(
new StubModelBinder(result: ModelBindingResult.Failed()),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.ModelName = ModelNames.CreatePropertyModelName(prefix, "ListProperty");
@ -313,7 +320,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public void CanCreateInstance_ReturnsExpectedValue(Type modelType, bool expectedResult)
{
// Arrange
var binder = new CollectionModelBinder<int>(CreateIntBinder());
var binder = new CollectionModelBinder<int>(CreateIntBinder(), NullLoggerFactory.Instance);
// Act
var result = binder.CanCreateInstance(modelType);
@ -335,7 +342,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
mbc.Result = ModelBindingResult.Success(42);
});
var modelBinder = new CollectionModelBinder<int>(elementBinder);
var modelBinder = new CollectionModelBinder<int>(elementBinder, NullLoggerFactory.Instance);
// Act
var boundCollection = await modelBinder.BindSimpleCollection(

View File

@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
@ -1352,7 +1353,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
}
public TestableComplexTypeModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders)
: base(propertyBinders)
: base(propertyBinders, NullLoggerFactory.Instance)
{
Results = new Dictionary<ModelMetadata, ModelBindingResult>();
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Globalization;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
protected override IModelBinder GetBinder(NumberStyles numberStyles)
{
return new DecimalModelBinder(numberStyles);
return new DecimalModelBinder(numberStyles, NullLoggerFactory.Instance);
}
}
}

View File

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Primitives;
using Xunit;
@ -36,8 +37,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bindingContext.ValueProvider = CreateEnumerableValueProvider("{0}", values);
var binder = new DictionaryModelBinder<int, string>(
new SimpleTypeModelBinder(typeof(int)),
new SimpleTypeModelBinder(typeof(string)));
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -76,8 +78,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bindingContext.Model = dictionary;
var binder = new DictionaryModelBinder<int, string>(
new SimpleTypeModelBinder(typeof(int)),
new SimpleTypeModelBinder(typeof(string)));
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -132,8 +135,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
// Arrange
var binder = new DictionaryModelBinder<string, string>(
new SimpleTypeModelBinder(typeof(string)),
new SimpleTypeModelBinder(typeof(string)));
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.ModelName = modelName;
@ -168,8 +172,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
};
var binder = new DictionaryModelBinder<string, string>(
new SimpleTypeModelBinder(typeof(string)),
new SimpleTypeModelBinder(typeof(string)));
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.ModelName = "prefix";
@ -218,8 +223,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var stringDictionary = dictionary.ToDictionary(kvp => kvp.Key.ToString(), kvp => kvp.Value.ToString());
var binder = new DictionaryModelBinder<long, int>(
new SimpleTypeModelBinder(typeof(long)),
new SimpleTypeModelBinder(typeof(int)));
new SimpleTypeModelBinder(typeof(long), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.ModelName = "prefix";
@ -271,12 +277,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var valueMetadata = metadataProvider.GetMetadataForType(typeof(ModelWithProperties));
var binder = new DictionaryModelBinder<int, ModelWithProperties>(
new SimpleTypeModelBinder(typeof(int)),
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
new ComplexTypeModelBinder(new Dictionary<ModelMetadata, IModelBinder>()
{
{ valueMetadata.Properties["Id"], new SimpleTypeModelBinder(typeof(int)) },
{ valueMetadata.Properties["Name"], new SimpleTypeModelBinder(typeof(string)) },
}));
{ valueMetadata.Properties["Id"], new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance) },
{ valueMetadata.Properties["Name"], new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance) },
},
NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -310,8 +318,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Arrange
var expectedDictionary = new SortedDictionary<string, string>(dictionary);
var binder = new DictionaryModelBinder<string, string>(
new SimpleTypeModelBinder(typeof(string)),
new SimpleTypeModelBinder(typeof(string)));
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.ModelName = modelName;
@ -339,8 +348,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
// Arrange
var binder = new DictionaryModelBinder<string, string>(
new SimpleTypeModelBinder(typeof(string)),
new SimpleTypeModelBinder(typeof(string)));
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.IsTopLevelObject = true;
@ -368,8 +378,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
// Arrange
var binder = new DictionaryModelBinder<int, int>(
new SimpleTypeModelBinder(typeof(int)),
new SimpleTypeModelBinder(typeof(int)));
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.ModelName = ModelNames.CreatePropertyModelName(prefix, "ListProperty");
@ -412,8 +423,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
// Arrange
var binder = new DictionaryModelBinder<int, int>(
new SimpleTypeModelBinder(typeof(int)),
new SimpleTypeModelBinder(typeof(int)));
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
// Act
var result = binder.CanCreateInstance(modelType);

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Globalization;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
protected override IModelBinder GetBinder(NumberStyles numberStyles)
{
return new DoubleModelBinder(numberStyles);
return new DoubleModelBinder(numberStyles, NullLoggerFactory.Instance);
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Globalization;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
protected override IModelBinder GetBinder(NumberStyles numberStyles)
{
return new FloatModelBinder(numberStyles);
return new FloatModelBinder(numberStyles, NullLoggerFactory.Instance);
}
}
}

View File

@ -7,6 +7,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Primitives;
using Moq;
using Xunit;
@ -26,7 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
});
var httpContext = GetMockHttpContext(formCollection);
var bindingContext = GetBindingContext(typeof(IFormCollection), httpContext);
var binder = new FormCollectionModelBinder();
var binder = new FormCollectionModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -47,7 +48,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Arrange
var httpContext = GetMockHttpContext(null, hasForm: false);
var bindingContext = GetBindingContext(typeof(IFormCollection), httpContext);
var binder = new FormCollectionModelBinder();
var binder = new FormCollectionModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
@ -23,7 +24,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
formFiles.Add(GetMockFormFile("file", "file1.txt"));
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IEnumerable<IFormFile>), httpContext);
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -44,7 +45,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var formFiles = GetTwoFiles();
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IEnumerable<IFormFile>), httpContext);
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -73,7 +74,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task FormFileModelBinder_BindsFiles_ForCollectionsItCanCreate(Type destinationType)
{
// Arrange
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
var formFiles = GetTwoFiles();
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(destinationType, httpContext);
@ -94,7 +95,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var formFiles = GetTwoFiles();
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IFormFile), httpContext);
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -112,7 +113,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var formFiles = new FormFileCollection();
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IFormFile), httpContext);
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -130,7 +131,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
formFiles.Add(GetMockFormFile("different name", "file1.txt"));
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IFormFile), httpContext);
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -156,7 +157,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
bindingContext.FieldName = "FieldName";
bindingContext.ModelName = "ModelName";
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -176,7 +177,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
formFiles.Add(new Mock<IFormFile>().Object);
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IFormFile), httpContext);
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -194,7 +195,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
formFiles.Add(GetMockFormFile("file", ""));
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(IFormFile), httpContext);
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -208,7 +209,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task FormFileModelBinder_ReturnsResult_ForReadOnlyDestination()
{
// Arrange
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
var formFiles = GetTwoFiles();
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContextForReadOnlyArray(httpContext);
@ -225,7 +226,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task FormFileModelBinder_ReturnsFailedResult_ForCollectionsItCannotCreate()
{
// Arrange
var binder = new FormFileModelBinder();
var binder = new FormFileModelBinder(NullLoggerFactory.Instance);
var formFiles = GetTwoFiles();
var httpContext = GetMockHttpContext(GetMockFormCollection(formFiles));
var bindingContext = GetBindingContext(typeof(ISet<IFormFile>), httpContext);

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
@ -21,7 +22,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
public async Task BindModelAsync_ReturnsNonEmptyResult_ForAllTypes_WithHeaderBindingSource(Type type)
{
// Arrange
var binder = new HeaderModelBinder();
var binder = new HeaderModelBinder(NullLoggerFactory.Instance);
var bindingContext = GetBindingContext(type);
// Act
@ -38,7 +39,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var type = typeof(string[]);
var header = "Accept";
var headerValue = "application/json,text/json";
var binder = new HeaderModelBinder();
var binder = new HeaderModelBinder(NullLoggerFactory.Instance);
var bindingContext = GetBindingContext(type);
bindingContext.FieldName = header;
@ -59,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var type = typeof(string);
var header = "User-Agent";
var headerValue = "UnitTest";
var binder = new HeaderModelBinder();
var binder = new HeaderModelBinder(NullLoggerFactory.Instance);
var bindingContext = GetBindingContext(type);
bindingContext.FieldName = header;
@ -85,7 +86,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Arrange
var header = "Accept";
var headerValue = "application/json,text/json";
var binder = new HeaderModelBinder();
var binder = new HeaderModelBinder(NullLoggerFactory.Instance);
var bindingContext = GetBindingContext(destinationType);
bindingContext.FieldName = header;
@ -106,7 +107,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Arrange
var header = "Accept";
var headerValue = "application/json,text/json";
var binder = new HeaderModelBinder();
var binder = new HeaderModelBinder(NullLoggerFactory.Instance);
var bindingContext = GetBindingContextForReadOnlyArray();
bindingContext.FieldName = header;
@ -126,7 +127,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Arrange
var header = "Accept";
var headerValue = "application/json,text/json";
var binder = new HeaderModelBinder();
var binder = new HeaderModelBinder(NullLoggerFactory.Instance);
var bindingContext = GetBindingContext(typeof(ISet<string>));
bindingContext.FieldName = header;

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
@ -19,7 +20,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Create string binder to create the value but not the key.
var bindingContext = GetBindingContext(valueProvider, typeof(KeyValuePair<int, string>));
var binder = new KeyValuePairModelBinder<int, string>(CreateIntBinder(false), CreateStringBinder());
var binder = new KeyValuePairModelBinder<int, string>(
CreateIntBinder(false),
CreateStringBinder(),
NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -41,8 +45,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Create int binder to create the value but not the key.
var bindingContext = GetBindingContext(valueProvider, typeof(KeyValuePair<int, string>));
var binder = new KeyValuePairModelBinder<int, string>(CreateIntBinder(), CreateStringBinder(false));
var binder = new KeyValuePairModelBinder<int, string>(
CreateIntBinder(),
CreateStringBinder(false),
NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -64,7 +71,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
// Create int binder to create the value but not the key.
var bindingContext = GetBindingContext(valueProvider, typeof(KeyValuePair<int, string>));
var binder = new KeyValuePairModelBinder<int, string>(CreateIntBinder(false), CreateStringBinder(false));
var binder = new KeyValuePairModelBinder<int, string>(
CreateIntBinder(false),
CreateStringBinder(false),
NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -82,7 +92,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var valueProvider = new SimpleValueProvider();
var bindingContext = GetBindingContext(valueProvider, typeof(KeyValuePair<int, string>));
var binder = new KeyValuePairModelBinder<int, string>(CreateIntBinder(), CreateStringBinder());
var binder = new KeyValuePairModelBinder<int, string>(
CreateIntBinder(),
CreateStringBinder(),
NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -120,7 +133,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
var valueProvider = new SimpleValueProvider();
var bindingContext = GetBindingContext(valueProvider, typeof(KeyValuePair<int, string>));
var binder = new KeyValuePairModelBinder<int, string>(innerBinder, innerBinder);
var binder = new KeyValuePairModelBinder<int, string>(innerBinder, innerBinder, NullLoggerFactory.Instance);
// Act
var result = await binder.TryBindStrongModel<int>(bindingContext, innerBinder, "Key", "someName.Key");
@ -135,8 +148,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
// Arrange
var binder = new KeyValuePairModelBinder<string, string>(
new SimpleTypeModelBinder(typeof(string)),
new SimpleTypeModelBinder(typeof(string)));
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.IsTopLevelObject = true;
@ -165,8 +179,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
// Arrange
var binder = new KeyValuePairModelBinder<string, string>(
new SimpleTypeModelBinder(typeof(string)),
new SimpleTypeModelBinder(typeof(string)));
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
NullLoggerFactory.Instance);
var bindingContext = CreateContext();
bindingContext.ModelName = ModelNames.CreatePropertyModelName(prefix, "KeyValuePairProperty");

View File

@ -5,6 +5,7 @@ using System;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", value }
};
var binder = new SimpleTypeModelBinder(typeof(string));
var binder = new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -53,7 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
.DisplayDetails(d => d.ConvertEmptyStringToNull = false);
bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string));
var binder = new SimpleTypeModelBinder(typeof(string));
var binder = new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -99,7 +100,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", "some-value" }
};
var binder = new SimpleTypeModelBinder(destinationType);
var binder = new SimpleTypeModelBinder(destinationType, NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -118,7 +119,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
{ "theModelName", string.Empty }
};
var binder = new SimpleTypeModelBinder(destinationType);
var binder = new SimpleTypeModelBinder(destinationType, NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -143,7 +144,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", "not an integer" }
};
var binder = new SimpleTypeModelBinder(typeof(int));
var binder = new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -161,7 +162,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{
// Arrange
var bindingContext = GetBindingContext(typeof(int));
var binder = new SimpleTypeModelBinder(typeof(int));
var binder = new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -183,7 +184,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", value }
};
var binder = new SimpleTypeModelBinder(typeof(string));
var binder = new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -203,7 +204,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", "12" }
};
var binder = new SimpleTypeModelBinder(typeof(int?));
var binder = new SimpleTypeModelBinder(typeof(int?), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -224,7 +225,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", "12.5" }
};
var binder = new SimpleTypeModelBinder(typeof(double?));
var binder = new SimpleTypeModelBinder(typeof(double?), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -245,7 +246,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", "42" }
};
var binder = new SimpleTypeModelBinder(typeof(int));
var binder = new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -287,7 +288,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", "32,000" }
};
var binder = new SimpleTypeModelBinder(type);
var binder = new SimpleTypeModelBinder(type, NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -315,7 +316,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", "12,5" }
};
var binder = new SimpleTypeModelBinder(typeof(decimal));
var binder = new SimpleTypeModelBinder(typeof(decimal), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -336,7 +337,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", "12,5" }
};
var binder = new SimpleTypeModelBinder(typeof(decimal));
var binder = new SimpleTypeModelBinder(typeof(decimal), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -360,7 +361,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", new object[] { "Value1" } }
};
var binder = new SimpleTypeModelBinder(typeof(IntEnum));
var binder = new SimpleTypeModelBinder(typeof(IntEnum), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -381,7 +382,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", new object[] { "1" } }
};
var binder = new SimpleTypeModelBinder(typeof(IntEnum));
var binder = new SimpleTypeModelBinder(typeof(IntEnum), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -422,7 +423,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", flagsEnumValue }
};
var binder = new SimpleTypeModelBinder(typeof(IntEnum));
var binder = new SimpleTypeModelBinder(typeof(IntEnum), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);
@ -445,7 +446,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
{ "theModelName", flagsEnumValue }
};
var binder = new SimpleTypeModelBinder(typeof(FlagsEnum));
var binder = new SimpleTypeModelBinder(typeof(FlagsEnum), NullLoggerFactory.Instance);
// Act
await binder.BindModelAsync(bindingContext);

View File

@ -9,6 +9,9 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Primitives;
using Xunit;
@ -73,7 +76,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
// Act
var context = DefaultModelBindingContext.CreateBindingContext(
new ActionContext(),
GetActionContext(),
original,
metadataProvider.GetMetadataForType(typeof(object)),
new BindingInfo() { BindingSource = BindingSource.Query },
@ -96,7 +99,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var original = CreateDefaultValueProvider();
var context = DefaultModelBindingContext.CreateBindingContext(
new ActionContext(),
GetActionContext(),
original,
metadataProvider.GetMetadataForType(typeof(string)),
new BindingInfo(),
@ -125,7 +128,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var original = CreateDefaultValueProvider();
var context = DefaultModelBindingContext.CreateBindingContext(
new ActionContext(),
GetActionContext(),
original,
metadataProvider.GetMetadataForType(typeof(string)),
new BindingInfo() { BindingSource = BindingSource.Query },
@ -155,6 +158,20 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
Assert.Equal(typeof(int), bindingContext.ModelType);
}
private static ActionContext GetActionContext()
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
return new ActionContext()
{
HttpContext = new DefaultHttpContext()
{
RequestServices = services.BuildServiceProvider()
}
};
}
private static CompositeValueProvider CreateDefaultValueProvider()
{
var result = new CompositeValueProvider();

View File

@ -5,6 +5,9 @@ using System;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
@ -21,7 +24,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
$"empty. At least one '{typeof(IModelBinderProvider).FullName}' is required to model bind.";
var metadataProvider = new TestModelMetadataProvider();
var options = Options.Create(new MvcOptions());
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
Metadata = metadataProvider.GetMetadataForType(typeof(string)),
@ -40,7 +46,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var options = Options.Create(new MvcOptions());
options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(_ => null));
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
Metadata = metadataProvider.GetMetadataForType(typeof(string)),
@ -72,7 +81,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return null;
}));
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -95,7 +107,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
.ForProperty<Widget>(nameof(Widget.Id))
.BindingDetails(m => m.IsBindingAllowed = false);
var modelBinder = new ByteArrayModelBinder();
var modelBinder = new ByteArrayModelBinder(NullLoggerFactory.Instance);
var options = Options.Create(new MvcOptions());
options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c =>
@ -108,7 +120,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return null;
}));
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -145,7 +160,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return null;
}));
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -182,7 +200,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return Mock.Of<IModelBinder>();
}));
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -209,7 +230,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return Mock.Of<IModelBinder>();
}));
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -237,7 +261,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return Mock.Of<IModelBinder>();
}));
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -345,7 +372,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var options = Options.Create(new MvcOptions());
options.Value.ModelBinderProviders.Insert(0, modelBinderProvider);
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var factoryContext = new ModelBinderFactoryContext
{
BindingInfo = parameterBindingInfo,
@ -398,7 +428,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
options.Value.ModelBinderProviders.Add(widgetProvider);
options.Value.ModelBinderProviders.Add(widgetIdProvider);
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -457,7 +490,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
options.Value.ModelBinderProviders.Add(widgetProvider);
options.Value.ModelBinderProviders.Add(widgetIdProvider);
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -508,7 +544,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
options.Value.ModelBinderProviders.Add(widgetProvider);
options.Value.ModelBinderProviders.Add(widgetIdProvider);
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -569,7 +608,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
options.Value.ModelBinderProviders.Add(widgetProvider);
options.Value.ModelBinderProviders.Add(widgetIdProvider);
var factory = new ModelBinderFactory(metadataProvider, options);
var factory = new ModelBinderFactory(
metadataProvider,
options,
GetServices());
var context = new ModelBinderFactoryContext()
{
@ -597,6 +639,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
Assert.Equal(0, widgetIdProvider.SuccessCount);
}
private IServiceProvider GetServices()
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
return services.BuildServiceProvider();
}
private class Widget
{
public WidgetId Id { get; set; }

View File

@ -16,6 +16,9 @@ using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.AspNetCore.Mvc.ModelBinding.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
@ -36,7 +39,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var result = await ModelBindingHelper.TryUpdateModelAsync(
model,
string.Empty,
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
metadataProvider,
GetModelBinderFactory(binder),
Mock.Of<IValueProvider>(),
@ -70,7 +73,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var valueProvider = new TestValueProvider(values);
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();
var actionContext = new ActionContext() { HttpContext = new DefaultHttpContext() };
var actionContext = GetActionContext();
var modelState = actionContext.ModelState;
// Act
@ -117,7 +120,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var result = await ModelBindingHelper.TryUpdateModelAsync(
model,
"",
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
metadataProvider,
GetModelBinderFactory(binderProviders),
valueProvider,
@ -141,7 +144,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var result = await ModelBindingHelper.TryUpdateModelAsync(
model,
string.Empty,
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
metadataProvider,
GetModelBinderFactory(binder),
Mock.Of<IValueProvider>(),
@ -195,7 +198,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var result = await ModelBindingHelper.TryUpdateModelAsync(
model,
"",
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
metadataProvider,
GetModelBinderFactory(binderProviders),
valueProvider,
@ -221,7 +224,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var result = await ModelBindingHelper.TryUpdateModelAsync(
model,
string.Empty,
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
metadataProvider,
GetModelBinderFactory(binder),
Mock.Of<IValueProvider>(),
@ -271,7 +274,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var result = await ModelBindingHelper.TryUpdateModelAsync(
model,
"",
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
TestModelMetadataProvider.CreateDefaultProvider(),
GetModelBinderFactory(binderProviders),
valueProvider,
@ -322,7 +325,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var result = await ModelBindingHelper.TryUpdateModelAsync(
model,
"",
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
metadataProvider,
GetModelBinderFactory(binderProviders),
valueProvider,
@ -469,7 +472,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
model,
model.GetType(),
prefix: "",
actionContext: new ActionContext() { HttpContext = new DefaultHttpContext() },
actionContext: GetActionContext(),
metadataProvider: metadataProvider,
modelBinderFactory: GetModelBinderFactory(binder),
valueProvider: Mock.Of<IValueProvider>(),
@ -524,7 +527,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
model,
model.GetType(),
"",
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
metadataProvider,
GetModelBinderFactory(binderProviders),
valueProvider,
@ -552,7 +555,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
model,
modelType: model.GetType(),
prefix: "",
actionContext: new ActionContext() { HttpContext = new DefaultHttpContext() },
actionContext: GetActionContext(),
metadataProvider: metadataProvider,
modelBinderFactory: GetModelBinderFactory(binder.Object),
valueProvider: Mock.Of<IValueProvider>(),
@ -592,7 +595,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
model,
model.GetType(),
"",
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
metadataProvider,
GetModelBinderFactory(binderProviders),
valueProvider,
@ -623,7 +626,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
model,
typeof(User),
"",
new ActionContext() { HttpContext = new DefaultHttpContext() },
GetActionContext(),
metadataProvider,
GetModelBinderFactory(binder.Object),
Mock.Of<IValueProvider>(),
@ -1492,6 +1495,20 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
Assert.False(result);
}
private static ActionContext GetActionContext()
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
return new ActionContext()
{
HttpContext = new DefaultHttpContext()
{
RequestServices = services.BuildServiceProvider()
}
};
}
private static DefaultModelBindingContext GetBindingContextForProperty(string propertyName)
{
var metadataProvider = TestModelMetadataProvider.CreateDefaultProvider();

View File

@ -5,12 +5,16 @@ using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.DataAnnotations;
using Microsoft.AspNetCore.Mvc.DataAnnotations.Internal;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
@ -94,9 +98,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var parameterBinder = new ParameterBinder(
metadataProvider,
factory.Object,
CreateMockValidatorProvider());
CreateMockValidatorProvider(),
NullLoggerFactory.Instance);
var controllerContext = new ControllerContext();
var controllerContext = GetControllerContext();
// Act & Assert
await parameterBinder.BindModelAsync(controllerContext, new SimpleValueProvider(), parameterDescriptor);
@ -144,7 +149,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
var argumentBinder = new ParameterBinder(
metadataProvider,
factory.Object,
CreateMockValidatorProvider());
CreateMockValidatorProvider(),
NullLoggerFactory.Instance);
var valueProvider = new SimpleValueProvider
{
@ -152,7 +158,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
};
var valueProviderFactory = new SimpleValueProviderFactory(valueProvider);
var controllerContext = new ControllerContext();
var controllerContext = GetControllerContext();
// Act & Assert
await argumentBinder.BindModelAsync(controllerContext, valueProvider, parameterDescriptor);
@ -163,7 +169,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public async Task BindModelAsync_EnforcesTopLevelBindRequired()
{
// Arrange
var actionContext = new ControllerContext();
var actionContext = GetControllerContext();
var mockModelMetadata = CreateMockModelMetadata();
mockModelMetadata.Setup(o => o.IsBindingRequired).Returns(true);
@ -193,7 +199,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public async Task BindModelAsync_EnforcesTopLevelRequired()
{
// Arrange
var actionContext = new ControllerContext();
var actionContext = GetControllerContext();
var mockModelMetadata = CreateMockModelMetadata();
mockModelMetadata.Setup(o => o.IsRequired).Returns(true);
mockModelMetadata.Setup(o => o.DisplayName).Returns("My Display Name");
@ -233,7 +239,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public async Task BindModelAsync_EnforcesTopLevelDataAnnotationsAttribute()
{
// Arrange
var actionContext = new ControllerContext();
var actionContext = GetControllerContext();
var mockModelMetadata = CreateMockModelMetadata();
var validationAttribute = new RangeAttribute(1, 100);
mockModelMetadata.Setup(o => o.DisplayName).Returns("My Display Name");
@ -272,7 +278,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public async Task BindModelAsync_SupportsIObjectModelValidatorForBackCompat()
{
// Arrange
var actionContext = new ControllerContext();
var actionContext = GetControllerContext();
var mockValidator = new Mock<IObjectModelValidator>(MockBehavior.Strict);
mockValidator
@ -309,6 +315,20 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
actionContext.ModelState.Single().Value.Errors.Single().ErrorMessage);
}
private static ControllerContext GetControllerContext()
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
return new ControllerContext()
{
HttpContext = new DefaultHttpContext()
{
RequestServices = services.BuildServiceProvider()
}
};
}
private static Mock<FakeModelMetadata> CreateMockModelMetadata()
{
var mockModelMetadata = new Mock<FakeModelMetadata>();
@ -344,7 +364,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return new ParameterBinder(
mockModelMetadataProvider.Object,
mockModelBinderFactory.Object,
CreateMockValidatorProvider(validator));
CreateMockValidatorProvider(validator),
NullLoggerFactory.Instance);
}
private static ParameterBinder CreateBackCompatParameterBinder(

View File

@ -3,6 +3,9 @@
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
@ -25,7 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
BindingSource = Metadata.BindingSource,
PropertyFilterProvider = Metadata.PropertyFilterProvider,
};
Services = GetServices();
}
public TestModelBinderProviderContext(ModelMetadata metadata, BindingInfo bindingInfo)
@ -40,6 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
};
MetadataProvider = CachedMetadataProvider;
Services = GetServices();
}
public override BindingInfo BindingInfo { get; }
@ -48,6 +52,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public override IModelMetadataProvider MetadataProvider { get; }
public override IServiceProvider Services { get; }
public override IModelBinder CreateBinder(ModelMetadata metadata)
{
foreach (var creator in _binderCreators)
@ -71,5 +77,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
_binderCreators.Add((m) => m.Equals(metadata) ? binderCreator() : null);
}
private static IServiceProvider GetServices()
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory, NullLoggerFactory>();
return services.BuildServiceProvider();
}
}
}

View File

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.Mvc.IntegrationTests
@ -757,7 +758,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
private class CustomComplexTypeModelBinder : ComplexTypeModelBinder
{
public CustomComplexTypeModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders)
: base(propertyBinders)
: base(propertyBinders, NullLoggerFactory.Instance)
{
}

View File

@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options;
@ -77,19 +78,22 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTests
return new ParameterBinder(
metadataProvider,
GetModelBinderFactory(metadataProvider, options),
new CompositeModelValidatorProvider(GetModelValidatorProviders(options)));
new CompositeModelValidatorProvider(GetModelValidatorProviders(options)),
NullLoggerFactory.Instance);
}
public static IModelBinderFactory GetModelBinderFactory(
IModelMetadataProvider metadataProvider,
IOptions<MvcOptions> options = null)
{
var services = GetServices();
if (options == null)
{
options = GetServices().GetRequiredService<IOptions<MvcOptions>>();
options = services.GetRequiredService<IOptions<MvcOptions>>();
}
return new ModelBinderFactory(metadataProvider, options);
return new ModelBinderFactory(metadataProvider, options, services);
}
public static IObjectModelValidator GetObjectValidator(

View File

@ -479,7 +479,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var parameterBinder = new ParameterBinder(
modelMetadataProvider,
TestModelBinderFactory.CreateDefault(),
Mock.Of<IModelValidatorProvider>());
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance);
return new PageActionInvokerProvider(
loader,

View File

@ -1238,7 +1238,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
return new ParameterBinder(
TestModelMetadataProvider.CreateDefaultProvider(),
factory,
validator);
validator,
NullLoggerFactory.Instance);
}
private static IModelValidatorProvider CreateMockValidatorProvider()

View File

@ -10,6 +10,9 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
@ -29,7 +32,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var binder = new ParameterBinder(
modelMetadataProvider,
TestModelBinderFactory.CreateDefault(),
Mock.Of<IModelValidatorProvider>());
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance);
// Act
var factory = PagePropertyBinderFactory.CreateBinder(binder, modelMetadataProvider, actionDescriptor);
@ -52,7 +56,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var binder = new ParameterBinder(
TestModelMetadataProvider.CreateDefaultProvider(),
TestModelBinderFactory.CreateDefault(),
Mock.Of<IModelValidatorProvider>());
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance);
// Act
var factory = PagePropertyBinderFactory.CreateBinder(binder, modelMetadataProvider, actionDescriptor);
@ -73,7 +78,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var binder = new ParameterBinder(
modelMetadataProvider,
TestModelBinderFactory.CreateDefault(),
Mock.Of<IModelValidatorProvider>());
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance);
// Act
var factory = PagePropertyBinderFactory.CreateBinder(binder, modelMetadataProvider, actionDescriptor);
@ -95,7 +101,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var binder = new ParameterBinder(
modelMetadataProvider,
TestModelBinderFactory.CreateDefault(),
Mock.Of<IModelValidatorProvider>());
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance);
// Act
var factory = PagePropertyBinderFactory.CreateBinder(binder, modelMetadataProvider, actionDescriptor);
@ -116,7 +123,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var binder = new ParameterBinder(
modelMetadataProvider,
TestModelBinderFactory.CreateDefault(),
Mock.Of<IModelValidatorProvider>());
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance);
// Act
var factory = PagePropertyBinderFactory.CreateBinder(binder, modelMetadataProvider, actionDescriptor);
@ -138,7 +146,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var binder = new ParameterBinder(
modelMetadataProvider,
TestModelBinderFactory.CreateDefault(),
Mock.Of<IModelValidatorProvider>());
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance);
// Act
var factory = PagePropertyBinderFactory.CreateBinder(binder, modelMetadataProvider, actionDescriptor);
@ -155,7 +164,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var actionDescriptor = new CompiledPageActionDescriptor
{
BoundProperties = new []
BoundProperties = new[]
{
new PageBoundPropertyDescriptor()
{
@ -192,10 +201,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var page = new PageWithProperty
{
PageContext = new PageContext()
{
HttpContext = new DefaultHttpContext(),
},
PageContext = GetPageContext(),
};
// Act
@ -253,10 +259,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var page = new PageWithProperty
{
PageContext = new PageContext()
{
HttpContext = new DefaultHttpContext(),
}
PageContext = GetPageContext()
};
var model = new PageModelWithProperty();
@ -304,10 +307,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var page = new PageWithProperty
{
PageContext = new PageContext()
{
HttpContext = new DefaultHttpContext(),
}
PageContext = GetPageContext()
};
var model = new PageModelWithDefaultValue();
@ -368,16 +368,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var page = new PageWithProperty
{
PageContext = new PageContext()
{
HttpContext = new DefaultHttpContext()
{
Request=
{
Method = method,
}
}
}
PageContext = GetPageContext(method)
};
var model = new PageModelWithSupportsGetProperty();
@ -434,10 +425,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
var page = new PageWithProperty
{
PageContext = new PageContext()
{
HttpContext = new DefaultHttpContext(),
}
PageContext = GetPageContext()
};
page.HttpContext.Request.Method = "Post";
@ -452,6 +440,27 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
Assert.Equal("value", model.Default);
}
private PageContext GetPageContext(string httpMethod = null)
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance);
var httpContext = new DefaultHttpContext()
{
RequestServices = services.BuildServiceProvider()
};
if (httpMethod != null)
{
httpContext.Request.Method = httpMethod;
}
return new PageContext()
{
HttpContext = httpContext
};
}
private class TestParameterBinder : ParameterBinder
{
private readonly IDictionary<string, object> _args;
@ -460,7 +469,8 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
: base(
TestModelMetadataProvider.CreateDefaultProvider(),
TestModelBinderFactory.CreateDefault(),
Mock.Of<IModelValidatorProvider>())
Mock.Of<IModelValidatorProvider>(),
NullLoggerFactory.Instance)
{
_args = args;
}

View File

@ -13,6 +13,7 @@
<PackageReference Include="Microsoft.AspNetCore.Html.Abstractions" Version="$(MicrosoftAspNetCoreHtmlAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Runtime" Version="$(MicrosoftAspNetCoreRazorRuntimePackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(MicrosoftAspNetCoreTestingPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(MicrosoftExtensionsDependencyInjectionPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Abstractions" Version="$(MicrosoftExtensionsFileProvidersAbstractionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsOptionsPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.WebEncoders" Version="$(MicrosoftExtensionsWebEncodersPackageVersion)" />

View File

@ -1,8 +1,12 @@
// 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;
using Microsoft.AspNetCore.Mvc.Internal;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
@ -36,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
public static TestModelBinderFactory CreateDefault(
IModelMetadataProvider metadataProvider,
IModelMetadataProvider metadataProvider,
params IModelBinderProvider[] providers)
{
if (metadataProvider == null)
@ -53,9 +57,16 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return new TestModelBinderFactory(metadataProvider, options);
}
protected TestModelBinderFactory(IModelMetadataProvider metadataProvider, IOptions<MvcOptions> options)
: base(metadataProvider, options)
protected TestModelBinderFactory(IModelMetadataProvider metadataProvider, IOptions<MvcOptions> options)
: base(metadataProvider, options, GetServices())
{
}
private static IServiceProvider GetServices()
{
var services = new ServiceCollection();
services.AddSingleton<ILoggerFactory, NullLoggerFactory>();
return services.BuildServiceProvider();
}
}
}