コード例 #1
0
        public MetadataOverrideScope(ModelMetadata metadata)
        {
            if (metadata == null)
            {
                throw new ArgumentNullException("metadata");
            }
            if (metadata.ModelType == null)
            {
                throw new ArgumentException("Need ModelType", "metadata");
            }

            _oldMetadataProvider = ModelMetadataProviders.Current;
            _metadata = metadata;
            _modelType = metadata.ModelType;

            // Mock a ModelMetadataProvider which delegates to the old one in most cases.  No need to special-case
            // GetMetadataForProperties() because product code uses it only within ModelMetadata.Properties and our
            // metadata instance will call _oldMetadataProvider there.
            var metadataProvider = new Mock<ModelMetadataProvider>();
            metadataProvider
                .Setup(p => p.GetMetadataForProperties(It.IsAny<object>(), It.IsAny<Type>()))
                .Returns((object container, Type containerType) =>
                    _oldMetadataProvider.GetMetadataForProperties(container, containerType));
            metadataProvider
                .Setup(p => p.GetMetadataForType(It.IsAny<Func<object>>(), It.IsAny<Type>()))
                .Returns((Func<object> modelAccessor, Type modelType) =>
                    _oldMetadataProvider.GetMetadataForType(modelAccessor, modelType));

            // When metadata for _modelType is requested, then return a clone of the provided metadata instance.
            // GetMetadataForProperty() is important because the static discovery methods (e.g.
            // ModelMetadata.FromLambdaExpression) use it.
            metadataProvider
                .Setup(p => p.GetMetadataForType(It.IsAny<Func<object>>(), _modelType))
                .Returns((Func<object> modelAccessor, Type modelType) => GetMetadataForType(modelAccessor, modelType));
            metadataProvider
                .Setup(p =>
                    p.GetMetadataForProperty(It.IsAny<Func<object>>(), It.IsAny<Type>(), It.IsAny<string>()))
                .Returns((Func<object> modelAccessor, Type containerType, string propertyName) =>
                    GetMetadataForProperty(modelAccessor, containerType, propertyName));

            // Calls to GetMetadataForProperties for the modelType are incorrect because _metadata.Provider must
            // reference _oldMetadataProvider and not this mock.
            metadataProvider
                .Setup(p => p.GetMetadataForProperty(It.IsAny<Func<object>>(), _modelType, It.IsAny<string>()))
                .Throws<InvalidOperationException>();

            // Finally make our ModelMetadataProvider visible everywhere.
            ModelMetadataProviders.Current = metadataProvider.Object;
        }
コード例 #2
0
        /// <summary>
        /// Determines whether the <paramref name="model"/> is valid and adds any validation errors to the <paramref name="actionContext"/>'s <see cref="ModelStateDictionary"/>
        /// </summary>
        /// <param name="model">The model to be validated.</param>
        /// <param name="type">The <see cref="Type"/> to use for validation.</param>
        /// <param name="metadataProvider">The <see cref="ModelMetadataProvider"/> used to provide the model metadata.</param>
        /// <param name="actionContext">The <see cref="HttpActionContext"/> within which the model is being validated.</param>
        /// <param name="keyPrefix">The <see cref="string"/> to append to the key for any validation errors.</param>
        /// <returns><c>true</c>if <paramref name="model"/> is valid, <c>false</c> otherwise.</returns>
        public bool Validate(object model, Type type, ModelMetadataProvider metadataProvider, HttpActionContext actionContext, string keyPrefix)
        {
            if (type == null)
            {
                throw Error.ArgumentNull("type");
            }

            if (metadataProvider == null)
            {
                throw Error.ArgumentNull("metadataProvider");
            }

            if (actionContext == null)
            {
                throw Error.ArgumentNull("actionContext");
            }

            if (model != null && !ShouldValidateType(model.GetType()))
            {
                return(true);
            }

            ModelValidatorProvider[] validatorProviders = actionContext.GetValidatorProviders().ToArray();
            // Optimization : avoid validating the object graph if there are no validator providers
            if (validatorProviders == null || validatorProviders.Length == 0)
            {
                return(true);
            }

            ModelMetadata     metadata          = metadataProvider.GetMetadataForType(() => model, type);
            ValidationContext validationContext = new ValidationContext()
            {
                MetadataProvider = metadataProvider,
                ActionContext    = actionContext,
                ValidatorCache   = actionContext.GetValidatorCache(),
                ModelState       = actionContext.ModelState,
                Visited          = new HashSet <object>(ReferenceEqualityComparer.Instance),
                KeyBuilders      = new Stack <IKeyBuilder>(),
                RootPrefix       = keyPrefix
            };

            return(ValidateNodeAndChildren(metadata, validationContext, container: null, validators: null));
        }
コード例 #3
0
        public bool Validate(object model, Type type, ModelMetadataProvider metadataProvider, HttpActionContext actionContext, string keyPrefix)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (metadataProvider == null)
            {
                throw new ArgumentNullException("metadataProvider");
            }

            if (actionContext == null)
            {
                throw new ArgumentNullException("actionContext");
            }

            if (model != null && MediaTypeFormatterCollection.IsTypeExcludedFromValidation(model.GetType()))
            {
                // no validation for some DOM like types
                return(true);
            }

            ModelValidatorProvider[] validatorProviders = actionContext.GetValidatorProviders().ToArray();
            // Optimization : avoid validating the object graph if there are no validator providers
            if (validatorProviders == null || validatorProviders.Length == 0)
            {
                return(true);
            }

            ModelMetadata     metadata          = metadataProvider.GetMetadataForType(() => model, type);
            ValidationContext validationContext = new ValidationContext {
                MetadataProvider = metadataProvider,
                ActionContext    = actionContext,
                ModelState       = actionContext.ModelState,
                Visited          = new HashSet <object>(),
                KeyBuilders      = new Stack <IKeyBuilder>(),
                RootPrefix       = keyPrefix
            };

            return(this.ValidateNodeAndChildren(metadata, validationContext, container: null));
        }
コード例 #4
0
        private ModelBindingContext GetModelBindingContext(ModelMetadataProvider metadataProvider, HttpActionContext actionContext)
        {
            string name = Descriptor.ParameterName;
            Type   type = Descriptor.ParameterType;

            string prefix = Descriptor.Prefix;

            IValueProvider vp = CompositeValueProviderFactory.GetValueProvider(actionContext, _valueProviderFactories);

            ModelBindingContext ctx = new ModelBindingContext()
            {
                ModelName             = prefix ?? name,
                FallbackToEmptyPrefix = prefix == null, // only fall back if prefix not specified
                ModelMetadata         = metadataProvider.GetMetadataForType(null, type),
                ModelState            = actionContext.ModelState,
                ValueProvider         = vp
            };

            return(ctx);
        }
コード例 #5
0
        // Helper for ReadAs() to get a ModelBindingContext to invoke model binding over FormUrl data.
        private static ModelBindingContext CreateModelBindingContext(HttpActionContext actionContext, string modelName, Type type, IValueProvider vp)
        {
            Contract.Assert(actionContext != null);
            Contract.Assert(type != null);
            Contract.Assert(vp != null);

            ServicesContainer     cs = actionContext.ControllerContext.Configuration.Services;
            ModelMetadataProvider metadataProvider = cs.GetModelMetadataProvider();

            ModelBindingContext ctx = new ModelBindingContext()
            {
                ModelName             = modelName,
                FallbackToEmptyPrefix = false,
                ModelMetadata         = metadataProvider.GetMetadataForType(null, type),
                ModelState            = actionContext.ModelState,
                ValueProvider         = vp
            };

            return(ctx);
        }
コード例 #6
0
        /// <summary>
        /// Pick out validation errors and turn these into a suitable exception structure
        /// </summary>
        /// <param name="actionContext">Action Context</param>
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            ModelStateDictionary modelState = actionContext.ModelState;

            if (modelState.IsValid)
            {
                // Only perform the FluentValidation if we've not already failed validation earlier on
                IDependencyScope scope = actionContext.Request.GetDependencyScope();
                var mvp = scope.GetService(typeof(IFluentValidatorProvider)) as IFluentValidatorProvider;

                if (mvp != null)
                {
                    ModelMetadataProvider metadataProvider = actionContext.GetMetadataProvider();

                    foreach (KeyValuePair <string, object> argument in actionContext.ActionArguments)
                    {
                        if (argument.Value != null && !argument.Value.GetType().IsSimpleType())
                        {
                            ModelMetadata metadata = metadataProvider.GetMetadataForType(
                                () => argument.Value,
                                argument.Value.GetType()
                                );

                            var validationContext = new InternalValidationContext
                            {
                                MetadataProvider = metadataProvider,
                                ActionContext    = actionContext,
                                ModelState       = actionContext.ModelState,
                                Visited          = new HashSet <object>(),
                                KeyBuilders      = new Stack <IKeyBuilder>(),
                                RootPrefix       = String.Empty,
                                Provider         = mvp,
                                Scope            = scope
                            };

                            ValidateNodeAndChildren(metadata, validationContext, null);
                        }
                    }
                }
            }
        }
コード例 #7
0
        public static bool TryBindStrongModel <TModel>(
            ControllerContext controllerContext,
            ExtensibleModelBindingContext parentBindingContext,
            string propertyName,
            ModelMetadataProvider metadataProvider,
            out TModel model
            )
        {
            ExtensibleModelBindingContext propertyBindingContext =
                new ExtensibleModelBindingContext(parentBindingContext)
            {
                ModelMetadata = metadataProvider.GetMetadataForType(null, typeof(TModel)),
                ModelName     = ModelBinderUtil.CreatePropertyModelName(
                    parentBindingContext.ModelName,
                    propertyName
                    )
            };

            IExtensibleModelBinder binder = parentBindingContext.ModelBinderProviders.GetBinder(
                controllerContext,
                propertyBindingContext
                );

            if (binder != null)
            {
                if (binder.BindModel(controllerContext, propertyBindingContext))
                {
                    object untypedModel = propertyBindingContext.Model;
                    model = ModelBinderUtil.CastOrDefault <TModel>(untypedModel);
                    parentBindingContext.ValidationNode.ChildNodes.Add(
                        propertyBindingContext.ValidationNode
                        );
                    return(true);
                }
            }

            model = default(TModel);
            return(false);
        }
コード例 #8
0
        public void Map(IDynamicDataModelSchema details, Type modelType)
        {
            Condition.Requires(details).IsNotNull();
            Condition.Requires(modelType).IsNotNull();

            var dataModelMetaData = _modelMetadataProvider.GetMetadataForType(null, modelType);

            details.DataTemplateName = StringHelper.FirstNonEmpty(
                dataModelMetaData.TemplateHint,
                dataModelMetaData.DataTypeName
                );

            var properiesMetaData = _modelMetadataProvider.GetMetadataForProperties(null, modelType);

            var dataModelProperties = new List <DynamicDataModelSchemaProperty>();

            foreach (var propertyMetaData in properiesMetaData.OrderBy(p => p.Order))
            {
                var property = new DynamicDataModelSchemaProperty();
                property.Name        = propertyMetaData.PropertyName;
                property.DisplayName = propertyMetaData.DisplayName;
                property.Description = propertyMetaData.Description;
                property.IsRequired  = propertyMetaData.IsRequired;

                property.DataTemplateName = StringHelper.FirstNonEmpty(
                    propertyMetaData.TemplateHint,
                    propertyMetaData.DataTypeName,
                    propertyMetaData.IsNullableValueType ? propertyMetaData.ModelType.GenericTypeArguments[0].Name : propertyMetaData.ModelType.Name
                    );

                property.AdditionalAttributes = propertyMetaData.AdditionalValues;

                dataModelProperties.Add(property);
            }

            details.DataModelProperties = dataModelProperties.ToArray();
        }
コード例 #9
0
        public static bool TryBindStrongModel <TModel>(
            this HttpActionContext actionContext,
            ModelBindingContext parentBindingContext,
            string propertyName,
            ModelMetadataProvider metadataProvider,
            out TModel model
            )
        {
            if (actionContext == null)
            {
                throw Error.ArgumentNull("actionContext");
            }

            ModelBindingContext propertyBindingContext = new ModelBindingContext(
                parentBindingContext
                )
            {
                ModelMetadata = metadataProvider.GetMetadataForType(null, typeof(TModel)),
                ModelName     = ModelBindingHelper.CreatePropertyModelName(
                    parentBindingContext.ModelName,
                    propertyName
                    )
            };

            if (actionContext.Bind(propertyBindingContext))
            {
                object untypedModel = propertyBindingContext.Model;
                model = ModelBindingHelper.CastOrDefault <TModel>(untypedModel);
                parentBindingContext.ValidationNode.ChildNodes.Add(
                    propertyBindingContext.ValidationNode
                    );
                return(true);
            }

            model = default(TModel);
            return(false);
        }
コード例 #10
0
        private void BuildColumns()
        {
            var modelMetadata = _metadataProvider.GetMetadataForType(() => null, typeof(T));

            foreach (var property in modelMetadata.Properties)
            {
                if (!property.ShowForDisplay)
                {
                    continue;
                }

                var column = For(PropertyToExpression(property));

                if (!string.IsNullOrEmpty(property.DisplayName))
                {
                    column.Named(property.DisplayName);
                }

                if (!string.IsNullOrEmpty(property.DisplayFormatString))
                {
                    column.Format(property.DisplayFormatString);
                }
            }
        }
コード例 #11
0
        public AutoColumnGridModel(ModelMetadataProvider metadataProvider)
        {
            var modelMetadata = metadataProvider.GetMetadataForType(() => null, typeof(T));

            foreach (var property in modelMetadata.Properties)
            {
                if (!property.ShowForDisplay)
                {
                    continue;
                }

                var column = Column.For(PropertyToExpression(property));

                if (!string.IsNullOrEmpty(property.DisplayName))
                {
                    column.Named(property.DisplayName);
                }

                if (!string.IsNullOrEmpty(property.DisplayFormatString))
                {
                    column.Format(property.DisplayFormatString);
                }
            }
        }
コード例 #12
0
        private object BindToModel(IDictionary <string, object> data, Type type, IFormatterLogger formatterLogger)
        {
            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            HttpConfiguration config = GlobalConfiguration.Configuration;

            // if there is a requiredMemberSelector set, use this one by replacing the validator provider
            bool validateRequiredMembers = RequiredMemberSelector != null && formatterLogger != null;

            if (validateRequiredMembers)
            {
                config.Services.Replace(typeof(ModelValidatorProvider), new RequiredMemberModelValidatorProvider(RequiredMemberSelector));
            }

            // create a action context for model binding
            HttpActionContext actionContext = new HttpActionContext
            {
                ControllerContext = new HttpControllerContext
                {
                    Configuration        = config,
                    ControllerDescriptor = new HttpControllerDescriptor
                    {
                        Configuration = config
                    }
                }
            };

            // create model binder context
            NameValuePairsValueProvider valueProvider    = new NameValuePairsValueProvider(data, CultureInfo.InvariantCulture);
            ModelMetadataProvider       metadataProvider = actionContext.ControllerContext.Configuration.Services.GetModelMetadataProvider();
            ModelMetadata       metadata            = metadataProvider.GetMetadataForType(null, type);
            ModelBindingContext modelBindingContext = new ModelBindingContext
            {
                ModelName             = string.Empty,
                FallbackToEmptyPrefix = false,
                ModelMetadata         = metadata,
                ModelState            = actionContext.ModelState,
                ValueProvider         = valueProvider
            };

            // bind model
            CompositeModelBinderProvider modelBinderProvider = new CompositeModelBinderProvider(config.Services.GetModelBinderProviders());
            IModelBinder binder     = modelBinderProvider.GetBinder(config, type);
            bool         haveResult = binder.BindModel(actionContext, modelBindingContext);

            // log validation errors
            if (formatterLogger != null)
            {
                foreach (KeyValuePair <string, ModelState> modelStatePair in actionContext.ModelState)
                {
                    foreach (ModelError modelError in modelStatePair.Value.Errors)
                    {
                        if (modelError.Exception != null)
                        {
                            formatterLogger.LogError(modelStatePair.Key, modelError.Exception);
                        }
                        else
                        {
                            formatterLogger.LogError(modelStatePair.Key, modelError.ErrorMessage);
                        }
                    }
                }
            }

            return(haveResult ? modelBindingContext.Model : GetDefaultValueForType(type));
        }
        void UpdateBindingInfo(ActionParameterContext context, ParameterDescriptor parameter)
        {
            var parameterType = parameter.ParameterType;
            var bindingInfo   = parameter.BindingInfo;

            if (bindingInfo == null || bindingInfo.BindingSource == null)
            {
                var metadata = ModelMetadataProvider.GetMetadataForType(parameterType);

                if (bindingInfo == null)
                {
                    parameter.BindingInfo = bindingInfo = new BindingInfo()
                    {
                        BindingSource = metadata.BindingSource
                    };
                }
                else
                {
                    bindingInfo.BindingSource = metadata.BindingSource;
                }
            }

            if (bindingInfo.BindingSource == Custom)
            {
                if (parameterType.IsODataQueryOptions() || parameterType.IsODataPath())
                {
                    bindingInfo.BindingSource = Special;
                }
            }

            if (bindingInfo.BindingSource != null)
            {
                return;
            }

            var key       = default(IEdmNamedElement);
            var paramName = parameter.Name;
            var source    = Query;

            switch (context.RouteContext.ActionType)
            {
            case EntitySet:

                var keys = context.RouteContext.EntitySet.EntityType().Key().ToArray();

                key = keys.FirstOrDefault(k => k.Name.Equals(paramName, OrdinalIgnoreCase));

                if (key == null)
                {
                    var template = context.Templates[0].PathTemplate;
                    var segments = template.Segments.OfType <KeySegmentTemplate>();

                    if (segments.SelectMany(s => s.ParameterMappings.Values).Any(name => name.Equals(paramName, OrdinalIgnoreCase)))
                    {
                        source = Path;
                    }
                }
                else
                {
                    source = Path;
                }

                break;

            case BoundOperation:
            case UnboundOperation:

                var operation = context.RouteContext.Operation;

                if (operation == null)
                {
                    break;
                }

                key = operation.Parameters.FirstOrDefault(p => p.Name.Equals(paramName, OrdinalIgnoreCase));

                if (key == null)
                {
                    if (operation.IsBound)
                    {
                        goto case EntitySet;
                    }
                }
                else
                {
                    source = Path;
                }

                break;
            }

            bindingInfo.BindingSource = source;
        }
        /// <summary>
        /// Deserialize the form data to the given type, using model binding.
        /// </summary>
        /// <param name="formData">collection with parsed form url data</param>
        /// <param name="type">target type to read as</param>
        /// <param name="modelName">null or empty to read the entire form as a single object. This is common for body data.
        /// <param name="requiredMemberSelector">The <see cref="IRequiredMemberSelector"/> used to determine required members.</param>
        /// <param name="formatterLogger">The <see cref="IFormatterLogger"/> to log events to.</param>
        /// Or the name of a model to do a partial binding against the form data. This is common for extracting individual fields.</param>
        /// <returns>best attempt to bind the object. The best attempt may be null.</returns>
        public static object ReadAs(this FormDataCollection formData, Type type, string modelName, IRequiredMemberSelector requiredMemberSelector, IFormatterLogger formatterLogger)
        {
            if (formData == null)
            {
                throw Error.ArgumentNull("formData");
            }
            if (type == null)
            {
                throw Error.ArgumentNull("type");
            }

            if (modelName == null)
            {
                modelName = string.Empty;
            }

            using (HttpConfiguration config = new HttpConfiguration())
            {
                bool validateRequiredMembers = requiredMemberSelector != null && formatterLogger != null;
                if (validateRequiredMembers)
                {
                    // Set a ModelValidatorProvider that understands the IRequiredMemberSelector
                    config.Services.Replace(typeof(ModelValidatorProvider), new RequiredMemberModelValidatorProvider(requiredMemberSelector));
                }

                // Looks like HttpActionContext is just a way of getting to the config, which we really
                // just need to get a list of modelbinderPRoviders for composition.
                HttpControllerContext controllerContext = new HttpControllerContext()
                {
                    Configuration = config
                };
                HttpActionContext actionContext = new HttpActionContext {
                    ControllerContext = controllerContext
                };

                ModelMetadataProvider metadataProvider = config.Services.GetModelMetadataProvider();

                // Create default over config
                IEnumerable <ModelBinderProvider> providers = config.Services.GetModelBinderProviders();
                ModelBinderProvider modelBinderProvider     = new CompositeModelBinderProvider(providers);

                IValueProvider vp = formData.GetJQueryValueProvider();

                ModelBindingContext ctx = new ModelBindingContext()
                {
                    ModelName             = modelName,
                    FallbackToEmptyPrefix = false,
                    ModelMetadata         = metadataProvider.GetMetadataForType(null, type),
                    ModelState            = actionContext.ModelState,
                    ValueProvider         = vp
                };

                IModelBinder binder = modelBinderProvider.GetBinder(actionContext, ctx);

                bool haveResult = binder.BindModel(actionContext, ctx);

                // Log model binding errors
                if (validateRequiredMembers)
                {
                    Contract.Assert(formatterLogger != null);
                    foreach (KeyValuePair <string, ModelState> modelStatePair in actionContext.ModelState)
                    {
                        foreach (ModelError modelError in modelStatePair.Value.Errors)
                        {
                            formatterLogger.LogError(modelStatePair.Key, modelError.ErrorMessage);
                        }
                    }
                }

                if (haveResult)
                {
                    return(ctx.Model);
                }
                return(null);
            }
        }
コード例 #15
0
        public MetadataOverrideScope(ModelMetadata metadata)
        {
            if (metadata == null)
            {
                throw new ArgumentNullException("metadata");
            }
            if (metadata.ModelType == null)
            {
                throw new ArgumentException("Need ModelType", "metadata");
            }

            _oldMetadataProvider = ModelMetadataProviders.Current;
            _metadata            = metadata;
            _modelType           = metadata.ModelType;

            // Mock a ModelMetadataProvider which delegates to the old one in most cases.  No need to special-case
            // GetMetadataForProperties() because product code uses it only within ModelMetadata.Properties and our
            // metadata instance will call _oldMetadataProvider there.
            var metadataProvider = new Mock <ModelMetadataProvider>();

            metadataProvider
            .Setup(p => p.GetMetadataForProperties(It.IsAny <object>(), It.IsAny <Type>()))
            .Returns(
                (object container, Type containerType) =>
                _oldMetadataProvider.GetMetadataForProperties(container, containerType)
                );
            metadataProvider
            .Setup(p => p.GetMetadataForType(It.IsAny <Func <object> >(), It.IsAny <Type>()))
            .Returns(
                (Func <object> modelAccessor, Type modelType) =>
                _oldMetadataProvider.GetMetadataForType(modelAccessor, modelType)
                );

            // When metadata for _modelType is requested, then return a clone of the provided metadata instance.
            // GetMetadataForProperty() is important because the static discovery methods (e.g.
            // ModelMetadata.FromLambdaExpression) use it.
            metadataProvider
            .Setup(p => p.GetMetadataForType(It.IsAny <Func <object> >(), _modelType))
            .Returns(
                (Func <object> modelAccessor, Type modelType) =>
                GetMetadataForType(modelAccessor, modelType)
                );
            metadataProvider
            .Setup(
                p =>
                p.GetMetadataForProperty(
                    It.IsAny <Func <object> >(),
                    It.IsAny <Type>(),
                    It.IsAny <string>()
                    )
                )
            .Returns(
                (Func <object> modelAccessor, Type containerType, string propertyName) =>
                GetMetadataForProperty(modelAccessor, containerType, propertyName)
                );

            // Calls to GetMetadataForProperties for the modelType are incorrect because _metadata.Provider must
            // reference _oldMetadataProvider and not this mock.
            metadataProvider
            .Setup(
                p =>
                p.GetMetadataForProperty(
                    It.IsAny <Func <object> >(),
                    _modelType,
                    It.IsAny <string>()
                    )
                )
            .Throws <InvalidOperationException>();

            // Finally make our ModelMetadataProvider visible everywhere.
            ModelMetadataProviders.Current = metadataProvider.Object;
        }
コード例 #16
0
 public override ModelMetadata GetMetadataForType(Func <object> modelAccessor, Type modelType)
 {
     return(_innerProvider.GetMetadataForType(modelAccessor, modelType));
 }
 public static ModelMetadata CollectionModelMetadata <T>(this ViewDataDictionary viewData, ModelMetadataProvider provider)
 {
     return(provider.GetMetadataForType(typeof(T)));
 }
        public static ModelMetadata CollectionModelMetadata(this ViewDataDictionary viewData, ModelMetadataProvider provider)
        {
            var type = viewData.ModelMetadata.ModelType.GenericTypeArguments.FirstOrDefault();

            return(provider.GetMetadataForType(type));
        }