// 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; using System.Collections.Generic; using System.ComponentModel; using System.Reflection; using Microsoft.AspNet.Mvc.ModelBinding.Metadata; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { /// /// A metadata representation of a model type, property or parameter. /// public abstract class ModelMetadata { private bool? _isComplexType; /// /// The default value of . /// public static readonly int DefaultOrder = 10000; /// /// Creates a new . /// /// The . protected ModelMetadata([NotNull] ModelMetadataIdentity identity) { Identity = identity; } /// /// Gets the container type of this metadata if it represents a property, otherwise null. /// public Type ContainerType { get { return Identity.ContainerType; } } /// /// Gets a value indicating the kind of metadata element represented by the current instance. /// public ModelMetadataKind MetadataKind { get { return Identity.MetadataKind; } } /// /// Gets the model type represented by the current instance. /// public Type ModelType { get { return Identity.ModelType; } } /// /// Gets the property name represented by the current instance. /// public string PropertyName { get { return Identity.Name; } } /// /// Gets the key for the current instance. /// protected ModelMetadataIdentity Identity { get; } /// /// Gets a collection of additional information about the model. /// public abstract IReadOnlyDictionary AdditionalValues { get; } /// /// Gets the collection of instances for the model's properties. /// public abstract ModelPropertyCollection Properties { get; } /// /// Gets the name of a model if specified explicitly using . /// public abstract string BinderModelName { get; } /// /// Gets the of an of a model if specified explicitly using /// . /// public abstract Type BinderType { get; } /// /// Gets a binder metadata for this model. /// public abstract BindingSource BindingSource { get; } /// /// Gets a value indicating whether or not to convert an empty string value to null when /// representing a model as text. /// public abstract bool ConvertEmptyStringToNull { get; } /// /// Gets the name of the model's datatype. Overrides in some /// display scenarios. /// /// null unless set manually or through additional metadata e.g. attributes. public abstract string DataTypeName { get; } /// /// Gets the description of the model. /// public abstract string Description { get; } /// /// Gets the composite format (see /// http://msdn.microsoft.com/en-us/library/txafckwd.aspx) used to display the model. /// public abstract string DisplayFormatString { get; } /// /// Gets the display name of the model. /// public abstract string DisplayName { get; } /// /// Gets the composite format (see /// http://msdn.microsoft.com/en-us/library/txafckwd.aspx) used to edit the model. /// public abstract string EditFormatString { get; } /// /// Gets the for elements of if that /// implements . /// /// /// for T if implements /// . for object if /// implements but not . null otherwise i.e. when /// is false. /// public abstract ModelMetadata ElementMetadata { get; } /// /// Gets the ordered display names and values of all values in /// . /// /// /// An of mappings between field names /// and values. null if is false. /// public abstract IEnumerable> EnumDisplayNamesAndValues { get; } /// /// Gets the names and values of all values in . /// /// /// An of mappings between field names /// and values. null if is false. /// public abstract IReadOnlyDictionary EnumNamesAndValues { get; } /// /// Gets a value indicating whether has a non-null, non-empty /// value different from the default for the datatype. /// public abstract bool HasNonDefaultEditFormat { get; } /// /// Gets a value indicating whether the value should be HTML-encoded. /// /// If true, value should be HTML-encoded. Default is true. public abstract bool HtmlEncode { get; } /// /// Gets a value indicating whether the "HiddenInput" display template should return /// string.Empty (not the expression value) and whether the "HiddenInput" editor template should not /// also return the expression value (together with the hidden <input> element). /// /// /// If true, also causes the default display and editor templates to return HTML /// lacking the usual per-property <div> wrapper around the associated property. Thus the default /// display template effectively skips the property and the default /// editor template returns only the hidden <input> element for the property. /// public abstract bool HideSurroundingHtml { get; } /// /// Gets a value indicating whether or not the model value can be bound by model binding. This is only /// applicable when the current instance represents a property. /// /// /// If true then the model value is considered supported by model binding and can be set /// based on provided input in the request. /// public abstract bool IsBindingAllowed { get; } /// /// Gets a value indicating whether or not the model value is required by model binding. This is only /// applicable when the current instance represents a property. /// /// /// If true then the model value is considered required by model binding and must have a value /// supplied in the request to be considered valid. /// public abstract bool IsBindingRequired { get; } /// /// Gets a value indicating whether is for an . /// /// /// true if type.IsEnum (type.GetTypeInfo().IsEnum for DNX Core 5.0) is true for /// ; false otherwise. /// public abstract bool IsEnum { get; } /// /// Gets a value indicating whether is for an with an /// associated . /// /// /// true if is true and has an /// associated ; false otherwise. /// public abstract bool IsFlagsEnum { get; } /// /// Gets a value indicating whether or not the model value is read-only. This is only applicable when /// the current instance represents a property. /// public abstract bool IsReadOnly { get; } /// /// Gets a value indicating whether or not the model value is required. This is only applicable when /// the current instance represents a property. /// /// /// /// If true then the model value is considered required by validators. /// /// /// By default an implicit System.ComponentModel.DataAnnotations.RequiredAttribute will be added /// if not present when true.. /// /// public abstract bool IsRequired { get; } /// /// Gets a value indicating where the current metadata should be ordered relative to other properties /// in its containing type. /// /// /// For example this property is used to order items in . /// The default order is 10000. /// /// The order value of the current metadata. public abstract int Order { get; } /// /// Gets the text to display when the model is null. /// public abstract string NullDisplayText { get; } /// /// Gets the , which can determine which properties /// should be model bound. /// public abstract IPropertyBindingPredicateProvider PropertyBindingPredicateProvider { get; } /// /// Gets a value that indicates whether the property should be displayed in read-only views. /// public abstract bool ShowForDisplay { get; } /// /// Gets a value that indicates whether the property should be displayed in editable views. /// public abstract bool ShowForEdit { get; } /// /// Gets a value which is the name of the property used to display the model. /// public abstract string SimpleDisplayProperty { get; } /// /// Gets a string used by the templating system to discover display-templates and editor-templates. /// public abstract string TemplateHint { get; } /// /// Gets a collection of metadata items for validators. /// public abstract IReadOnlyList ValidatorMetadata { get; } /// /// Gets a value indicating whether is a simple type. /// /// /// A simple type is defined as a which has a /// that can convert from . /// public bool IsComplexType { get { if (_isComplexType == null) { _isComplexType = !TypeDescriptor.GetConverter(ModelType).CanConvertFrom(typeof(string)); } return _isComplexType.Value; } } /// /// Gets a value indicating whether or not is a . /// public bool IsNullableValueType { get { return Nullable.GetUnderlyingType(ModelType) != null; } } /// /// Gets a value indicating whether or not is a collection type. /// /// /// A collection type is defined as a which is assignable to /// , and is not a . /// public bool IsCollectionType { 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); } } /// /// Gets a value indicating whether or not allows null values. /// public bool IsReferenceOrNullableType { get { return !ModelType.GetTypeInfo().IsValueType || IsNullableValueType; } } /// /// Gets the underlying type argument if inherits from . /// Otherwise gets . /// /// /// Identical to unless is true. /// public Type UnderlyingOrModelType { get { return Nullable.GetUnderlyingType(ModelType) ?? ModelType; } } /// /// Gets a property getter delegate to get the property value from a model object. /// public abstract Func PropertyGetter { get; } /// /// Gets a property setter delegate to set the property value on a model object. /// public abstract Action PropertySetter { get; } /// /// Gets a display name for the model. /// /// /// will return the first of the following expressions which has a /// non-null value: DisplayName, PropertyName, ModelType.Name. /// /// The display name. public string GetDisplayName() { return DisplayName ?? PropertyName ?? ModelType.Name; } } }