zoukankan      html  css  js  c++  java
  • asp.net mvc源码分析Controller篇 ValueProvider

    在上篇文章asp.net mvc源码分析-Action篇 IModelBinder中我们提到了ValueProvider,其实这个东西是Controller的属性,在写前面Controller的是曾打算把它写书来,后来有以下在后面用的时候在写它相关的东东吧,需求才能推动发展啊。先说明一下这个属性石很重要的,Action参数的值最总都是通过它来获取的。

       public IValueProvider ValueProvider {
                get {
                    if (_valueProvider == null) {
                        _valueProvider = ValueProviderFactories.Factories.GetValueProvider(ControllerContext);
                    }
                    return _valueProvider;
                }
                set {
                    _valueProvider = value;
                }
            }

    想让我们看看ValueProviderFactories类是个什么东东

     public static class ValueProviderFactories {

            private static readonly ValueProviderFactoryCollection _factories = new ValueProviderFactoryCollection() {
                new ChildActionValueProviderFactory(),
                new FormValueProviderFactory(),
                new JsonValueProviderFactory(),
                new RouteDataValueProviderFactory(),
                new QueryStringValueProviderFactory(),
                new HttpFileCollectionValueProviderFactory(),

            };


            public static ValueProviderFactoryCollection Factories {
                get {
                    return _factories;
                }
            }

        }

    看来 默认就跟我们加了6个ProviderFactory啊,这个顺序很重要。

            public IValueProvider GetValueProvider(ControllerContext controllerContext) {
                var valueProviders = from factory in _serviceResolver.Current
                                     let valueProvider = factory.GetValueProvider(controllerContext)
                                     where valueProvider != null
                                     select valueProvider;

                return new ValueProviderCollection(valueProviders.ToList());
            }

    GetValueProvider这个返回的是一个ValueProvider集合类ValueProviderCollection,所以我认为这个方法名应该加个s改为GetValueProviders。这里的_serviceResolver.Current就是我们默认的那6个ProviderFactory

    其中 除JsonValueProviderFactory 有点特殊,其他的几个只要controllerContext有效都能返回valueProvider ,他们的valueProvider 类型依次对应如下:

    ChildActionValueProviderFactory           ->ChildActionValueProvider
    FormValueProviderFactory                      ->FormValueProvider
    RouteDataValueProviderFactory             ->RouteDataValueProvider
    QueryStringValueProviderFactory           ->QueryStringValueProvider
    HttpFileCollectionValueProviderFactory->HttpFileCollectionValueProvider

    而 JsonValueProviderFactory 除了要验证controllerContext数据是否有效还需要验证 json格式是否正确,所以它直接返回了一个类DictionaryValueProvider<object>

    这里的每个ValueProvider实例类我们就不用管了,太细节了。

    现在我们就可以得到一个ValueProviderCollection,它有一个很有用的方法

      public virtual ValueProviderResult GetValue(string key) {
                return GetValue(key, skipValidation: false);
            }

            public virtual ValueProviderResult GetValue(string key, bool skipValidation) {
                return (from provider in this
                        let result = GetValueFromProvider(provider, key, skipValidation)
                        where result != null
                        select result).FirstOrDefault();
            }
    从先前得到的ValueProvider依次待用他们的GetValue方法,返回了一个不含ValueProviderResult为空的ValueProviderResult集合,最总返回这个集合中的第一个ValueProviderResult。

            internal static ValueProviderResult GetValueFromProvider(IValueProvider provider, string key, bool skipValidation) {
                // Since IUnvalidatedValueProvider is a superset of IValueProvider, it's always OK to use the
                // IUnvalidatedValueProvider-supplied members if they're present. Otherwise just call the
                // normal IValueProvider members.

                IUnvalidatedValueProvider unvalidatedProvider = provider as IUnvalidatedValueProvider;
                return (unvalidatedProvider != null) ? unvalidatedProvider.GetValue(key, skipValidation) : provider.GetValue(key);

            }

    为什么会出现上面provider as IUnvalidatedValueProvider这样的代码了?因为前面提到的

    QueryStringValueProvider、NameValueCollectionValueProvider都继承与NameValueCollectionValueProvider

     public class NameValueCollectionValueProvider : IValueProvider, IUnvalidatedValueProvider 
    而ChildActionValueProvider、RouteDataValueProvider、HttpFileCollectionValueProvider却继承与DictionaryValueProvider
     public class DictionaryValueProvider<TValue> : IValueProvider

    NameValueCollectionValueProvider的主要方法如下:

    private void AddValues(NameValueCollection validatedCollection, NameValueCollection unvalidatedCollection, CultureInfo culture) {
                // Need to read keys from the unvalidated collection, as M.W.I's granular request validation is a bit touchy
                // and validated entries at the time the key or value is looked at. For example, GetKey() will throw if the
                // value fails request validation, even though the value's not being looked at (M.W.I can't tell the difference).
    
                if (unvalidatedCollection.Count > 0) {
                    _prefixes.Add("");
                }
    
                foreach (string key in unvalidatedCollection) {
                    if (key != null) {
                        _prefixes.UnionWith(ValueProviderUtil.GetPrefixes(key));
    
                        // need to look up values lazily, as eagerly looking at the collection might trigger validation
                        _values[key] = new ValueProviderResultPlaceholder(key, validatedCollection, unvalidatedCollection, culture);
                    }
                }
            }
     public virtual ValueProviderResult GetValue(string key, bool skipValidation) {
                if (key == null) {
                    throw new ArgumentNullException("key");
                }
    
                ValueProviderResultPlaceholder placeholder;
                _values.TryGetValue(key, out placeholder);
                if (placeholder == null) {
                    return null;
                }
                else {
                    return (skipValidation) ? placeholder.UnvalidatedResult : placeholder.ValidatedResult;
                }
            }
    

     而DictionaryValueProvider的主要方法:

     private void AddValues(IDictionary<string, TValue> dictionary, CultureInfo culture) {
                if (dictionary.Count > 0) {
                    _prefixes.Add("");
                }
    
                foreach (var entry in dictionary) {
                    _prefixes.UnionWith(ValueProviderUtil.GetPrefixes(entry.Key));
    
                    object rawValue = entry.Value;
                    string attemptedValue = Convert.ToString(rawValue, culture);
                    _values[entry.Key] = new ValueProviderResult(rawValue, attemptedValue, culture);
                }
            }
     public virtual ValueProviderResult GetValue(string key) {
                if (key == null) {
                    throw new ArgumentNullException("key");
                }
    
                ValueProviderResult vpResult;
                _values.TryGetValue(key, out vpResult);
                return vpResult;
            }
    

      充这里可以看到ValueProviderResultPlaceholder是一个ValueProviderResult的包装类,使其数据实现延迟加载

     private sealed class ValueProviderResultPlaceholder {
                private readonly Lazy<ValueProviderResult> _validatedResultPlaceholder;
                private readonly Lazy<ValueProviderResult> _unvalidatedResultPlaceholder;
    
                public ValueProviderResultPlaceholder(string key, NameValueCollection validatedCollection, NameValueCollection unvalidatedCollection, CultureInfo culture) {
                    _validatedResultPlaceholder = new Lazy<ValueProviderResult>(() => GetResultFromCollection(key, validatedCollection, culture), LazyThreadSafetyMode.None);
                    _unvalidatedResultPlaceholder = new Lazy<ValueProviderResult>(() => GetResultFromCollection(key, unvalidatedCollection, culture), LazyThreadSafetyMode.None);
                }
    
                private static ValueProviderResult GetResultFromCollection(string key, NameValueCollection collection, CultureInfo culture) {
                    string[] rawValue = collection.GetValues(key);
                    string attemptedValue = collection[key];
                    return new ValueProviderResult(rawValue, attemptedValue, culture);
                }
    
                public ValueProviderResult ValidatedResult {
                    get { return _validatedResultPlaceholder.Value; }
                }
    
                public ValueProviderResult UnvalidatedResult {
                    get { return _unvalidatedResultPlaceholder.Value; }
                }
            }
    

      具体其他的什么细节之处我就不提了。在项目中我们往往要实现自己ValueProviderFactory,那么我们需要怎么注册它了在 Application_Start()加入ValueProviderFactories.Factories.Add(xxxx)。
    我们举一个demo来说说怎么用的吧

    public class CookieValueProviderFactory : ValueProviderFactory
        {
            public CookieValueProviderFactory() { }
            public override IValueProvider GetValueProvider(ControllerContext controllerContext)
            {
                if (controllerContext == null)
                {
                    throw new ArgumentNullException("controllerContext");
                }
                return new CookieValueProvider(controllerContext);
            }
        }
        public class CookieValueProvider : NameValueCollectionValueProvider
        {
            public CookieValueProvider(ControllerContext controllerContext) :
                base(GetCookies(controllerContext), CultureInfo.InvariantCulture)
            { }
    
            static NameValueCollection GetCookies(ControllerContext controllerContext)
            {
                NameValueCollection data = new NameValueCollection();
                foreach (string key in controllerContext.HttpContext.Request.Cookies.AllKeys)
                {
                    data.Add(key, controllerContext.HttpContext.Request.Cookies[key].Value);
                }
                return data;
            }
        }
     public class HomeController : Controller
        {
          
            public ActionResult Index(string name)
            {
                if (string.IsNullOrEmpty(name))
                {
                    Response.Cookies.Add(new HttpCookie("name", "majiang"));
                    return Content("写入cookie");
                }
                else
                {
                    return Content("读取cookie:"+name);
                }
                
            }
         
        }
       
    

      在Application_Start中加入ValueProviderFactories.Factories.Add(new CookieValueProviderFactory());

    两次运行结果如图:

  • 相关阅读:
    web服务webserver
    java:Comparator比较器
    6递归
    5.二分查找 = 折半查找
    4.线性查找 = 顺序查找
    3选择排序
    2.冒泡排序----还是不懂,先记录下来
    1交换算法
    调试篇
    sql表合并,统计计算,生成总计
  • 原文地址:https://www.cnblogs.com/majiang/p/2763882.html
Copyright © 2011-2022 走看看