From 320507604a7045110ebf0b64f669cccddb6d9123 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 7 May 2015 14:27:52 -0700 Subject: [PATCH] Removing superfluous types and methods from Common. --- src/Microsoft.AspNet.JsonPatch/project.json | 2 - .../ModelBinding/ModelMetadata.cs | 26 +++- .../ModelBinding/ValueProviderResult.cs | 8 +- .../DefaultApiDescriptionProvider.cs | 3 +- .../PlatformHelper.cs | 20 ---- .../StringHelper.cs | 58 --------- .../TypeExtensions.cs | 113 ------------------ src/Microsoft.AspNet.Mvc.Common/TypeHelper.cs | 50 +++++--- .../BindAttribute.cs | 4 +- .../ControllerActionExecutor.cs | 2 +- .../ControllerActionInvoker.cs | 10 +- .../DefaultControllerActionArgumentBinder.cs | 2 +- .../Filters/FilterCollectionExtensions.cs | 3 +- .../Formatters/JsonContractResolver.cs | 3 +- .../Formatters/JsonPatchInputFormatter.cs | 6 +- .../ModelBinding/FormCollectionModelBinder.cs | 3 +- .../ModelBinding/GenericModelBinder.cs | 12 +- .../DataAnnotationsMetadataProvider.cs | 5 +- .../Metadata/DefaultModelMetadata.cs | 2 +- .../Metadata/DefaultModelMetadataProvider.cs | 3 +- .../ModelBinding/MutableObjectModelBinder.cs | 2 +- .../ModelBinding/TypeConverterModelBinder.cs | 2 +- .../ModelBinding/TypeMatchModelBinder.cs | 2 +- .../Validation/DefaultObjectValidator.cs | 5 +- .../DefaultTypeBasedExcludeFilter.cs | 3 +- .../DefaultTypeNameBasedExcludeFilter.cs | 3 +- .../Validation/SimpleTypesExcludeFilter.cs | 2 +- .../ParameterBinding/ModelBindingHelper.cs | 12 +- .../Rendering/Html/DefaultDisplayTemplates.cs | 2 +- .../Rendering/Html/DefaultEditorTemplates.cs | 2 +- .../Rendering/Internal/TemplateRenderer.cs | 15 ++- .../ViewDataDictionary.cs | 3 +- .../ViewEngineDescriptor.cs | 3 +- .../MvcRazorCodeParser.cs | 52 +++++++- .../project.json | 1 - .../Internal/SymbolsUtility.cs | 3 +- .../Internal/AttributeMatcher.cs | 3 +- .../SelectTagHelper.cs | 4 +- .../project.json | 1 - ...erConventionsApplicationModelConvention.cs | 10 +- .../OverloadActionConstraint.cs | 10 +- .../project.json | 2 +- .../EnumerableWrapperProvider.cs | 2 +- .../EnumerableWrapperProviderFactory.cs | 5 +- .../RequiredValidationHelper.cs | 4 +- src/Microsoft.AspNet.Mvc/project.json | 1 - .../StringHelperTest.cs | 97 --------------- ...ypeExtensionsTest.cs => TypeHelperTest.cs} | 8 +- .../ActionResults/ViewExecutorTest.cs | 3 +- .../MvcRazorParserTest.cs | 86 +++++++++++++ 50 files changed, 295 insertions(+), 388 deletions(-) delete mode 100644 src/Microsoft.AspNet.Mvc.Common/PlatformHelper.cs delete mode 100644 src/Microsoft.AspNet.Mvc.Common/StringHelper.cs delete mode 100644 src/Microsoft.AspNet.Mvc.Common/TypeExtensions.cs delete mode 100644 test/Microsoft.AspNet.Mvc.Common.Test/StringHelperTest.cs rename test/Microsoft.AspNet.Mvc.Common.Test/{TypeExtensionsTest.cs => TypeHelperTest.cs} (87%) diff --git a/src/Microsoft.AspNet.JsonPatch/project.json b/src/Microsoft.AspNet.JsonPatch/project.json index bda4d2c9dd..0fcc66aebd 100644 --- a/src/Microsoft.AspNet.JsonPatch/project.json +++ b/src/Microsoft.AspNet.JsonPatch/project.json @@ -2,7 +2,6 @@ "version": "1.0.0-*", "dependencies": { "Microsoft.AspNet.Http.Extensions": "1.0.0-*", - "Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" }, "Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" }, "Microsoft.Framework.PropertyHelper.Sources": { "version": "1.0.0-*", "type": "build" }, "Newtonsoft.Json": "6.0.6" @@ -12,7 +11,6 @@ "dnxcore50": { "dependencies": { "Microsoft.CSharp": "4.0.0-beta-*", - "System.Collections": "4.0.10-beta-*", "System.Collections.Concurrent": "4.0.10-beta-*", "System.ComponentModel.TypeConverter": "4.0.0-beta-*", "System.Globalization": "4.0.10-beta-*", diff --git a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelMetadata.cs b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelMetadata.cs index 020f16e1a1..e246d2d91c 100644 --- a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelMetadata.cs +++ b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelMetadata.cs @@ -2,7 +2,10 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; using Microsoft.AspNet.Mvc.ModelBinding.Metadata; using Microsoft.Framework.Internal; @@ -273,7 +276,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// Gets a collection of metadata items for validators. /// - public abstract IReadOnlyList ValidatorMetadata { get;} + public abstract IReadOnlyList ValidatorMetadata { get; } /// /// Gets a value indicating whether is a simple type. @@ -288,7 +291,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { if (_isComplexType == null) { - _isComplexType = !TypeHelper.HasStringConverter(ModelType); + _isComplexType = !TypeDescriptor.GetConverter(ModelType).CanConvertFrom(typeof(string)); } return _isComplexType.Value; @@ -300,7 +303,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// public bool IsNullableValueType { - get { return ModelType.IsNullableValueType(); } + get { return TypeHelper.IsNullableValueType(ModelType); } } /// @@ -308,11 +311,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// /// /// A collection type is defined as a which is assignable to - /// , and is not a . + /// , and is not a . /// public bool IsCollectionType { - get { return TypeHelper.IsCollectionType(ModelType); } + get + { + if (ModelType == typeof(string)) + { + // Even though string implements IEnumerable, we don't really think of it + // as a collection for the purposes of model binding. + return false; + } + + // We only need to look for IEnumerable, because IEnumerable extends it. + return typeof(IEnumerable).IsAssignableFrom(ModelType); + } } /// @@ -338,4 +352,4 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// public abstract Action PropertySetter { get; } } -} +} diff --git a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs index aee3b4bc07..762c9e817e 100644 --- a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs +++ b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ValueProviderResult.cs @@ -70,12 +70,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return UnwrapPossibleArrayType(cultureToUse, value, type); } - public static bool CanConvertFromString(Type destinationType) - { - return TypeHelper.IsSimpleType(UnwrapNullableType(destinationType)) || - TypeHelper.HasStringConverter(destinationType); - } - private object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType) { // array conversion results in four cases, as below @@ -148,7 +142,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding if (!(canConvertFrom || converter.CanConvertTo(destinationType))) { // EnumConverter cannot convert integer, so we verify manually - if (destinationType.IsEnum() && (value is int)) + if (destinationType.GetTypeInfo().IsEnum && (value is int)) { return Enum.ToObject(destinationType, (int)value); } diff --git a/src/Microsoft.AspNet.Mvc.ApiExplorer/DefaultApiDescriptionProvider.cs b/src/Microsoft.AspNet.Mvc.ApiExplorer/DefaultApiDescriptionProvider.cs index f0ee860ef9..20fd1f22b6 100644 --- a/src/Microsoft.AspNet.Mvc.ApiExplorer/DefaultApiDescriptionProvider.cs +++ b/src/Microsoft.AspNet.Mvc.ApiExplorer/DefaultApiDescriptionProvider.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Routing; @@ -361,7 +362,7 @@ namespace Microsoft.AspNet.Mvc.ApiExplorer // If the method is declared to return IActionResult or a derived class, that information // isn't valuable to the formatter. - if (typeof(IActionResult).IsAssignableFrom(unwrappedType)) + if (typeof(IActionResult).GetTypeInfo().IsAssignableFrom(unwrappedType.GetTypeInfo())) { return null; } diff --git a/src/Microsoft.AspNet.Mvc.Common/PlatformHelper.cs b/src/Microsoft.AspNet.Mvc.Common/PlatformHelper.cs deleted file mode 100644 index 9393f16972..0000000000 --- a/src/Microsoft.AspNet.Mvc.Common/PlatformHelper.cs +++ /dev/null @@ -1,20 +0,0 @@ -// 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.AspNet.Mvc -{ - internal static class PlatformHelper - { - private static readonly Lazy _isMono = new Lazy(() => Type.GetType("Mono.Runtime") != null); - - public static bool IsMono - { - get - { - return _isMono.Value; - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Common/StringHelper.cs b/src/Microsoft.AspNet.Mvc.Common/StringHelper.cs deleted file mode 100644 index b6c8c22d89..0000000000 --- a/src/Microsoft.AspNet.Mvc.Common/StringHelper.cs +++ /dev/null @@ -1,58 +0,0 @@ -// 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.Linq; - -namespace Microsoft.AspNet.Mvc -{ - internal static class StringHelper - { - public static string TrimSpacesAndChars(string value, params char[] chars) - { - if (string.IsNullOrWhiteSpace(value)) - { - return string.Empty; - } - - if (chars == null || chars.Length == 0) - { - return value.Trim(); - } - - var firstIndex = 0; - for (; firstIndex < value.Length; firstIndex++) - { - var currentChar = value[firstIndex]; - if (!char.IsWhiteSpace(currentChar) && !chars.Any(compareChar => compareChar == currentChar)) - { - break; - } - } - - // We trimmed all the way - if (firstIndex == value.Length) - { - return string.Empty; - } - - var lastIndex = value.Length - 1; - for (; lastIndex > firstIndex; lastIndex--) - { - var currentChar = value[lastIndex]; - if (!char.IsWhiteSpace(currentChar) && !chars.Any(compareChar => compareChar == currentChar)) - { - break; - } - } - - if (firstIndex == 0 && lastIndex == value.Length - 1) - { - return value; - } - else - { - return value.Substring(firstIndex, lastIndex - firstIndex + 1); - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Common/TypeExtensions.cs b/src/Microsoft.AspNet.Mvc.Common/TypeExtensions.cs deleted file mode 100644 index 2aada1e1fd..0000000000 --- a/src/Microsoft.AspNet.Mvc.Common/TypeExtensions.cs +++ /dev/null @@ -1,113 +0,0 @@ -// 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 System.Linq; -using System.Reflection; -using Microsoft.Framework.Internal; - -namespace Microsoft.AspNet.Mvc -{ - internal static class TypeExtensions - { - // NOTE: Do not make #105 worse! Do not add new extension methods that conflict w/ .NET 4.5 methods. The - // exising NETFX_CORE || DNXCORE50 methods should go away (soon). -#if NETFX_CORE || DNXCORE50 - private static bool EqualTo([NotNull] this Type[] t1, [NotNull] Type[] t2) - { - if (t1.Length != t2.Length) - { - return false; - } - - for (var idx = 0; idx < t1.Length; ++idx) - { - if (t1[idx] != t2[idx]) - { - return false; - } - } - - return true; - } - - public static ConstructorInfo GetConstructor([NotNull] this Type type, Type[] types) - { - return type.GetTypeInfo().DeclaredConstructors - .Where(c => c.IsPublic) - .SingleOrDefault(c => c.GetParameters() - .Select(p => p.ParameterType).ToArray().EqualTo(types)); - } -#endif - - public static Type BaseType([NotNull] this Type type) - { - return type.GetTypeInfo().BaseType; - } - -#if NETFX_CORE || DNXCORE50 - public static Type[] GetGenericArguments([NotNull] this Type type) - { - return type.GetTypeInfo().GenericTypeArguments; - } - - public static Type[] GetInterfaces([NotNull] this Type type) - { - return type.GetTypeInfo().ImplementedInterfaces.ToArray(); - } - - public static bool IsAssignableFrom([NotNull] this Type type, [NotNull] Type c) - { - return type.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo()); - } -#endif - - public static bool IsEnum([NotNull] this Type type) - { - return type.GetTypeInfo().IsEnum; - } - - public static bool IsGenericType([NotNull] this Type type) - { - return type.GetTypeInfo().IsGenericType; - } - - public static bool IsInterface([NotNull] this Type type) - { - return type.GetTypeInfo().IsInterface; - } - - public static bool IsValueType([NotNull] this Type type) - { - return type.GetTypeInfo().IsValueType; - } - - public static bool IsCompatibleWith([NotNull] this Type type, object value) - { - return (value == null && AllowsNullValue(type)) || - (value != null && type.GetTypeInfo().IsAssignableFrom(value.GetType().GetTypeInfo())); - } - - public static bool IsNullableValueType([NotNull] this Type type) - { - return Nullable.GetUnderlyingType(type) != null; - } - - public static bool AllowsNullValue([NotNull] this Type type) - { - return (!type.GetTypeInfo().IsValueType || IsNullableValueType(type)); - } - - public static Type[] GetTypeArgumentsIfMatch([NotNull] Type closedType, Type matchingOpenType) - { - var closedTypeInfo = closedType.GetTypeInfo(); - if (!closedTypeInfo.IsGenericType) - { - return null; - } - - var openType = closedType.GetGenericTypeDefinition(); - return (matchingOpenType == openType) ? closedTypeInfo.GenericTypeArguments : null; - } - } -} diff --git a/src/Microsoft.AspNet.Mvc.Common/TypeHelper.cs b/src/Microsoft.AspNet.Mvc.Common/TypeHelper.cs index 35b27d000c..9e598872d1 100644 --- a/src/Microsoft.AspNet.Mvc.Common/TypeHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Common/TypeHelper.cs @@ -2,9 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; using System.Reflection; using System.Threading.Tasks; using Microsoft.Framework.Internal; @@ -15,12 +15,13 @@ namespace Microsoft.AspNet.Mvc { private static readonly Type TaskGenericType = typeof(Task<>); - public static Type GetTaskInnerTypeOrNull([NotNull]Type type) + public static Type GetTaskInnerTypeOrNull([NotNull] Type type) { - if (type.GetTypeInfo().IsGenericType && !type.GetTypeInfo().IsGenericTypeDefinition) + var typeInfo = type.GetTypeInfo(); + if (typeInfo.IsGenericType && !typeInfo.IsGenericTypeDefinition) { - var genericTypeDefinition = type.GetGenericTypeDefinition(); - var genericArguments = type.GetGenericArguments(); + var genericTypeDefinition = typeInfo.GetGenericTypeDefinition(); + var genericArguments = typeInfo.GenericTypeArguments; if (genericArguments.Length == 1 && TaskGenericType == genericTypeDefinition) { // Only Return if there is a single argument. @@ -75,22 +76,39 @@ namespace Microsoft.AspNet.Mvc type.Equals(typeof(Uri)); } - public static bool HasStringConverter(Type type) + public static bool IsCompatibleWith([NotNull] Type type, object value) { - return TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string)); + return (value == null && AllowsNullValue(type)) || + (value != null && type.GetTypeInfo().IsAssignableFrom(value.GetType().GetTypeInfo())); } - public static bool IsCollectionType(Type type) + public static bool IsNullableValueType([NotNull] Type type) { - if (type == typeof(string)) - { - // Even though string implements IEnumerable, we don't really think of it - // as a collection for the purposes of model binding. - return false; - } + return Nullable.GetUnderlyingType(type) != null; + } - // We only need to look for IEnumerable, because IEnumerable extends it. - return typeof(IEnumerable).IsAssignableFrom(type); + public static bool AllowsNullValue([NotNull] Type type) + { + return !type.GetTypeInfo().IsValueType || IsNullableValueType(type); + } + + public static TypeInfo ExtractGenericInterface([NotNull] Type queryType, Type interfaceType) + { + Func matchesInterface = + typeInfo => typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == interfaceType; + var queryTypeInfo = queryType.GetTypeInfo(); + + if (matchesInterface(queryTypeInfo)) + { + return queryTypeInfo; + } + else + { + return queryTypeInfo + .ImplementedInterfaces + .Select(type => type.GetTypeInfo()) + .FirstOrDefault(matchesInterface); + } } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/BindAttribute.cs b/src/Microsoft.AspNet.Mvc.Core/BindAttribute.cs index 6e365f15a4..782da1164b 100644 --- a/src/Microsoft.AspNet.Mvc.Core/BindAttribute.cs +++ b/src/Microsoft.AspNet.Mvc.Core/BindAttribute.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using System.Reflection; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.Framework.DependencyInjection; @@ -40,7 +41,8 @@ namespace Microsoft.AspNet.Mvc /// public BindAttribute([NotNull] Type predicateProviderType) { - if (!typeof(IPropertyBindingPredicateProvider).IsAssignableFrom(predicateProviderType)) + if (!typeof(IPropertyBindingPredicateProvider).GetTypeInfo() + .IsAssignableFrom(predicateProviderType.GetTypeInfo())) { var message = Resources.FormatPropertyBindingPredicateProvider_WrongType( predicateProviderType.FullName, diff --git a/src/Microsoft.AspNet.Mvc.Core/ControllerActionExecutor.cs b/src/Microsoft.AspNet.Mvc.Core/ControllerActionExecutor.cs index 91bd8a3c39..a2f883098e 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ControllerActionExecutor.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ControllerActionExecutor.cs @@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Mvc } else { - value = parameterInfo.ParameterType.IsValueType() + value = parameterInfo.ParameterType.GetTypeInfo().IsValueType ? Activator.CreateInstance(parameterInfo.ParameterType) : null; } diff --git a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs index 10a04a5a9d..4a81008d94 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding.Validation; @@ -39,8 +40,8 @@ namespace Microsoft.AspNet.Mvc.Core filterProviders, inputFormatters, outputFormatters, - modelBinders, - modelValidatorProviders, + modelBinders, + modelValidatorProviders, valueProviderFactories, actionBindingContextAccessor, loggerFactory, @@ -88,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.Core } protected override Task> BindActionArgumentsAsync( - ActionContext context, + ActionContext context, ActionBindingContext bindingContext) { return _argumentBinder.BindActionArgumentsAsync(context, bindingContext, Instance); @@ -116,7 +117,8 @@ namespace Microsoft.AspNet.Mvc.Core // Unwrap potential Task types. var actualReturnType = TypeHelper.GetTaskInnerTypeOrNull(declaredReturnType) ?? declaredReturnType; - if (actionReturnValue == null && typeof(IActionResult).IsAssignableFrom(actualReturnType)) + if (actionReturnValue == null && + typeof(IActionResult).GetTypeInfo().IsAssignableFrom(actualReturnType.GetTypeInfo())) { throw new InvalidOperationException( Resources.FormatActionResult_ActionReturnValueCannotBeNull(actualReturnType)); diff --git a/src/Microsoft.AspNet.Mvc.Core/DefaultControllerActionArgumentBinder.cs b/src/Microsoft.AspNet.Mvc.Core/DefaultControllerActionArgumentBinder.cs index 0244155c3b..7353482bf2 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DefaultControllerActionArgumentBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DefaultControllerActionArgumentBinder.cs @@ -128,7 +128,7 @@ namespace Microsoft.AspNet.Mvc if (propertyHelper.Property.CanWrite && propertyHelper.Property.SetMethod?.IsPublic == true) { // Handle settable property. Do not set the property if the type is a non-nullable type. - if (source != null || propertyType.AllowsNullValue()) + if (source != null || TypeHelper.AllowsNullValue(propertyType)) { propertyHelper.SetValue(controller, source); } diff --git a/src/Microsoft.AspNet.Mvc.Core/Filters/FilterCollectionExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/Filters/FilterCollectionExtensions.cs index 102dc9e3b0..90f37e088a 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Filters/FilterCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Filters/FilterCollectionExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Reflection; using Microsoft.AspNet.Mvc.Core; using Microsoft.Framework.Internal; @@ -94,7 +95,7 @@ namespace Microsoft.AspNet.Mvc [NotNull] Type filterType, int order) { - if (!typeof(IFilter).IsAssignableFrom(filterType)) + if (!typeof(IFilter).GetTypeInfo().IsAssignableFrom(filterType.GetTypeInfo())) { var message = Resources.FormatTypeMustDeriveFromType(filterType.FullName, typeof(IFilter).FullName); throw new ArgumentException(message, nameof(filterType)); diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonContractResolver.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonContractResolver.cs index a2f1126303..d46c85f265 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonContractResolver.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonContractResolver.cs @@ -1,6 +1,7 @@ // 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 System.ComponentModel.DataAnnotations; using System.Reflection; using Newtonsoft.Json; @@ -30,7 +31,7 @@ namespace Microsoft.AspNet.Mvc // With the following settings here, if a value is not present on the wire for value types // like primitive, struct etc., Json.net's serializer would throw exception which we catch // and add it to model state. - if (propertyType.IsValueType() && !propertyType.IsNullableValueType()) + if (propertyType.GetTypeInfo().IsValueType && !TypeHelper.IsNullableValueType(propertyType)) { property.Required = Required.AllowNull; } diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonPatchInputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonPatchInputFormatter.cs index 33b3925306..2c5ccdf7ce 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonPatchInputFormatter.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/JsonPatchInputFormatter.cs @@ -1,6 +1,7 @@ // 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.Reflection; using System.Threading.Tasks; using Microsoft.AspNet.JsonPatch; using Microsoft.Framework.Internal; @@ -33,8 +34,9 @@ namespace Microsoft.AspNet.Mvc /// public override bool CanRead(InputFormatterContext context) { - if (!typeof(IJsonPatchDocument).IsAssignableFrom(context.ModelType) || - !context.ModelType.IsGenericType()) + var modelTypeInfo = context.ModelType.GetTypeInfo(); + if (!typeof(IJsonPatchDocument).GetTypeInfo().IsAssignableFrom(modelTypeInfo) || + !modelTypeInfo.IsGenericType) { return false; } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormCollectionModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormCollectionModelBinder.cs index 3025f69514..cdc5731e29 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormCollectionModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/FormCollectionModelBinder.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Internal; @@ -29,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding if (request.HasFormContentType) { var form = await request.ReadFormAsync(); - if (bindingContext.ModelType.IsAssignableFrom(form.GetType())) + if (bindingContext.ModelType.GetTypeInfo().IsAssignableFrom(form.GetType().GetTypeInfo())) { model = form; } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/GenericModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/GenericModelBinder.cs index 41ab67da5b..6791ee2988 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/GenericModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/GenericModelBinder.cs @@ -69,10 +69,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding private static Type GetKeyValuePairBinder(Type modelType) { - return ModelBindingHelper.GetPossibleBinderInstanceType( - closedModelType: modelType, - openModelType: typeof(KeyValuePair<,>), - openBinderType: typeof(KeyValuePairModelBinder<,>)); + var modelTypeInfo = modelType.GetTypeInfo(); + if (modelTypeInfo.IsGenericType && + modelTypeInfo.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) + { + return typeof(KeyValuePairModelBinder<,>).MakeGenericType(modelTypeInfo.GenericTypeArguments); + } + + return null; } /// diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DataAnnotationsMetadataProvider.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DataAnnotationsMetadataProvider.cs index dd6b54f64c..15588722a6 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DataAnnotationsMetadataProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DataAnnotationsMetadataProvider.cs @@ -94,13 +94,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata // IsEnum et cetera var underlyingType = Nullable.GetUnderlyingType(context.Key.ModelType) ?? context.Key.ModelType; - if (underlyingType.IsEnum()) + var underlyingTypeInfo = underlyingType.GetTypeInfo(); + + if (underlyingTypeInfo.IsEnum) { // IsEnum displayMetadata.IsEnum = true; // IsFlagsEnum - var underlyingTypeInfo = underlyingType.GetTypeInfo(); displayMetadata.IsFlagsEnum = underlyingTypeInfo.GetCustomAttribute(inherit: false) != null; diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs index b9b7987d2a..85cd371b8a 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs @@ -343,7 +343,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata } else { - _isRequired = !ModelType.AllowsNullValue(); + _isRequired = !TypeHelper.AllowsNullValue(ModelType); } } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs index 6eb3b56ca8..2ec19ee739 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadataProvider.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Reflection; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata @@ -126,7 +127,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata if (propertyHelper.Property.CanWrite && propertyHelper.Property.SetMethod?.IsPublic == true && - !key.ModelType.IsValueType()) + !key.ModelType.GetTypeInfo().IsValueType) { propertyEntry.PropertySetter = propertyHelper.ValueSetter; } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs index c0b7ca9bfb..0e46b65960 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/MutableObjectModelBinder.cs @@ -511,7 +511,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return; } - if (value != null || property.PropertyType.AllowsNullValue()) + if (value != null || TypeHelper.AllowsNullValue(property.PropertyType)) { try { diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/TypeConverterModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/TypeConverterModelBinder.cs index 8aa5283ecb..f548c06c53 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/TypeConverterModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/TypeConverterModelBinder.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { ModelBindingHelper.ValidateBindingContext(bindingContext); - if (!TypeHelper.HasStringConverter(bindingContext.ModelType)) + if (bindingContext.ModelMetadata.IsComplexType) { // this type cannot be converted return null; diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/TypeMatchModelBinder.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/TypeMatchModelBinder.cs index 16c8b35c5a..ea1c90d587 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/TypeMatchModelBinder.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/TypeMatchModelBinder.cs @@ -32,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return null; // the value doesn't exist } - if (!context.ModelType.IsCompatibleWith(valueProviderResult.RawValue)) + if (!TypeHelper.IsCompatibleWith(context.ModelType, valueProviderResult.RawValue)) { return null; // value is of incompatible type } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultObjectValidator.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultObjectValidator.cs index 0c04131c28..0aa43cb445 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultObjectValidator.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultObjectValidator.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection; using System.Runtime.CompilerServices; using Microsoft.Framework.Internal; @@ -313,7 +314,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation private static Type GetElementType(Type type) { - Debug.Assert(typeof(IEnumerable).IsAssignableFrom(type)); + Debug.Assert(typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())); if (type.IsArray) { return type.GetElementType(); @@ -321,7 +322,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation foreach (var implementedInterface in type.GetInterfaces()) { - if (implementedInterface.IsGenericType() && + if (implementedInterface.GetTypeInfo().IsGenericType && implementedInterface.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { return implementedInterface.GetGenericArguments()[0]; diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultTypeBasedExcludeFilter.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultTypeBasedExcludeFilter.cs index 02d44035b0..e77dffe58d 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultTypeBasedExcludeFilter.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultTypeBasedExcludeFilter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Reflection; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding.Validation @@ -29,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation /// public bool IsTypeExcluded([NotNull] Type propertyType) { - return ExcludedType.IsAssignableFrom(propertyType); + return ExcludedType.GetTypeInfo().IsAssignableFrom(propertyType.GetTypeInfo()); } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultTypeNameBasedExcludeFilter.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultTypeNameBasedExcludeFilter.cs index b39179ea45..a76c39d8de 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultTypeNameBasedExcludeFilter.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultTypeNameBasedExcludeFilter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Reflection; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding.Validation @@ -44,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation return true; } - return CheckIfTypeNameMatches(type.BaseType()); + return CheckIfTypeNameMatches(type.GetTypeInfo().BaseType); } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/SimpleTypesExcludeFilter.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/SimpleTypesExcludeFilter.cs index dd54c0e252..0561ab7616 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/SimpleTypesExcludeFilter.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/SimpleTypesExcludeFilter.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation { Type[] actualTypes; - if (type.IsGenericType() && + if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) { actualTypes = type.GenericTypeArguments; diff --git a/src/Microsoft.AspNet.Mvc.Core/ParameterBinding/ModelBindingHelper.cs b/src/Microsoft.AspNet.Mvc.Core/ParameterBinding/ModelBindingHelper.cs index 30e2f98c67..057f17c1c9 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ParameterBinding/ModelBindingHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ParameterBinding/ModelBindingHelper.cs @@ -413,7 +413,7 @@ namespace Microsoft.AspNet.Mvc private static Type GetElementType(Type type) { - Debug.Assert(typeof(IEnumerable).IsAssignableFrom(type)); + Debug.Assert(typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())); if (type.IsArray) { return type.GetElementType(); @@ -421,7 +421,7 @@ namespace Microsoft.AspNet.Mvc foreach (var implementedInterface in type.GetInterfaces()) { - if (implementedInterface.IsGenericType() && + if (implementedInterface.GetTypeInfo().IsGenericType && implementedInterface.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { return implementedInterface.GetGenericArguments()[0]; @@ -473,14 +473,6 @@ namespace Microsoft.AspNet.Mvc return (model is TModel) ? (TModel)model : default(TModel); } - internal static Type GetPossibleBinderInstanceType(Type closedModelType, - Type openModelType, - Type openBinderType) - { - var typeArguments = TypeExtensions.GetTypeArgumentsIfMatch(closedModelType, openModelType); - return (typeArguments != null) ? openBinderType.MakeGenericType(typeArguments) : null; - } - internal static void ReplaceEmptyStringWithNull(ModelMetadata modelMetadata, ref object model) { if (model is string && diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs index b87be41910..c7fa4fba3c 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultDisplayTemplates.cs @@ -115,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.Rendering typeInCollection = genericEnumerableType.GenericTypeArguments[0]; } - var typeInCollectionIsNullableValueType = typeInCollection.IsNullableValueType(); + var typeInCollectionIsNullableValueType = TypeHelper.IsNullableValueType(typeInCollection); var oldPrefix = htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix; diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultEditorTemplates.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultEditorTemplates.cs index 36cb7cf370..2d16f6e71f 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultEditorTemplates.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/DefaultEditorTemplates.cs @@ -76,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.Rendering typeInCollection = genericEnumerableType.GenericTypeArguments[0]; } - var typeInCollectionIsNullableValueType = typeInCollection.IsNullableValueType(); + var typeInCollectionIsNullableValueType = TypeHelper.IsNullableValueType(typeInCollection); var oldPrefix = viewData.TemplateInfo.HtmlFieldPrefix; try diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Internal/TemplateRenderer.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Internal/TemplateRenderer.cs index c71a046a10..989a5858eb 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Internal/TemplateRenderer.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Internal/TemplateRenderer.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Reflection; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.ModelBinding; @@ -161,6 +162,8 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal { // Not returning type name here for IEnumerable since we will be returning // a more specific name, IEnumerableOfIFormFileName. + var fieldTypeInfo = fieldType.GetTypeInfo(); + if (typeof(IEnumerable) != fieldType) { yield return fieldType.Name; @@ -174,7 +177,7 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal else if (!modelMetadata.IsComplexType) { // IsEnum is false for the Enum class itself - if (fieldType.IsEnum()) + if (fieldTypeInfo.IsEnum) { // Same as fieldType.BaseType.Name in this case yield return "Enum"; @@ -187,12 +190,12 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal yield return "String"; yield break; } - else if (!fieldType.IsInterface()) + else if (!fieldTypeInfo.IsInterface) { var type = fieldType; while (true) { - type = type.BaseType(); + type = type.GetTypeInfo().BaseType; if (type == null || type == typeof(object)) { break; @@ -202,9 +205,9 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal } } - if (typeof(IEnumerable).IsAssignableFrom(fieldType)) + if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(fieldTypeInfo)) { - if (typeof(IEnumerable).IsAssignableFrom(fieldType)) + if (typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(fieldTypeInfo)) { yield return IEnumerableOfIFormFileName; @@ -217,7 +220,7 @@ namespace Microsoft.AspNet.Mvc.Rendering.Internal yield return "Collection"; } - else if (typeof(IFormFile) != fieldType && typeof(IFormFile).IsAssignableFrom(fieldType)) + else if (typeof(IFormFile) != fieldType && typeof(IFormFile).GetTypeInfo().IsAssignableFrom(fieldTypeInfo)) { yield return nameof(IFormFile); } diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewDataDictionary.cs b/src/Microsoft.AspNet.Mvc.Core/ViewDataDictionary.cs index 39f7c4d681..be20b82eba 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ViewDataDictionary.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ViewDataDictionary.cs @@ -5,6 +5,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Globalization; +using System.Reflection; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering.Expressions; @@ -372,7 +373,7 @@ namespace Microsoft.AspNet.Mvc { // IsCompatibleObject verifies if the value is either an instance of _declaredModelType or (if value is // null) that _declaredModelType is a nullable type. - var castWillSucceed = _declaredModelType.IsCompatibleWith(value); + var castWillSucceed = TypeHelper.IsCompatibleWith(_declaredModelType, value); if (!castWillSucceed) { string message; diff --git a/src/Microsoft.AspNet.Mvc.Core/ViewEngineDescriptor.cs b/src/Microsoft.AspNet.Mvc.Core/ViewEngineDescriptor.cs index 5e89ff386f..951d77d408 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ViewEngineDescriptor.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ViewEngineDescriptor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Reflection; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.Framework.Internal; @@ -19,7 +20,7 @@ namespace Microsoft.AspNet.Mvc /// The type that the descriptor represents. public ViewEngineDescriptor([NotNull] Type type) { - if (!typeof(IViewEngine).IsAssignableFrom(type)) + if (!typeof(IViewEngine).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())) { var message = Resources.FormatTypeMustDeriveFromType(type.FullName, typeof(IViewEngine).FullName); throw new ArgumentException(message, nameof(type)); diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorCodeParser.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorCodeParser.cs index 38cff3f1b4..0dd32b2596 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorCodeParser.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorCodeParser.cs @@ -1,6 +1,7 @@ // 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.Linq; using Microsoft.AspNet.Mvc.Razor.Host; using Microsoft.AspNet.Razor; using Microsoft.AspNet.Razor.Generator; @@ -128,7 +129,7 @@ namespace Microsoft.AspNet.Mvc.Razor .Substring(typeName.Length); // ';' is optional - propertyName = StringHelper.TrimSpacesAndChars(propertyName, ';'); + propertyName = TrimSpacesAndChars(propertyName, ';'); Span.CodeGenerator = new InjectParameterGenerator(typeName.Trim(), propertyName); // Output the span and finish the block @@ -140,5 +141,54 @@ namespace Microsoft.AspNet.Mvc.Razor { return new ModelCodeGenerator(_baseType, model); } + + // Internal for unit testing + internal static string TrimSpacesAndChars(string value, params char[] chars) + { + if (string.IsNullOrWhiteSpace(value)) + { + return string.Empty; + } + + if (chars == null || chars.Length == 0) + { + return value.Trim(); + } + + var firstIndex = 0; + for (; firstIndex < value.Length; firstIndex++) + { + var currentChar = value[firstIndex]; + if (!char.IsWhiteSpace(currentChar) && !chars.Any(compareChar => compareChar == currentChar)) + { + break; + } + } + + // We trimmed all the way + if (firstIndex == value.Length) + { + return string.Empty; + } + + var lastIndex = value.Length - 1; + for (; lastIndex > firstIndex; lastIndex--) + { + var currentChar = value[lastIndex]; + if (!char.IsWhiteSpace(currentChar) && !chars.Any(compareChar => compareChar == currentChar)) + { + break; + } + } + + if (firstIndex == 0 && lastIndex == value.Length - 1) + { + return value; + } + else + { + return value.Substring(firstIndex, lastIndex - firstIndex + 1); + } + } } } diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/project.json b/src/Microsoft.AspNet.Mvc.Razor.Host/project.json index b380c407bf..75d58a17eb 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/project.json +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/project.json @@ -6,7 +6,6 @@ }, "dependencies": { "Microsoft.AspNet.FileProviders.Physical": "1.0.0-*", - "Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" }, "Microsoft.AspNet.Razor.Runtime": "4.0.0-*", "Microsoft.Framework.Caching.Memory": "1.0.0-*", "Microsoft.Framework.PropertyHelper.Sources": { "version": "1.0.0-*", "type": "build" }, diff --git a/src/Microsoft.AspNet.Mvc.Razor/Internal/SymbolsUtility.cs b/src/Microsoft.AspNet.Mvc.Razor/Internal/SymbolsUtility.cs index 0d7d546885..12980fb1da 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Internal/SymbolsUtility.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Internal/SymbolsUtility.cs @@ -12,6 +12,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Internal public class SymbolsUtility { private const string SymWriterGuid = "0AE2DEB0-F901-478b-BB9F-881EE8066788"; + private static readonly Lazy _isMono = new Lazy(() => Type.GetType("Mono.Runtime") != null); /// /// Determines if the current platform supports symbols (pdb) generation. @@ -19,7 +20,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Internal /// true if pdb generation is supported; false otherwise. public static bool SupportsSymbolsGeneration() { - if (PlatformHelper.IsMono) + if (_isMono.Value) { return false; } diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs index be349c0c9b..7e354456a3 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/Internal/AttributeMatcher.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Microsoft.Framework.Internal; @@ -88,7 +89,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal { if (!context.AllAttributes.ContainsName(attribute) || context.AllAttributes[attribute] == null || - (typeof(string).IsAssignableFrom(context.AllAttributes[attribute].Value.GetType()) && + (context.AllAttributes[attribute].Value is string && string.IsNullOrWhiteSpace(context.AllAttributes[attribute].Value as string))) { // Missing attribute! diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/SelectTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/SelectTagHelper.cs index 0764f8bb15..d96a4dd040 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/SelectTagHelper.cs +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/SelectTagHelper.cs @@ -5,6 +5,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Reflection; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Razor.Runtime.TagHelpers; @@ -74,7 +75,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers // "SelectExpressionNotEnumerable" InvalidOperationException during generation. // Metadata.IsCollectionType() is similar but does not take runtime type into account. var realModelType = For.ModelExplorer.ModelType; - var allowMultiple = typeof(string) != realModelType && typeof(IEnumerable).IsAssignableFrom(realModelType); + var allowMultiple = typeof(string) != realModelType && + typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(realModelType.GetTypeInfo()); // Ensure GenerateSelect() _never_ looks anything up in ViewData. var items = Items ?? Enumerable.Empty(); diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/project.json b/src/Microsoft.AspNet.Mvc.TagHelpers/project.json index 021555d3f5..666e3c66f3 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/project.json +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/project.json @@ -5,7 +5,6 @@ "warningsAsErrors": true }, "dependencies": { - "Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" }, "Microsoft.AspNet.Mvc.Razor": "6.0.0-*", "Microsoft.Framework.Caching.Memory": "1.0.0-*", "Microsoft.Framework.FileSystemGlobbing": "1.0.0-*", diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Conventions/WebApiParameterConventionsApplicationModelConvention.cs b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Conventions/WebApiParameterConventionsApplicationModelConvention.cs index 1d7f473300..d8131722d3 100644 --- a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Conventions/WebApiParameterConventionsApplicationModelConvention.cs +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/Conventions/WebApiParameterConventionsApplicationModelConvention.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Web.Http; using Microsoft.AspNet.Mvc.ApplicationModels; @@ -27,7 +28,7 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim { // This has a binding behavior configured, just leave it alone. } - else if (ValueProviderResult.CanConvertFromString(parameter.ParameterInfo.ParameterType)) + else if (CanConvertFromString(parameter.ParameterInfo.ParameterType)) { // Simple types are by-default from the URI. parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo(); @@ -60,5 +61,12 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim { return controller.Attributes.OfType().Any(); } + + private static bool CanConvertFromString(Type destinationType) + { + destinationType = Nullable.GetUnderlyingType(destinationType) ?? destinationType; + return TypeHelper.IsSimpleType(destinationType) || + TypeDescriptor.GetConverter(destinationType).CanConvertFrom(typeof(string)); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/OverloadActionConstraint.cs b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/OverloadActionConstraint.cs index 8d7bcdb433..c92e65d3ef 100644 --- a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/OverloadActionConstraint.cs +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/OverloadActionConstraint.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Net.Http.Formatting; using Microsoft.AspNet.Mvc.ModelBinding; @@ -101,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim if ((source.CanAcceptDataFrom(BindingSource.Path) || source.CanAcceptDataFrom(BindingSource.Query)) && - ValueProviderResult.CanConvertFromString(parameter.ParameterType)) + CanConvertFromString(parameter.ParameterType)) { if (optionalParameters != null) { @@ -155,6 +156,13 @@ namespace Microsoft.AspNet.Mvc.WebApiCompatShim return keys; } + private static bool CanConvertFromString(Type destinationType) + { + destinationType = Nullable.GetUnderlyingType(destinationType) ?? destinationType; + return TypeHelper.IsSimpleType(destinationType) || + TypeDescriptor.GetConverter(destinationType).CanConvertFrom(typeof(string)); + } + private class OverloadedParameter { public ParameterDescriptor ParameterDescriptor { get; set; } diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/project.json b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/project.json index 8ab7774925..8b640768fd 100644 --- a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/project.json +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/project.json @@ -5,7 +5,7 @@ "warningsAsErrors": false }, "dependencies": { - "Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" }, + "Microsoft.AspNet.Mvc.Common": { "type": "build", "version": "6.0.0-*" }, "Microsoft.AspNet.Mvc.Core": "6.0.0-*", "Microsoft.AspNet.WebApi.Client": "5.2.2", "Microsoft.Framework.PropertyHelper.Sources": { "version": "1.0.0-*", "type": "build" }, diff --git a/src/Microsoft.AspNet.Mvc.Xml/EnumerableWrapperProvider.cs b/src/Microsoft.AspNet.Mvc.Xml/EnumerableWrapperProvider.cs index 006e412132..8072be86a7 100644 --- a/src/Microsoft.AspNet.Mvc.Xml/EnumerableWrapperProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Xml/EnumerableWrapperProvider.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.Xml var enumerableOfT = ClosedGenericMatcher.ExtractGenericInterface( sourceEnumerableOfT, typeof(IEnumerable<>)); - if (!sourceEnumerableOfT.IsInterface() || enumerableOfT == null) + if (!sourceEnumerableOfT.GetTypeInfo().IsInterface || enumerableOfT == null) { throw new ArgumentException( Resources.FormatEnumerableWrapperProvider_InvalidSourceEnumerableOfT(typeof(IEnumerable<>).Name), diff --git a/src/Microsoft.AspNet.Mvc.Xml/EnumerableWrapperProviderFactory.cs b/src/Microsoft.AspNet.Mvc.Xml/EnumerableWrapperProviderFactory.cs index bc4471db58..1cf23bfe7c 100644 --- a/src/Microsoft.AspNet.Mvc.Xml/EnumerableWrapperProviderFactory.cs +++ b/src/Microsoft.AspNet.Mvc.Xml/EnumerableWrapperProviderFactory.cs @@ -1,8 +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; using System.Collections.Generic; +using System.Reflection; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.Xml @@ -37,10 +37,11 @@ namespace Microsoft.AspNet.Mvc.Xml { // Example: IEnumerable var declaredType = context.DeclaredType; + var declaredTypeInfo = declaredType.GetTypeInfo(); // We only wrap interfaces types(ex: IEnumerable, IQueryable, IList etc.) and not // concrete types like List, Collection which implement IEnumerable. - if (declaredType != null && declaredType.IsInterface() && declaredType.IsGenericType()) + if (declaredType != null && declaredTypeInfo.IsInterface && declaredTypeInfo.IsGenericType) { var enumerableOfT = ClosedGenericMatcher.ExtractGenericInterface( declaredType, diff --git a/src/Microsoft.AspNet.Mvc.Xml/RequiredValidationHelper.cs b/src/Microsoft.AspNet.Mvc.Xml/RequiredValidationHelper.cs index d03f8ed5f9..6d1ce483a5 100644 --- a/src/Microsoft.AspNet.Mvc.Xml/RequiredValidationHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Xml/RequiredValidationHelper.cs @@ -87,7 +87,7 @@ namespace Microsoft.AspNet.Mvc.Xml // is Dictionary<,> which implements IEnumerable>) as the model // type here would be KeyValuePair where Key and Value are public properties // which would also be probed for Required attribute validation. - if (modelType.IsGenericType()) + if (modelType.GetTypeInfo().IsGenericType) { var enumerableOfT = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(IEnumerable<>)); if (enumerableOfT != null) @@ -125,7 +125,7 @@ namespace Microsoft.AspNet.Mvc.Xml // Since DefaultObjectValidator can handle Required attribute validation for reference types, // we only consider value types here. - if (propertyType.IsValueType() && !propertyType.IsNullableValueType()) + if (propertyType.GetTypeInfo().IsValueType && !TypeHelper.IsNullableValueType(propertyType)) { var validationError = GetValidationError(propertyInfo); if (validationError != null) diff --git a/src/Microsoft.AspNet.Mvc/project.json b/src/Microsoft.AspNet.Mvc/project.json index a84b3257d3..3abcb432c1 100644 --- a/src/Microsoft.AspNet.Mvc/project.json +++ b/src/Microsoft.AspNet.Mvc/project.json @@ -8,7 +8,6 @@ "Microsoft.AspNet.Authorization": "1.0.0-*", "Microsoft.AspNet.Cors": "1.0.0-*", "Microsoft.AspNet.Mvc.ApiExplorer": "6.0.0-*", - "Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" }, "Microsoft.AspNet.Mvc.Razor": "6.0.0-*", "Microsoft.Framework.Caching.Memory": "1.0.0-*", "Microsoft.Framework.DependencyInjection": "1.0.0-*", diff --git a/test/Microsoft.AspNet.Mvc.Common.Test/StringHelperTest.cs b/test/Microsoft.AspNet.Mvc.Common.Test/StringHelperTest.cs deleted file mode 100644 index 7993229867..0000000000 --- a/test/Microsoft.AspNet.Mvc.Common.Test/StringHelperTest.cs +++ /dev/null @@ -1,97 +0,0 @@ -// 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 Xunit; - -namespace Microsoft.AspNet.Mvc -{ - public class StringHelperTest - { - public static TheoryData TrimSpacesAndCharsData - { - get - { - // input, trimCharacters, expectedOutput - return new TheoryData - { - { "abcd", new char[] { }, "abcd" }, - { " /.", new char[] { '/', '.' }, string.Empty }, - { string.Empty, new char[] { }, string.Empty }, - { " ", new char[] { }, string.Empty }, - { " ", new char[] { }, string.Empty }, - { " / ", new char[] { '/' }, string.Empty }, - { " \t ", new char[] { '/' }, string.Empty }, - { " ", new char[] { '/' }, string.Empty }, - { " ", new char[] { '/' }, string.Empty }, - { "/", new char[] { '/' }, string.Empty }, - { "//", new char[] { '/' }, string.Empty }, - { "// ", new char[] { '/' }, string.Empty }, - { "/ ", new char[] { '/' }, string.Empty }, - { " a ", new char[] { }, "a" }, - { " a", new char[] { }, "a" }, - { "a ", new char[] { }, "a" }, - { " a ", new char[] { }, "a" }, - { " a \n\r", new char[] { }, "a" }, - { "\t\r a ", new char[] { }, "a" }, - { "\ta ", new char[] { }, "a" }, - { " a a ", new char[] { }, "a a" }, - { " a ", new char[] { '/' }, "a" }, - { " a", new char[] { '/' }, "a" }, - { "a ", new char[] { '/' }, "a" }, - { " a ", new char[] { '/' }, "a" }, - { " a \n\r", new char[] { '/' }, "a" }, - { "\t\r a ", new char[] { '/' }, "a" }, - { "\ta ", new char[] { '/' }, "a" }, - { " a a ", new char[] { '/' }, "a a" }, - { " a ", new char[] { '/', ' ' }, "a" }, - { " a", new char[] { '/', ' ' }, "a" }, - { "a ", new char[] { '/', ' ' }, "a" }, - { " a ", new char[] { '/', ' ' }, "a" }, - { " a \n\r", new char[] { '/', ' ' }, "a" }, - { "\t\r a ", new char[] { '/', ' ' }, "a" }, - { "\ta ", new char[] { '/', ' ' }, "a" }, - { " a a ", new char[] { '/', ' ' }, "a a" }, - { "/ a ", new char[] { '/' }, "a" }, - { " / a", new char[] { '/' }, "a" }, - { "a / /", new char[] { '/' }, "a" }, - { " a // //", new char[] { '/' }, "a" }, - { " a \n\r//", new char[] { '/' }, "a" }, - { "////\t\r a ", new char[] { '/' }, "a" }, - { "\ta /", new char[] { '/' }, "a" }, - { " a/ a ", new char[] { '/' }, "a/ a" }, - { "/ a ", new char[] { '/', ' ' }, "a" }, - { " / a", new char[] { '/', ' ' }, "a" }, - { "a / /", new char[] { '/', ' ' }, "a" }, - { " a // //", new char[] { '/', ' ' }, "a" }, - { " a \n\r//", new char[] { '/', ' ' }, "a" }, - { "////\t\r a ", new char[] { '/', ' ' }, "a" }, - { "\ta /", new char[] { '/', ' ' }, "a" }, - { " a/ a ", new char[] { '/', ' ' }, "a/ a" }, - { " a /.", new char[] { '/', '.' }, "a" }, - { " a", new char[] { '/', '.' }, "a" }, - { "/. ./a ", new char[] { '/', '.' }, "a" }, - { " a ", new char[] { '/', '.' }, "a" }, - { " a \n\r", new char[] { '/', '.' }, "a" }, - { "\t\r a ", new char[] { '/', '.' }, "a" }, - { "\ta ", new char[] { '/', '.' }, "a" }, - { "///..a/./a /. ./....", new char[] { '/', '.' }, "a/./a" }, - }; - } - } - - [Theory] - [MemberData(nameof(TrimSpacesAndCharsData))] - public void TrimSpacesAndChars_GeneratesExpectedOutput( - string input, - char[] trimCharacters, - string expectedOutput) - { - // Arrange & Act - var output = StringHelper.TrimSpacesAndChars(input, trimCharacters); - - // Assert - Assert.Equal(expectedOutput, output, StringComparer.Ordinal); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Common.Test/TypeExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.Common.Test/TypeHelperTest.cs similarity index 87% rename from test/Microsoft.AspNet.Mvc.Common.Test/TypeExtensionsTest.cs rename to test/Microsoft.AspNet.Mvc.Common.Test/TypeHelperTest.cs index 11e781f7ad..38dca7955a 100644 --- a/test/Microsoft.AspNet.Mvc.Common.Test/TypeExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.Common.Test/TypeHelperTest.cs @@ -7,7 +7,7 @@ using Xunit; namespace Microsoft.AspNet.Mvc { - public class TypeExtensionsTest + public class TypeHelperTests { [Theory] [InlineData(typeof(decimal))] @@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Mvc public void IsCompatibleWithReturnsFalse_IfValueTypeIsNull(Type type) { // Act - bool result = TypeExtensions.IsCompatibleWith(type, value: null); + bool result = TypeHelper.IsCompatibleWith(type, value: null); // Assert Assert.False(result); @@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Mvc public void IsCompatibleWithReturnsFalse_IfValueIsMismatched(Type type) { // Act - bool result = TypeExtensions.IsCompatibleWith(type, value: "Hello world"); + bool result = TypeHelper.IsCompatibleWith(type, value: "Hello world"); // Assert Assert.False(result); @@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Mvc public void IsCompatibleWithReturnsTrue_IfValueIsAssignable(Type type, object value) { // Act - bool result = TypeExtensions.IsCompatibleWith(type, value); + bool result = TypeHelper.IsCompatibleWith(type, value); // Assert Assert.True(result); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ViewExecutorTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ViewExecutorTest.cs index bb84925dc3..746ec2e992 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ViewExecutorTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ActionResults/ViewExecutorTest.cs @@ -9,6 +9,7 @@ using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Routing; +using Microsoft.AspNet.Testing; using Microsoft.Net.Http.Headers; using Moq; using Xunit; @@ -90,7 +91,7 @@ namespace Microsoft.AspNet.Mvc { yield return new object[] { 30, 0 }; - if (PlatformHelper.IsMono) + if (TestPlatformHelper.IsMono) { // The StreamWriter in Mono buffers 2x the buffer size before flushing. yield return new object[] { ViewResultStreamWriterBufferSize * 2 + 30, ViewResultStreamWriterBufferSize }; diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorParserTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorParserTest.cs index a983451bd6..909584eec8 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorParserTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/MvcRazorParserTest.cs @@ -177,6 +177,92 @@ namespace Microsoft.AspNet.Mvc.Razor } } + public static TheoryData TrimSpacesAndCharsData + { + get + { + // input, trimCharacters, expectedOutput + return new TheoryData + { + { "abcd", new char[] { }, "abcd" }, + { " /.", new char[] { '/', '.' }, string.Empty }, + { string.Empty, new char[] { }, string.Empty }, + { " ", new char[] { }, string.Empty }, + { " ", new char[] { }, string.Empty }, + { " / ", new char[] { '/' }, string.Empty }, + { " \t ", new char[] { '/' }, string.Empty }, + { " ", new char[] { '/' }, string.Empty }, + { " ", new char[] { '/' }, string.Empty }, + { "/", new char[] { '/' }, string.Empty }, + { "//", new char[] { '/' }, string.Empty }, + { "// ", new char[] { '/' }, string.Empty }, + { "/ ", new char[] { '/' }, string.Empty }, + { " a ", new char[] { }, "a" }, + { " a", new char[] { }, "a" }, + { "a ", new char[] { }, "a" }, + { " a ", new char[] { }, "a" }, + { " a \n\r", new char[] { }, "a" }, + { "\t\r a ", new char[] { }, "a" }, + { "\ta ", new char[] { }, "a" }, + { " a a ", new char[] { }, "a a" }, + { " a ", new char[] { '/' }, "a" }, + { " a", new char[] { '/' }, "a" }, + { "a ", new char[] { '/' }, "a" }, + { " a ", new char[] { '/' }, "a" }, + { " a \n\r", new char[] { '/' }, "a" }, + { "\t\r a ", new char[] { '/' }, "a" }, + { "\ta ", new char[] { '/' }, "a" }, + { " a a ", new char[] { '/' }, "a a" }, + { " a ", new char[] { '/', ' ' }, "a" }, + { " a", new char[] { '/', ' ' }, "a" }, + { "a ", new char[] { '/', ' ' }, "a" }, + { " a ", new char[] { '/', ' ' }, "a" }, + { " a \n\r", new char[] { '/', ' ' }, "a" }, + { "\t\r a ", new char[] { '/', ' ' }, "a" }, + { "\ta ", new char[] { '/', ' ' }, "a" }, + { " a a ", new char[] { '/', ' ' }, "a a" }, + { "/ a ", new char[] { '/' }, "a" }, + { " / a", new char[] { '/' }, "a" }, + { "a / /", new char[] { '/' }, "a" }, + { " a // //", new char[] { '/' }, "a" }, + { " a \n\r//", new char[] { '/' }, "a" }, + { "////\t\r a ", new char[] { '/' }, "a" }, + { "\ta /", new char[] { '/' }, "a" }, + { " a/ a ", new char[] { '/' }, "a/ a" }, + { "/ a ", new char[] { '/', ' ' }, "a" }, + { " / a", new char[] { '/', ' ' }, "a" }, + { "a / /", new char[] { '/', ' ' }, "a" }, + { " a // //", new char[] { '/', ' ' }, "a" }, + { " a \n\r//", new char[] { '/', ' ' }, "a" }, + { "////\t\r a ", new char[] { '/', ' ' }, "a" }, + { "\ta /", new char[] { '/', ' ' }, "a" }, + { " a/ a ", new char[] { '/', ' ' }, "a/ a" }, + { " a /.", new char[] { '/', '.' }, "a" }, + { " a", new char[] { '/', '.' }, "a" }, + { "/. ./a ", new char[] { '/', '.' }, "a" }, + { " a ", new char[] { '/', '.' }, "a" }, + { " a \n\r", new char[] { '/', '.' }, "a" }, + { "\t\r a ", new char[] { '/', '.' }, "a" }, + { "\ta ", new char[] { '/', '.' }, "a" }, + { "///..a/./a /. ./....", new char[] { '/', '.' }, "a/./a" }, + }; + } + } + + [Theory] + [MemberData(nameof(TrimSpacesAndCharsData))] + public void TrimSpacesAndChars_GeneratesExpectedOutput( + string input, + char[] trimCharacters, + string expectedOutput) + { + // Arrange & Act + var output = MvcRazorCodeParser.TrimSpacesAndChars(input, trimCharacters); + + // Assert + Assert.Equal(expectedOutput, output, StringComparer.Ordinal); + } + private static CodeTree CreateCodeTree(params Chunk[] chunks) { return new CodeTree