コード例 #1
0
        /// <summary>
        /// Reads a <see cref="IAsyncEnumerable{T}"/> into an <see cref="ICollection{T}"/>.
        /// </summary>
        /// <param name="value">The <see cref="IAsyncEnumerable{T}"/> to read.</param>
        /// <returns>The <see cref="ICollection"/>.</returns>
        public Task <ICollection> ReadAsync(IAsyncEnumerable <object> value)
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            var type = value.GetType();

            if (!_asyncEnumerableConverters.TryGetValue(type, out var result))
            {
                var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(IAsyncEnumerable <>));
                Debug.Assert(enumerableType != null);

                var enumeratedObjectType = enumerableType.GetGenericArguments()[0];

                var converter = (ReaderFunc)Converter
                                .MakeGenericMethod(enumeratedObjectType)
                                .CreateDelegate(typeof(ReaderFunc), this);

                _asyncEnumerableConverters.TryAdd(type, converter);
                result = converter;
            }

            return(result(value));
        }
コード例 #2
0
        /// <summary>
        /// Initializes an instance of <see cref="EnumerableWrapperProvider"/>.
        /// </summary>
        /// <param name="sourceEnumerableOfT">Type of the original <see cref="IEnumerable{T}" />
        /// that is being wrapped.</param>
        /// <param name="elementWrapperProvider">The <see cref="IWrapperProvider"/> for the element type.
        /// Can be null.</param>
        public EnumerableWrapperProvider(
            Type sourceEnumerableOfT,
            IWrapperProvider elementWrapperProvider)
        {
            if (sourceEnumerableOfT == null)
            {
                throw new ArgumentNullException(nameof(sourceEnumerableOfT));
            }

            var enumerableOfT = ClosedGenericMatcher.ExtractGenericInterface(
                sourceEnumerableOfT,
                typeof(IEnumerable <>));

            if (!sourceEnumerableOfT.IsInterface || enumerableOfT == null)
            {
                throw new ArgumentException(
                          Resources.FormatEnumerableWrapperProvider_InvalidSourceEnumerableOfT(typeof(IEnumerable <>).Name),
                          nameof(sourceEnumerableOfT));
            }

            _wrapperProvider = elementWrapperProvider;

            var declaredElementType = enumerableOfT.GenericTypeArguments[0];
            var wrappedElementType  = elementWrapperProvider?.WrappingType ?? declaredElementType;

            WrappingType = typeof(DelegatingEnumerable <,>).MakeGenericType(wrappedElementType, declaredElementType);

            _wrappingTypeConstructor = WrappingType.GetConstructor(new[]
            {
                sourceEnumerableOfT,
                typeof(IWrapperProvider)
            });
        }
コード例 #3
0
        /// <summary>
        /// Attempts to produces a delagate that reads a <see cref="IAsyncEnumerable{T}"/> into an <see cref="ICollection{T}"/>.
        /// </summary>
        /// <param name="type">The type to read.</param>
        /// <param name="reader">A delegate that when awaited reads the <see cref="IAsyncEnumerable{T}"/>.</param>
        /// <returns><see langword="true" /> when <paramref name="type"/> is an instance of <see cref="IAsyncEnumerable{T}"/>, othwerise <see langword="false"/>.</returns>
        public bool TryGetReader(Type type, out Func <object, Task <ICollection> > reader)
        {
            if (!_asyncEnumerableConverters.TryGetValue(type, out reader))
            {
                var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(IAsyncEnumerable <>));
                if (enumerableType is null)
                {
                    // Not an IAsyncEnumerable<T>. Cache this result so we avoid reflection the next time we see this type.
                    reader = null;
                    _asyncEnumerableConverters.TryAdd(type, reader);
                }
                else
                {
                    var enumeratedObjectType = enumerableType.GetGenericArguments()[0];

                    var converter = (Func <object, Task <ICollection> >)Converter
                                    .MakeGenericMethod(enumeratedObjectType)
                                    .CreateDelegate(typeof(Func <object, Task <ICollection> >), this);

                    reader = converter;
                    _asyncEnumerableConverters.TryAdd(type, reader);
                }
            }

            return(reader != null);
        }
コード例 #4
0
        private TagHelperAttributeDescriptor GetIndexerAttributeDescriptor(ParameterInfo parameter, string name)
        {
            var dictionaryTypeArguments = ClosedGenericMatcher.ExtractGenericInterface(
                parameter.ParameterType,
                typeof(IDictionary <,>))
                                          ?.GenericTypeArguments
                                          .Select(t => t.IsGenericParameter ? null : t)
                                          .ToArray();

            if (dictionaryTypeArguments?[0] != typeof(string))
            {
                return(null);
            }

            var type       = dictionaryTypeArguments[1];
            var descriptor = new TagHelperAttributeDescriptor
            {
                Name         = name + "-",
                PropertyName = parameter.Name,
                TypeName     = GetCSharpTypeName(type),
                IsEnum       = type.GetTypeInfo().IsEnum,
                IsIndexer    = true
            };

            return(descriptor);
        }
コード例 #5
0
    protected virtual bool TryGetListTypeArgument(IList list, out Type listTypeArgument, out string errorMessage)
    {
        // Arrays are not supported as they have fixed size and operations like Add, Insert do not make sense
        var listType = list.GetType();

        if (listType.IsArray)
        {
            errorMessage     = Resources.FormatPatchNotSupportedForArrays(listType.FullName);
            listTypeArgument = null;
            return(false);
        }
        else
        {
            var genericList = ClosedGenericMatcher.ExtractGenericInterface(listType, typeof(IList <>));
            if (genericList == null)
            {
                errorMessage     = Resources.FormatPatchNotSupportedForNonGenericLists(listType.FullName);
                listTypeArgument = null;
                return(false);
            }
            else
            {
                listTypeArgument = genericList.GenericTypeArguments[0];
                errorMessage     = null;
                return(true);
            }
        }
    }
コード例 #6
0
        public IModelBinder?GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var modelType      = context.Metadata.ModelType;
            var dictionaryType = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(IDictionary <,>));

            if (dictionaryType != null)
            {
                var binderType = typeof(DictionaryModelBinder <,>).MakeGenericType(dictionaryType.GenericTypeArguments);

                var keyType   = dictionaryType.GenericTypeArguments[0];
                var keyBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(keyType));

                var valueType   = dictionaryType.GenericTypeArguments[1];
                var valueBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(valueType));

                var loggerFactory = context.Services.GetRequiredService <ILoggerFactory>();
                var mvcOptions    = context.Services.GetRequiredService <IOptions <MvcOptions> >().Value;
                return((IModelBinder)Activator.CreateInstance(
                           binderType,
                           keyBinder,
                           valueBinder,
                           loggerFactory,
                           true /* allowValidatingTopLevelNodes */,
                           mvcOptions) !);
            }

            return(null);
        }
コード例 #7
0
        /// <summary>
        /// Initializes an instance of <see cref="EnumerableWrapperProvider"/>.
        /// </summary>
        /// <param name="sourceEnumerableOfT">Type of the original <see cref="IEnumerable{T}" />
        /// that is being wrapped.</param>
        /// <param name="elementWrapperProvider">The <see cref="IWrapperProvider"/> for the element type.
        /// Can be null.</param>
        public EnumerableWrapperProvider(
            Type sourceEnumerableOfT,
            IWrapperProvider elementWrapperProvider)
        {
            if (sourceEnumerableOfT == null)
            {
                throw new ArgumentNullException(nameof(sourceEnumerableOfT));
            }

            var enumerableOfT = ClosedGenericMatcher.ExtractGenericInterface(
                sourceEnumerableOfT,
                typeof(IEnumerable <>));

            if (!sourceEnumerableOfT.GetTypeInfo().IsInterface || enumerableOfT == null)
            {
                throw new ArgumentException($"The type must be an interface and must be or derive from '{typeof(IEnumerable<>).Name}'.",
                                            nameof(sourceEnumerableOfT));
            }

            _wrapperProvider = elementWrapperProvider;

            var declaredElementType = enumerableOfT.GenericTypeArguments[0];
            var wrappedElementType  = elementWrapperProvider?.WrappingType ?? declaredElementType;

            WrappingType = typeof(DelegatingEnumerable <,>).MakeGenericType(wrappedElementType, declaredElementType);

            _wrappingTypeConstructor = WrappingType.GetConstructor(new[]
            {
                sourceEnumerableOfT,
                typeof(IWrapperProvider)
            });
        }
コード例 #8
0
        /// <summary>
        /// Gets an <see cref="EnumerableWrapperProvider"/> for the provided context.
        /// </summary>
        /// <param name="context">The <see cref="WrapperProviderContext"/>.</param>
        /// <returns>An instance of <see cref="EnumerableWrapperProvider"/> if the declared type is
        /// an interface and implements <see cref="IEnumerable{T}"/>.</returns>
        public IWrapperProvider?GetProvider(WrapperProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (context.IsSerialization)
            {
                // Example: IEnumerable<SerializableError>
                var declaredType = context.DeclaredType;

                // We only wrap interfaces types(ex: IEnumerable<T>, IQueryable<T>, IList<T> etc.) and not
                // concrete types like List<T>, Collection<T> which implement IEnumerable<T>.
                if (declaredType != null && declaredType.IsInterface && declaredType.IsGenericType)
                {
                    var enumerableOfT = ClosedGenericMatcher.ExtractGenericInterface(
                        declaredType,
                        typeof(IEnumerable <>));
                    if (enumerableOfT != null)
                    {
                        var elementType            = enumerableOfT.GenericTypeArguments[0];
                        var wrapperProviderContext = new WrapperProviderContext(elementType, context.IsSerialization);

                        var elementWrapperProvider =
                            _wrapperProviderFactories.GetWrapperProvider(wrapperProviderContext);

                        return(new EnumerableWrapperProvider(enumerableOfT, elementWrapperProvider));
                    }
                }
            }

            return(null);
        }
コード例 #9
0
        private static HandlerMethod CreateHandlerMethod(HandlerMethodDescriptor handlerDescriptor)
        {
            var method     = handlerDescriptor.MethodInfo;
            var parameters = handlerDescriptor.Parameters.ToArray();

            var returnType = method.ReturnType;

            if (returnType == typeof(void))
            {
                return(new VoidHandlerMethod(parameters, method));
            }
            else if (typeof(IActionResult).IsAssignableFrom(returnType))
            {
                return(new ActionResultHandlerMethod(parameters, method));
            }
            else if (returnType == typeof(Task))
            {
                return(new NonGenericTaskHandlerMethod(parameters, method));
            }
            else
            {
                var taskType = ClosedGenericMatcher.ExtractGenericInterface(returnType, typeof(Task <>));
                if (taskType != null && typeof(IActionResult).IsAssignableFrom(taskType.GenericTypeArguments[0]))
                {
                    return(new GenericTaskHandlerMethod(parameters, method));
                }
            }

            throw new InvalidOperationException(Resources.FormatUnsupportedHandlerMethodType(returnType));
        }
コード例 #10
0
        private Type GetDeclaredReturnType(ControllerActionDescriptor action)
        {
            var declaredReturnType = action.MethodInfo.ReturnType;

            if (declaredReturnType == typeof(void) ||
                declaredReturnType == typeof(Task))
            {
                return(typeof(void));
            }

            // Unwrap the type if it's a Task<T>. The Task (non-generic) case was already handled.
            var unwrappedType = UnwrapGenericType(declaredReturnType, typeof(Task <>));

            // Unwrap the type if it's ActionResult<T> or Task<ActionResult<T>>.
            unwrappedType = UnwrapGenericType(unwrappedType, typeof(ActionResult <>));

            // 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))
            {
                return(null);
            }
            else
            {
                return(unwrappedType);
            }

            Type UnwrapGenericType(Type type, Type queryType)
            {
                var genericType = ClosedGenericMatcher.ExtractGenericInterface(type, queryType);

                return(genericType?.GenericTypeArguments[0] ?? type);
            }
        }
コード例 #11
0
        /// <inheritdoc />
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var modelType = context.Metadata.ModelType;

            // Arrays are handled by another binder.
            if (modelType.IsArray)
            {
                return(null);
            }

            var loggerFactory = context.Services.GetRequiredService <ILoggerFactory>();
            var mvcOptions    = context.Services.GetRequiredService <IOptions <MvcOptions> >().Value;

            // 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)
            {
                var elementType   = collectionType.GenericTypeArguments[0];
                var elementBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(elementType));

                var binderType = typeof(CollectionModelBinder <>).MakeGenericType(collectionType.GenericTypeArguments);
                return((IModelBinder)Activator.CreateInstance(
                           binderType,
                           elementBinder,
                           loggerFactory,
                           mvcOptions.AllowValidatingTopLevelNodes));
            }

            // If the model type is IEnumerable<> then we need to know if we can assign a List<> to it, since
            // that's what we would create. (The cases handled here are IEnumerable<>, IReadOnlyCollection<> and
            // IReadOnlyList<>).
            var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(IEnumerable <>));

            if (enumerableType != null)
            {
                var listType = typeof(List <>).MakeGenericType(enumerableType.GenericTypeArguments);
                if (modelType.GetTypeInfo().IsAssignableFrom(listType.GetTypeInfo()))
                {
                    var elementType   = enumerableType.GenericTypeArguments[0];
                    var elementBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(elementType));

                    var binderType = typeof(CollectionModelBinder <>).MakeGenericType(enumerableType.GenericTypeArguments);
                    return((IModelBinder)Activator.CreateInstance(
                               binderType,
                               elementBinder,
                               loggerFactory,
                               mvcOptions.AllowValidatingTopLevelNodes));
                }
            }

            return(null);
        }
コード例 #12
0
        public static TryGetValueDelegate CreateInstance(Type targetType)
        {
            if (targetType == null)
            {
                throw new ArgumentNullException(nameof(targetType));
            }

            TryGetValueDelegate result;

            // Cache delegates since properties of model types are re-evaluated numerous times.
            _tryGetValueDelegateCacheLock.EnterReadLock();
            try
            {
                if (_tryGetValueDelegateCache.TryGetValue(targetType, out result))
                {
                    return(result);
                }
            }
            finally
            {
                _tryGetValueDelegateCacheLock.ExitReadLock();
            }

            var dictionaryType = ClosedGenericMatcher.ExtractGenericInterface(targetType, typeof(IDictionary <,>));

            // Just wrap a call to the underlying IDictionary<TKey, TValue>.TryGetValue() where string can be cast to
            // TKey.
            if (dictionaryType != null)
            {
                var typeArguments = dictionaryType.GenericTypeArguments;
                var keyType       = typeArguments[0];
                var returnType    = typeArguments[1];

                if (keyType.IsAssignableFrom(typeof(string)))
                {
                    var implementationMethod = _strongTryGetValueImplInfo.MakeGenericMethod(keyType, returnType);
                    result = (TryGetValueDelegate)implementationMethod.CreateDelegate(typeof(TryGetValueDelegate));
                }
            }

            // Wrap a call to the underlying IDictionary.Item().
            if (result == null && typeof(IDictionary).IsAssignableFrom(targetType))
            {
                result = TryGetValueFromNonGenericDictionary;
            }

            _tryGetValueDelegateCacheLock.EnterWriteLock();
            try
            {
                _tryGetValueDelegateCache[targetType] = result;
            }
            finally
            {
                _tryGetValueDelegateCacheLock.ExitWriteLock();
            }

            return(result);
        }
コード例 #13
0
 /// <inheritdoc />
 public ITypeInfo[] GetGenericDictionaryParameters()
 {
     return(ClosedGenericMatcher.ExtractGenericInterface(
                TypeInfo.AsType(),
                typeof(IDictionary <,>))
            ?.GenericTypeArguments
            .Select(type => type.IsGenericParameter ? null : new RuntimeTypeInfo(type.GetTypeInfo()))
            .ToArray());
 }
コード例 #14
0
        // Get the generic arguments for the binder, based on the model type. Or null if not compatible.
        private static Type[] GetGenericBinderTypeArgs(Type supportedInterfaceType, Type modelType)
        {
            Debug.Assert(supportedInterfaceType != null);
            Debug.Assert(modelType != null);

            var closedGenericInterface =
                ClosedGenericMatcher.ExtractGenericInterface(modelType, supportedInterfaceType);

            return(closedGenericInterface?.GenericTypeArguments);
        }
コード例 #15
0
    public void ExtractGenericInterface_ReturnsExpectedType(
        Type queryType,
        Type interfaceType,
        Type expectedResult)
    {
        // Arrange & Act
        var result = ClosedGenericMatcher.ExtractGenericInterface(queryType, interfaceType);

        // Assert
        Assert.Equal(expectedResult, result);
    }
コード例 #16
0
    public void ExtractGenericInterface_MultipleDefinitionsOnSameType()
    {
        // Arrange
        var type = typeof(TwoIEnumerableImplementationsOnSameClass);

        // Act
        var result = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(IEnumerable <>));

        // Sort
        Assert.Equal(typeof(IEnumerable <int>), result);
    }
コード例 #17
0
        public static bool CanSerializeType(Type typeToSerialize, out string errorMessage)
        {
            typeToSerialize = typeToSerialize ?? throw new ArgumentNullException(nameof(typeToSerialize));

            errorMessage = null;

            Type actualType = null;

            if (typeToSerialize.IsArray)
            {
                actualType = typeToSerialize.GetElementType();
            }
            else if (typeToSerialize.GetTypeInfo().IsGenericType)
            {
                if (ClosedGenericMatcher.ExtractGenericInterface(typeToSerialize, typeof(IList <>)) != null)
                {
                    var genericTypeArguments = typeToSerialize.GenericTypeArguments;
                    Debug.Assert(genericTypeArguments.Length == 1, "IList<T> has one generic argument");
                    actualType = genericTypeArguments[0];
                }
                else if (ClosedGenericMatcher.ExtractGenericInterface(typeToSerialize, typeof(IDictionary <,>)) != null)
                {
                    var genericTypeArguments = typeToSerialize.GenericTypeArguments;
                    Debug.Assert(
                        genericTypeArguments.Length == 2,
                        "IDictionary<TKey, TValue> has two generic arguments");

                    // The key must be of type string.
                    if (genericTypeArguments[0] != typeof(string))
                    {
                        errorMessage = Resources.FormatTempData_CannotSerializeDictionary(
                            typeof(TempDataSerializer).FullName,
                            genericTypeArguments[0],
                            typeof(string).FullName);
                        return(false);
                    }
                    else
                    {
                        actualType = genericTypeArguments[1];
                    }
                }
            }

            actualType = actualType ?? typeToSerialize;
            if (!IsSimpleType(actualType))
            {
                errorMessage = Resources.FormatTempData_CannotSerializeType(
                    typeof(TempDataSerializer).FullName,
                    actualType);
                return(false);
            }

            return(true);
        }
コード例 #18
0
        private void ActivateProperties(object controller, Type containerType, Dictionary <string, object> properties)
        {
            var propertyHelpers = PropertyHelper.GetProperties(controller);

            foreach (var property in properties)
            {
                var propertyHelper = propertyHelpers.First(helper =>
                                                           string.Equals(helper.Name, property.Key, StringComparison.Ordinal));
                var propertyType = propertyHelper.Property.PropertyType;
                var source       = property.Value;
                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 || TypeHelper.AllowsNullValue(propertyType))
                    {
                        propertyHelper.SetValue(controller, source);
                    }

                    continue;
                }

                if (propertyType.IsArray)
                {
                    // Do not attempt to copy values into an array because an array's length is immutable. This choice
                    // is also consistent with MutableObjectModelBinder's handling of a read-only array property.
                    continue;
                }

                var target = propertyHelper.GetValue(controller);
                if (source == null || target == null)
                {
                    // Nothing to do when source or target is null.
                    continue;
                }

                // Determine T if this is an ICollection<T> property.
                var collectionTypeArguments = ClosedGenericMatcher.ExtractGenericInterface(
                    propertyType,
                    typeof(ICollection <>))
                                              ?.GenericTypeArguments;
                if (collectionTypeArguments == null)
                {
                    // Not a collection model.
                    continue;
                }

                // Handle a read-only collection property.
                var propertyAddRange = CallPropertyAddRangeOpenGenericMethod.MakeGenericMethod(
                    collectionTypeArguments);
                propertyAddRange.Invoke(obj: null, parameters: new[] { target, source });
            }
        }
コード例 #19
0
    private void InitializeTypeInformation()
    {
        Debug.Assert(ModelType != null);

        IsComplexType             = !TypeDescriptor.GetConverter(ModelType).CanConvertFrom(typeof(string));
        IsNullableValueType       = Nullable.GetUnderlyingType(ModelType) != null;
        IsReferenceOrNullableType = !ModelType.IsValueType || IsNullableValueType;
        UnderlyingOrModelType     = Nullable.GetUnderlyingType(ModelType) ?? ModelType;

        var collectionType = ClosedGenericMatcher.ExtractGenericInterface(ModelType, typeof(ICollection <>));

        IsCollectionType = collectionType != null;

        var nullabilityContext = new NullabilityInfoContext();
        var nullability        = MetadataKind switch
        {
            ModelMetadataKind.Parameter => Identity.ParameterInfo != null?nullabilityContext.Create(Identity.ParameterInfo !) : null,
                ModelMetadataKind.Property => Identity.PropertyInfo != null?nullabilityContext.Create(Identity.PropertyInfo !) : null,
                    _ => null
        };

        NullabilityState = nullability?.ReadState ?? NullabilityState.Unknown;

        if (ModelType == typeof(string) || !typeof(IEnumerable).IsAssignableFrom(ModelType))
        {
            // Do nothing, not Enumerable.
        }
        else if (ModelType.IsArray)
        {
            IsEnumerableType = true;
            ElementType      = ModelType.GetElementType() !;
        }
        else
        {
            IsEnumerableType = true;

            var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(ModelType, typeof(IEnumerable <>));
            ElementType = enumerableType?.GenericTypeArguments[0] !;

            if (ElementType == null)
            {
                // ModelType implements IEnumerable but not IEnumerable<T>.
                ElementType = typeof(object);
            }

            Debug.Assert(
                ElementType != null,
                $"Unable to find element type for '{ModelType.FullName}' though IsEnumerableType is true.");
        }
    }
コード例 #20
0
        private static Type GetKeyValuePairBinder(Type modelType)
        {
            Debug.Assert(modelType != null);

            // Since KeyValuePair is a value type, ExtractGenericInterface() succeeds only on an exact match.
            var closedGenericType = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(KeyValuePair <,>));

            if (closedGenericType != null)
            {
                return(typeof(KeyValuePairModelBinder <,>).MakeGenericType(modelType.GenericTypeArguments));
            }

            return(null);
        }
コード例 #21
0
        /// <inheritdoc />
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var modelType = context.Metadata.ModelType;

            // Arrays are handled by another binder.
            if (modelType.IsArray)
            {
                return(null);
            }

            // 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)
            {
                var elementType   = collectionType.GenericTypeArguments[0];
                var elementBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(elementType));

                var binderType = typeof(CollectionModelBinder <>).MakeGenericType(collectionType.GenericTypeArguments);
                return((IModelBinder)Activator.CreateInstance(binderType, elementBinder));
            }

            // If the model type is IEnumerable<> then we need to know if we can assign a List<> to it, since
            // that's what we would create. (The cases handled here are IEnumerable<>, IReadOnlyColection<> and
            // IReadOnlyList<>).
            //
            // We need to check IsReadOnly because we need to know if we can SET the property.
            var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(IEnumerable <>));

            if (enumerableType != null && !context.Metadata.IsReadOnly)
            {
                var listType = typeof(List <>).MakeGenericType(enumerableType.GenericTypeArguments);
                if (modelType.GetTypeInfo().IsAssignableFrom(listType.GetTypeInfo()))
                {
                    var elementType   = enumerableType.GenericTypeArguments[0];
                    var elementBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(elementType));

                    var binderType = typeof(CollectionModelBinder <>).MakeGenericType(enumerableType.GenericTypeArguments);
                    return((IModelBinder)Activator.CreateInstance(binderType, elementBinder));
                }
            }

            return(null);
        }
コード例 #22
0
        private void AddToProperty(
            ModelBindingContext bindingContext,
            ModelExplorer modelExplorer,
            PropertyInfo property,
            ModelBindingResult result)
        {
            var propertyExplorer = modelExplorer.GetExplorerForProperty(property.Name);

            var target = propertyExplorer.Model;
            var source = result.Model;

            if (target == null || source == null)
            {
                // Cannot copy to or from a null collection.
                return;
            }

            if (target == source)
            {
                // Added to the target collection in BindPropertiesAsync().
                return;
            }

            // Determine T if this is an ICollection<T> property. No need for a T[] case because CanUpdateProperty()
            // ensures property is either settable or not an array. Underlying assumption is that CanUpdateProperty()
            // and SetProperty() are overridden together.
            var collectionTypeArguments = ClosedGenericMatcher.ExtractGenericInterface(
                propertyExplorer.ModelType,
                typeof(ICollection <>))
                                          ?.GenericTypeArguments;

            if (collectionTypeArguments == null)
            {
                // Not a collection model.
                return;
            }

            var propertyAddRange = CallPropertyAddRangeOpenGenericMethod.MakeGenericMethod(collectionTypeArguments);

            try
            {
                propertyAddRange.Invoke(obj: null, parameters: new[] { target, source });
            }
            catch (Exception exception)
            {
                AddModelError(exception, bindingContext, result);
            }
        }
コード例 #23
0
        internal void EnsureObjectCanBeSerialized(object item)
        {
            var  itemType   = item.GetType();
            Type actualType = null;

            if (itemType.IsArray)
            {
                itemType = itemType.GetElementType();
            }
            else if (itemType.GetTypeInfo().IsGenericType)
            {
                if (ClosedGenericMatcher.ExtractGenericInterface(itemType, typeof(IList <>)) != null)
                {
                    var genericTypeArguments = itemType.GenericTypeArguments;
                    Debug.Assert(genericTypeArguments.Length == 1, "IList<T> has one generic argument");
                    actualType = genericTypeArguments[0];
                }
                else if (ClosedGenericMatcher.ExtractGenericInterface(itemType, typeof(IDictionary <,>)) != null)
                {
                    var genericTypeArguments = itemType.GenericTypeArguments;
                    Debug.Assert(
                        genericTypeArguments.Length == 2,
                        "IDictionary<TKey, TValue> has two generic arguments");

                    // Throw if the key type of the dictionary is not string.
                    if (genericTypeArguments[0] != typeof(string))
                    {
                        var message = Resources.FormatTempData_CannotSerializeDictionary(
                            typeof(SessionStateTempDataProvider).FullName, genericTypeArguments[0]);
                        throw new InvalidOperationException(message);
                    }
                    else
                    {
                        actualType = genericTypeArguments[1];
                    }
                }
            }

            actualType = actualType ?? itemType;
            if (!IsSimpleType(actualType))
            {
                var underlyingType = Nullable.GetUnderlyingType(actualType) ?? actualType;
                var message        = Resources.FormatTempData_CannotSerializeToSession(
                    typeof(SessionStateTempDataProvider).FullName, underlyingType);
                throw new InvalidOperationException(message);
            }
        }
コード例 #24
0
        private void InitializeTypeInformation()
        {
            Debug.Assert(ModelType != null);

            IsComplexType             = !TypeDescriptor.GetConverter(ModelType).CanConvertFrom(typeof(string));
            IsNullableValueType       = Nullable.GetUnderlyingType(ModelType) != null;
            IsReferenceOrNullableType = !ModelType.GetTypeInfo().IsValueType || IsNullableValueType;
            UnderlyingOrModelType     = Nullable.GetUnderlyingType(ModelType) ?? ModelType;

            var collectionType = ClosedGenericMatcher.ExtractGenericInterface(ModelType, typeof(ICollection <>));

            IsCollectionType = collectionType != null;

            if (ModelType == typeof(string) || !typeof(IEnumerable).IsAssignableFrom(ModelType))
            {
                // Do nothing, not Enumerable.
            }
            else if (ModelType.IsArray)
            {
                IsEnumerableType = true;
                ElementType      = ModelType.GetElementType();
            }
            else
            {
                IsEnumerableType = true;

                var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(ModelType, typeof(IEnumerable <>));
                ElementType = enumerableType?.GenericTypeArguments[0];

                if (ElementType == null && typeof(IEnumerable).IsAssignableFrom(ModelType))
                {
                    // ModelType implements IEnumerable but not IEnumerable<T>.
                    ElementType = typeof(object);
                }

                Debug.Assert(
                    ElementType != null,
                    $"Unable to find element type for '{ModelType.FullName}' though IsEnumerableType is true.");
            }
        }
コード例 #25
0
    public IModelBinder?GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        var modelType = context.Metadata.ModelType;

        // Arrays are handled by another binder.
        if (modelType.IsArray)
        {
            return(null);
        }

        // 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)
        {
            return(CreateInstance(context, collectionType));
        }

        // If the model type is IEnumerable<> then we need to know if we can assign a List<> to it, since
        // that's what we would create. (The cases handled here are IEnumerable<>, IReadOnlyCollection<> and
        // IReadOnlyList<>).
        var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(IEnumerable <>));

        if (enumerableType != null)
        {
            var listType = typeof(List <>).MakeGenericType(enumerableType.GenericTypeArguments);
            if (modelType.IsAssignableFrom(listType))
            {
                return(CreateInstance(context, listType));
            }
        }

        return(null);
    }
コード例 #26
0
        /// <inheritdoc />
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var modelType      = context.Metadata.ModelType;
            var dictionaryType = ClosedGenericMatcher.ExtractGenericInterface(modelType, typeof(IDictionary <,>));

            if (dictionaryType != null)
            {
                var keyType   = dictionaryType.GenericTypeArguments[0];
                var keyBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(keyType));

                var valueType   = dictionaryType.GenericTypeArguments[1];
                var valueBinder = context.CreateBinder(context.MetadataProvider.GetMetadataForType(valueType));

                var binderType = typeof(DictionaryModelBinder <,>).MakeGenericType(dictionaryType.GenericTypeArguments);
                return((IModelBinder)Activator.CreateInstance(binderType, keyBinder, valueBinder));
            }

            return(null);
        }
コード例 #27
0
        public static string CollectionTemplate(IHtmlHelper htmlHelper)
        {
            var viewData = htmlHelper.ViewData;
            var model    = viewData.Model;

            if (model == null)
            {
                return(string.Empty);
            }

            var collection = model as IEnumerable;

            if (collection == null)
            {
                // Only way we could reach here is if user passed templateName: "Collection" to an Editor() overload.
                throw new InvalidOperationException(Resources.FormatTemplates_TypeMustImplementIEnumerable(
                                                        "Collection", model.GetType().FullName, typeof(IEnumerable).FullName));
            }

            var typeInCollection      = typeof(string);
            var genericEnumerableType = ClosedGenericMatcher.ExtractGenericInterface(
                collection.GetType(),
                typeof(IEnumerable <>));

            if (genericEnumerableType != null)
            {
                typeInCollection = genericEnumerableType.GenericTypeArguments[0];
            }

            var typeInCollectionIsNullableValueType = TypeHelper.IsNullableValueType(typeInCollection);
            var oldPrefix = viewData.TemplateInfo.HtmlFieldPrefix;

            try
            {
                viewData.TemplateInfo.HtmlFieldPrefix = string.Empty;

                var fieldNameBase = oldPrefix;
                var result        = new StringBuilder();

                var serviceProvider  = htmlHelper.ViewContext.HttpContext.RequestServices;
                var metadataProvider = serviceProvider.GetRequiredService <IModelMetadataProvider>();
                var viewEngine       = serviceProvider.GetRequiredService <ICompositeViewEngine>();

                var index = 0;
                foreach (var item in collection)
                {
                    var itemType = typeInCollection;
                    if (item != null && !typeInCollectionIsNullableValueType)
                    {
                        itemType = item.GetType();
                    }

                    var modelExplorer = metadataProvider.GetModelExplorerForType(itemType, item);
                    var fieldName     = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", fieldNameBase, index++);

                    var templateBuilder = new TemplateBuilder(
                        viewEngine,
                        htmlHelper.ViewContext,
                        htmlHelper.ViewData,
                        modelExplorer,
                        htmlFieldName: fieldName,
                        templateName: null,
                        readOnly: false,
                        additionalViewData: null);

                    var output = templateBuilder.Build();
                    result.Append(output);
                }

                return(result.ToString());
            }
            finally
            {
                viewData.TemplateInfo.HtmlFieldPrefix = oldPrefix;
            }
        }
コード例 #28
0
        private TagHelperAttributeDescriptor ToIndexerAttributeDescriptor(
            PropertyInfo property,
            HtmlAttributeNameAttribute attributeNameAttribute,
            Type parentType,
            ErrorSink errorSink,
            string defaultPrefix,
            out bool isInvalid)
        {
            isInvalid = false;
            var hasPublicSetter = property.SetMethod != null && property.SetMethod.IsPublic;
            var dictionaryTypeArguments = ClosedGenericMatcher.ExtractGenericInterface(
                property.PropertyType,
                typeof(IDictionary<,>))
                ?.GenericTypeArguments
                .Select(type => type.IsGenericParameter ? null : type)
                .ToArray();
            if (dictionaryTypeArguments?[0] != typeof(string))
            {
                if (attributeNameAttribute?.DictionaryAttributePrefix != null)
                {
                    // DictionaryAttributePrefix is not supported unless associated with an
                    // IDictionary<string, TValue> property.
                    isInvalid = true;
                    errorSink.OnError(
                        SourceLocation.Zero,
                        Resources.FormatTagHelperDescriptorFactory_InvalidAttributePrefixNotNull(
                            parentType.FullName,
                            property.Name,
                            nameof(HtmlAttributeNameAttribute),
                            nameof(HtmlAttributeNameAttribute.DictionaryAttributePrefix),
                            "IDictionary<string, TValue>"),
                        length: 0);
                }
                else if (attributeNameAttribute != null && !hasPublicSetter)
                {
                    // Associated an HtmlAttributeNameAttribute with a non-dictionary property that lacks a public
                    // setter.
                    isInvalid = true;
                    errorSink.OnError(
                        SourceLocation.Zero,
                        Resources.FormatTagHelperDescriptorFactory_InvalidAttributeNameAttribute(
                            parentType.FullName,
                            property.Name,
                            nameof(HtmlAttributeNameAttribute),
                            "IDictionary<string, TValue>"),
                        length: 0);
                }

                return null;
            }
            else if (!hasPublicSetter &&
                attributeNameAttribute != null &&
                !attributeNameAttribute.DictionaryAttributePrefixSet)
            {
                // Must set DictionaryAttributePrefix when using HtmlAttributeNameAttribute with a dictionary property
                // that lacks a public setter.
                isInvalid = true;
                errorSink.OnError(
                    SourceLocation.Zero,
                    Resources.FormatTagHelperDescriptorFactory_InvalidAttributePrefixNull(
                        parentType.FullName,
                        property.Name,
                        nameof(HtmlAttributeNameAttribute),
                        nameof(HtmlAttributeNameAttribute.DictionaryAttributePrefix),
                        "IDictionary<string, TValue>"),
                    length: 0);

                return null;
            }

            // Potential prefix case. Use default prefix (based on name)?
            var useDefault = attributeNameAttribute == null || !attributeNameAttribute.DictionaryAttributePrefixSet;

            var prefix = useDefault ? defaultPrefix : attributeNameAttribute.DictionaryAttributePrefix;
            if (prefix == null)
            {
                // DictionaryAttributePrefix explicitly set to null. Ignore.
                return null;
            }

            return ToAttributeDescriptor(
                property,
                attributeName: prefix,
                typeName: dictionaryTypeArguments[1].FullName,
                isIndexer: true,
                isStringProperty: typeof(string) == dictionaryTypeArguments[1]);
        }
コード例 #29
0
        private static Type GetTaskInnerTypeOrNull(Type type)
        {
            var genericType = ClosedGenericMatcher.ExtractGenericInterface(type, typeof(Task <>));

            return(genericType?.GenericTypeArguments[0]);
        }
コード例 #30
0
ファイル: ProxyModelMetadata.cs プロジェクト: tahaipek/Proxy
        private void InitializeTypeInformation()
        {
            var typeInfo = ModelType.GetTypeInfo();

            IsComplexType             = !TypeDescriptor.GetConverter(ModelType).CanConvertFrom(typeof(string));
            IsNullableValueType       = Nullable.GetUnderlyingType(ModelType) != null;
            IsReferenceType           = !typeInfo.IsValueType;
            IsReferenceOrNullableType = !typeInfo.IsValueType || IsNullableValueType;
            UnderlyingOrModelType     = Nullable.GetUnderlyingType(ModelType) ?? ModelType;
            IsFormFile     = typeof(IFormFile).IsAssignableFrom(ModelType);
            IsSimpleType   = IsSimple(ModelType);
            IsSystemObject = ModelType == typeof(object);

            var collectionType = ClosedGenericMatcher.ExtractGenericInterface(ModelType, typeof(ICollection <>));

            IsCollectionType = collectionType != null;

            if (ModelType == typeof(string) || !typeof(IEnumerable).IsAssignableFrom(ModelType))
            {
                // Do nothing, not Enumerable.
            }
            else if (ModelType.IsArray)
            {
                IsEnumerableType = true;
                var elementType = ModelType.GetElementType();

                PropertyInfo propertyInfo = ContainerType?.GetProperty(PropertyName);
                if (propertyInfo != null)
                {
                    ElementType = new ProxyModelMetadata(propertyInfo,
                                                         ProxyModelMetadataIdentity.ForProperty(elementType, propertyInfo.Name, ModelType),
                                                         reflectedType: _reflectedType);
                }

                IsFormFile = typeof(IFormFile).IsAssignableFrom(elementType);
            }
            else
            {
                IsEnumerableType = true;

                var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(ModelType, typeof(IEnumerable <>));
                var elementType    = enumerableType?.GenericTypeArguments[0];

                if (elementType != null)
                {
                    IsFormFile = typeof(IFormFile).IsAssignableFrom(elementType);
                }

                if (elementType == null)
                {
                    // ModelType implements IEnumerable but not IEnumerable<T>.
                    elementType = typeof(object);
                }

                PropertyInfo propertyInfo = ContainerType?.GetProperty(PropertyName);
                if (propertyInfo != null)
                {
                    ElementType = new ProxyModelMetadata(propertyInfo,
                                                         ProxyModelMetadataIdentity.ForProperty(elementType, propertyInfo.Name, ModelType),
                                                         reflectedType: _reflectedType);
                }
            }

            if (IsNullableValueType)
            {
                var          elementType = Nullable.GetUnderlyingType(ModelType);
                PropertyInfo pInfo       = ContainerType?.GetProperty(PropertyName);
                if (pInfo != null)
                {
                    ElementType = new ProxyModelMetadata(pInfo,
                                                         ProxyModelMetadataIdentity.ForProperty(elementType, pInfo.Name, ModelType),
                                                         reflectedType: _reflectedType);
                }
            }

            if (IsComplexType && IsReferenceOrNullableType &&
                (!IsEnumerableType && !IsCollectionType) &&
                ModelType.Name != typeof(object).Name)
            {
                PropertyInfo[]            properties   = ModelType.GetProperties();
                List <ProxyModelMetadata> metadataList = new List <ProxyModelMetadata>();
                foreach (var prop in properties)
                {
                    if (_reflectedType == null)
                    {
                        _reflectedType = prop.ReflectedType;
                    }

                    if (_reflectedType == prop.PropertyType)
                    {
                        // self reference loop
                        continue;
                    }

                    if (ModelType == prop.PropertyType)
                    {
                        // Parent child ref - self reference loop
                        continue;
                    }

                    metadataList.Add(new ProxyModelMetadata(prop,
                                                            ProxyModelMetadataIdentity.ForProperty(prop.PropertyType, prop.Name, ModelType),
                                                            reflectedType: _reflectedType));
                }

                Properties = metadataList;
            }
        }