// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; namespace Microsoft.AspNet.Mvc.ModelBinding { // This class assumes that model metadata is expensive to create, and allows the user to // stash a cache object that can be copied around as a prototype to make creation and // computation quicker. It delegates the retrieval of values to getter methods, the results // of which are cached on a per-metadata-instance basis. // // This allows flexible caching strategies: either caching the source of information across // instances or caching of the actual information itself, depending on what the developer // decides to put into the prototype cache. public abstract class CachedModelMetadata : ModelMetadata { private bool _convertEmptyStringToNull; private string _dataTypeName; private string _description; private string _displayFormatString; private string _displayName; private string _editFormatString; private bool _hasNonDefaultEditFormat; private bool _hideSurroundingHtml; private bool _htmlEncode; private bool _isReadOnly; private bool _isComplexType; private bool _isRequired; private string _nullDisplayText; private int _order; private bool _showForDisplay; private bool _showForEdit; private IBinderMetadata _binderMetadata; private string _binderModelName; private IPropertyBindingPredicateProvider _propertyBindingPredicateProvider; private Type _binderType; private bool _convertEmptyStringToNullComputed; private bool _dataTypeNameComputed; private bool _descriptionComputed; private bool _displayFormatStringComputed; private bool _displayNameComputed; private bool _editFormatStringComputed; private bool _hasNonDefaultEditFormatComputed; private bool _hideSurroundingHtmlComputed; private bool _htmlEncodeComputed; private bool _isReadOnlyComputed; private bool _isComplexTypeComputed; private bool _isRequiredComputed; private bool _nullDisplayTextComputed; private bool _orderComputed; private bool _showForDisplayComputed; private bool _showForEditComputed; private bool _isBinderMetadataComputed; private bool _isBinderModelNameComputed; private bool _isBinderTypeComputed; private bool _propertyBindingPredicateProviderComputed; // Constructor for creating real instances of the metadata class based on a prototype protected CachedModelMetadata(CachedModelMetadata prototype, Func modelAccessor) : base(prototype.Provider, prototype.ContainerType, modelAccessor, prototype.ModelType, prototype.PropertyName) { CacheKey = prototype.CacheKey; PrototypeCache = prototype.PrototypeCache; _isComplexType = prototype.IsComplexType; _isComplexTypeComputed = true; } // Constructor for creating the prototype instances of the metadata class protected CachedModelMetadata(DataAnnotationsModelMetadataProvider provider, Type containerType, Type modelType, string propertyName, TPrototypeCache prototypeCache) : base(provider, containerType, modelAccessor: null, modelType: modelType, propertyName: propertyName) { PrototypeCache = prototypeCache; } // Sealing for consistency with other properties. // ModelMetadata already caches the collection and we have no use case for a ComputeAdditionalValues() method. /// public sealed override IDictionary AdditionalValues { get { return base.AdditionalValues; } } /// public sealed override IBinderMetadata BinderMetadata { get { if (!_isBinderMetadataComputed) { _binderMetadata = ComputeBinderMetadata(); _isBinderMetadataComputed = true; } return _binderMetadata; } set { _binderMetadata = value; _isBinderMetadataComputed = true; } } /// public sealed override string BinderModelName { get { if (!_isBinderModelNameComputed) { _binderModelName = ComputeBinderModelNamePrefix(); _isBinderModelNameComputed = true; } return _binderModelName; } set { _binderModelName = value; _isBinderModelNameComputed = true; } } /// public sealed override bool ConvertEmptyStringToNull { get { if (!_convertEmptyStringToNullComputed) { _convertEmptyStringToNull = ComputeConvertEmptyStringToNull(); _convertEmptyStringToNullComputed = true; } return _convertEmptyStringToNull; } set { _convertEmptyStringToNull = value; _convertEmptyStringToNullComputed = true; } } /// public sealed override string DataTypeName { get { if (!_dataTypeNameComputed) { _dataTypeName = ComputeDataTypeName(); _dataTypeNameComputed = true; } return _dataTypeName; } set { _dataTypeName = value; _dataTypeNameComputed = true; } } /// public sealed override string Description { get { if (!_descriptionComputed) { _description = ComputeDescription(); _descriptionComputed = true; } return _description; } set { _description = value; _descriptionComputed = true; } } /// public sealed override string DisplayFormatString { get { if (!_displayFormatStringComputed) { _displayFormatString = ComputeDisplayFormatString(); _displayFormatStringComputed = true; } return _displayFormatString; } set { _displayFormatString = value; _displayFormatStringComputed = true; } } /// public sealed override string DisplayName { get { if (!_displayNameComputed) { _displayName = ComputeDisplayName(); _displayNameComputed = true; } return _displayName; } set { _displayName = value; _displayNameComputed = true; } } /// public sealed override string EditFormatString { get { if (!_editFormatStringComputed) { _editFormatString = ComputeEditFormatString(); _editFormatStringComputed = true; } return _editFormatString; } set { _editFormatString = value; _editFormatStringComputed = true; } } /// public sealed override bool HasNonDefaultEditFormat { get { if (!_hasNonDefaultEditFormatComputed) { _hasNonDefaultEditFormat = ComputeHasNonDefaultEditFormat(); _hasNonDefaultEditFormatComputed = true; } return _hasNonDefaultEditFormat; } set { _hasNonDefaultEditFormat = value; _hasNonDefaultEditFormatComputed = true; } } /// public sealed override bool HideSurroundingHtml { get { if (!_hideSurroundingHtmlComputed) { _hideSurroundingHtml = ComputeHideSurroundingHtml(); _hideSurroundingHtmlComputed = true; } return _hideSurroundingHtml; } set { _hideSurroundingHtml = value; _hideSurroundingHtmlComputed = true; } } /// public sealed override bool HtmlEncode { get { if (!_htmlEncodeComputed) { _htmlEncode = ComputeHtmlEncode(); _htmlEncodeComputed = true; } return _htmlEncode; } set { _htmlEncode = value; _htmlEncodeComputed = true; } } /// public sealed override bool IsReadOnly { get { if (!_isReadOnlyComputed) { _isReadOnly = ComputeIsReadOnly(); _isReadOnlyComputed = true; } return _isReadOnly; } set { _isReadOnly = value; _isReadOnlyComputed = true; } } /// public sealed override bool IsRequired { get { if (!_isRequiredComputed) { _isRequired = ComputeIsRequired(); _isRequiredComputed = true; } return _isRequired; } set { _isRequired = value; _isRequiredComputed = true; } } /// public sealed override bool IsComplexType { get { if (!_isComplexTypeComputed) { _isComplexType = ComputeIsComplexType(); _isComplexTypeComputed = true; } return _isComplexType; } } /// public sealed override string NullDisplayText { get { if (!_nullDisplayTextComputed) { _nullDisplayText = ComputeNullDisplayText(); _nullDisplayTextComputed = true; } return _nullDisplayText; } set { _nullDisplayText = value; _nullDisplayTextComputed = true; } } /// public sealed override int Order { get { if (!_orderComputed) { _order = ComputeOrder(); _orderComputed = true; } return _order; } set { _order = value; _orderComputed = true; } } public sealed override IPropertyBindingPredicateProvider PropertyBindingPredicateProvider { get { if (!_propertyBindingPredicateProviderComputed) { _propertyBindingPredicateProvider = ComputePropertyBindingPredicateProvider(); _propertyBindingPredicateProviderComputed = true; } return _propertyBindingPredicateProvider; } set { _propertyBindingPredicateProvider = value; _propertyBindingPredicateProviderComputed = true; } } // Sealing for consistency with other properties. // ModelMetadata already caches the collection and we have no use case for a ComputeProperties() method. /// public override ModelPropertyCollection Properties { get { return base.Properties; } } /// public sealed override bool ShowForDisplay { get { if (!_showForDisplayComputed) { _showForDisplay = ComputeShowForDisplay(); _showForDisplayComputed = true; } return _showForDisplay; } set { _showForDisplay = value; _showForDisplayComputed = true; } } /// public sealed override bool ShowForEdit { get { if (!_showForEditComputed) { _showForEdit = ComputeShowForEdit(); _showForEditComputed = true; } return _showForEdit; } set { _showForEdit = value; _showForEditComputed = true; } } /// public sealed override string SimpleDisplayText { get { // Value already cached in ModelMetadata. That class also already exposes ComputeSimpleDisplayText() // for overrides. Sealed here for consistency with other properties. return base.SimpleDisplayText; } set { base.SimpleDisplayText = value; } } /// public sealed override Type BinderType { get { if (!_isBinderTypeComputed) { _binderType = ComputeBinderType(); _isBinderTypeComputed = true; } return _binderType; } set { _binderType = value; _isBinderTypeComputed = true; } } protected TPrototypeCache PrototypeCache { get; set; } protected virtual Type ComputeBinderType() { return base.BinderType; } protected virtual IBinderMetadata ComputeBinderMetadata() { return base.BinderMetadata; } protected virtual IPropertyBindingPredicateProvider ComputePropertyBindingPredicateProvider() { return base.PropertyBindingPredicateProvider; } protected virtual string ComputeBinderModelNamePrefix() { return base.BinderModelName; } protected virtual bool ComputeConvertEmptyStringToNull() { return base.ConvertEmptyStringToNull; } /// /// Calculate the value. /// /// Calculated value. protected virtual string ComputeDataTypeName() { return base.DataTypeName; } protected virtual string ComputeDescription() { return base.Description; } /// /// Calculate the value. /// /// Calculated value. protected virtual string ComputeDisplayFormatString() { return base.DisplayFormatString; } protected virtual string ComputeDisplayName() { return base.DisplayName; } /// /// Calculate the value. /// /// Calculated value. protected virtual string ComputeEditFormatString() { return base.EditFormatString; } /// /// Calculate the value. /// /// Calculated value. protected virtual bool ComputeHasNonDefaultEditFormat() { return base.HasNonDefaultEditFormat; } /// /// Calculate the value. /// /// Calculated value. protected virtual bool ComputeHideSurroundingHtml() { return base.HideSurroundingHtml; } /// /// Calculate the value. /// /// Calculated value. protected virtual bool ComputeHtmlEncode() { return base.HtmlEncode; } protected virtual bool ComputeIsReadOnly() { return base.IsReadOnly; } protected virtual bool ComputeIsRequired() { return base.IsRequired; } protected virtual bool ComputeIsComplexType() { return base.IsComplexType; } /// /// Calculate the value. /// /// Calculated value. protected virtual string ComputeNullDisplayText() { return base.NullDisplayText; } /// /// Calculate the value. /// /// Calculated value. protected virtual int ComputeOrder() { return base.Order; } protected virtual bool ComputeShowForDisplay() { return base.ShowForDisplay; } protected virtual bool ComputeShowForEdit() { return base.ShowForEdit; } } }