模型扩展

/****************************注册元数据*******************************************/

using System.Web.Mvc;
using WebApplication2.Areas.FluentMetadata.Models;
using WebApplication2.Areas.FluentMetadata.Utility;

namespace WebApplication2.Areas.FluentMetadata
{
    public class FluentMetadataAreaRegistration : AreaRegistration
    {
        public override string AreaName { get { return "FluentMetadata"; } }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "FluentMetadata_default",
                "FluentMetadata/{action}/{id}",
                new { controller = "FluentMetadata", action = "Index", id = UrlParameter.Optional }
            );

            ModelMetadataProviders.Current =
                new FluentMetadataProvider()
                    .ForModel<Contact>()
                        .ForProperty(m => m.FirstName)
                            .DisplayName("First Name")
                            .DataTypeName("string")
                        .ForProperty(m => m.LastName)
                            .DisplayName("Last Name")
                            .DataTypeName("string")
                        .ForProperty(m => m.EmailAddress)
                            .DisplayName("E-mail Address")
                            .DataTypeName("email");
        }
    }
}

/*******************************元数据提供器************************************/

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web.Mvc;

namespace WebApplication2.Areas.FluentMetadata.Utility
{
    public class FluentMetadataProvider : DataAnnotationsModelMetadataProvider
    {
        // This dictionary is a mapping from incoming metadata request to a list of
        // functions which will modify the metadata. The incoming metadata request
        // might be for just a type (so, getting metadata on a class), in which case
        // the key tuple will contain the type and a null value for the string; if
        // the incoming request is for a property, then the key tuple will contain
        // the container type and the name of the property.
        ConcurrentDictionary<Tuple<Type, string>, List<Action<ModelMetadata>>> modifiers
            = new ConcurrentDictionary<Tuple<Type, string>, List<Action<ModelMetadata>>>();

        protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes,
                                                        Type containerType,
                                                        Func<object> modelAccessor,
                                                        Type modelType,
                                                        string propertyName)
        {
            // We've derived from DataAnnotationsModelMetadataProvider so that we can
            // mix both attribute-based metadata and the fluent metadata. We want the
            // fluent metadata to override the attributes, so we start by calling the
            // base CreateMetadata method so we can get those values.
            ModelMetadata metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);

            // Next, we determine the request type. If the property name is null, then
            // we're being asked for model-level metadata; otherwise, we're being asked
            // for property-level metadata. We make a tuple which matches the type of
            // request we're being asked to perform.
            Tuple<Type, string> key = propertyName == null ? new Tuple<Type, string>(modelType, null)
                                                            : new Tuple<Type, string>(containerType, propertyName);

            // If we have any modifier functions that match the requested key tuple, then
            // we'll loop over them and run them all.
            List<Action<ModelMetadata>> modifierList;
            if (modifiers.TryGetValue(key, out modifierList))
                foreach (Action<ModelMetadata> modifier in modifierList)
                    modifier(metadata);

            return metadata;
        }

        // This method is called by the registrar class so that it can add modification
        // actions to the given registration.
        private void Add(Type type, string propertyName, Action<ModelMetadata> modifier)
        {
            modifiers.GetOrAdd(
                new Tuple<Type, string>(type, propertyName),
                _ => new List<Action<ModelMetadata>>()
            ).Add(modifier);
        }

        // This method is called by the developer to get an instance of the registrar which
        // can be used to record model-level metadata changes.
        public MetadataRegistrar<TModel> ForModel<TModel>()
        {
            return new MetadataRegistrar<TModel>(this);
        }

        // The MetadataRegistrar class is the core type that records registrations. It
        // contains methods which add actions to the provider list which modify the
        // metadata object appropriately. Because this is a fluent API, we always return
        // an instance of ourselves so that we can chain calls together.
        public class MetadataRegistrar<TModel>
        {
            FluentMetadataProvider provider;
            string propertyName;

            public MetadataRegistrar(FluentMetadataProvider provider, string propertyName = null)
            {
                this.provider = provider;
                this.propertyName = propertyName;
            }

            public MetadataRegistrar<TModel> ConvertEmptyStringToNull(bool convertEmptyStringToNull)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.ConvertEmptyStringToNull = convertEmptyStringToNull);
                return this;
            }

            public MetadataRegistrar<TModel> DataTypeName(string dataTypeName)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.DataTypeName = dataTypeName);
                return this;
            }

            public MetadataRegistrar<TModel> Description(string description)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.Description = description);
                return this;
            }

            public MetadataRegistrar<TModel> DisplayFormatString(string displayFormatString)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.DisplayFormatString = displayFormatString);
                return this;
            }

            public MetadataRegistrar<TModel> DisplayName(string displayName)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.DisplayName = displayName);
                return this;
            }

            public MetadataRegistrar<TModel> EditFormatString(string editFormatString)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.EditFormatString = editFormatString);
                return this;
            }

            public MetadataRegistrar<TModel> HideSurroundingHtml(bool hideSurroundingHtml)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.HideSurroundingHtml = hideSurroundingHtml);
                return this;
            }

            public MetadataRegistrar<TModel> IsReadOnly(bool isReadOnly)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.IsReadOnly = isReadOnly);
                return this;
            }

            public MetadataRegistrar<TModel> NullDisplayText(string nullDisplayText)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.NullDisplayText = nullDisplayText);
                return this;
            }

            public MetadataRegistrar<TModel> ShortDisplayName(string shortDisplayName)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.ShortDisplayName = shortDisplayName);
                return this;
            }

            public MetadataRegistrar<TModel> ShowForDisplay(bool showForDisplay)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.ShowForDisplay = showForDisplay);
                return this;
            }

            public MetadataRegistrar<TModel> ShowForEdit(bool showForEdit)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.ShowForEdit = showForEdit);
                return this;
            }

            public MetadataRegistrar<TModel> SimpleDisplayText(string simpleDisplayText)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.SimpleDisplayText = simpleDisplayText);
                return this;
            }

            public MetadataRegistrar<TModel> TemplateHint(string templateHint)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.TemplateHint = templateHint);
                return this;
            }

            public MetadataRegistrar<TModel> Watermark(string watermark)
            {
                provider.Add(typeof(TModel), propertyName, metadata => metadata.Watermark = watermark);
                return this;
            }

            // Support implicit conversion back to the provider, so that the user can create,
            // configure, and register the provider with a single line of code.
            public static implicit operator FluentMetadataProvider(MetadataRegistrar<TModel> registrar)
            {
                return registrar.provider;
            }

            // This method is like ForModel above, except that it lets the developer transition
            // to a new model without needing to go back to the registrar itself.
            public MetadataRegistrar<TNewModel> ForModel<TNewModel>()
            {
                return new MetadataRegistrar<TNewModel>(provider);
            }

            // This method is called by the developer to get an instance of the registrar which
            // can be used to record property-level metadata changes. We use Expression<T> here
            // so that the user can get Intellisense for the property expression, and also so
            // that their registration code can support refactoring operations like renaming
            // properties on models.
            public MetadataRegistrar<TModel> ForProperty(Expression<Func<TModel, object>> expression)
            {
                return new MetadataRegistrar<TModel>(provider, ExpressionToPropertyName(expression));
            }

            // This helper method extracts the property name from the Expression<T>
            private static string ExpressionToPropertyName(Expression<Func<TModel, object>> expression)
            {
                Expression body = expression.Body;

                UnaryExpression unaryExpression = body as UnaryExpression;
                if (unaryExpression != null && unaryExpression.NodeType == ExpressionType.Convert)  // Boxing value type to object
                    body = unaryExpression.Operand;

                MemberExpression memberExpression = (MemberExpression)body;
                return memberExpression.Member.Name;
            }
        }
    }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值