1 namespace System.Web.ModelBinding { 2 using System; 3 using System.Collections.Generic; 4 using System.Collections.ObjectModel; 5 using System.Globalization; 6 using System.Linq; 7 8 public sealed class ModelBinderProviderCollection : Collection<ModelBinderProvider> { 9 ModelBinderProviderCollection()10 public ModelBinderProviderCollection() { 11 } 12 ModelBinderProviderCollection(IList<ModelBinderProvider> list)13 public ModelBinderProviderCollection(IList<ModelBinderProvider> list) 14 : base(list) { 15 } 16 GetBinder(ModelBindingExecutionContext modelBindingExecutionContext, ModelBindingContext bindingContext)17 public IModelBinder GetBinder(ModelBindingExecutionContext modelBindingExecutionContext, ModelBindingContext bindingContext) { 18 if (modelBindingExecutionContext == null) { 19 throw new ArgumentNullException("modelBindingExecutionContext"); 20 } 21 if (bindingContext == null) { 22 throw new ArgumentNullException("bindingContext"); 23 } 24 25 ModelBinderProvider providerFromAttr; 26 if (TryGetProviderFromAttributes(bindingContext.ModelType, out providerFromAttr)) { 27 return providerFromAttr.GetBinder(modelBindingExecutionContext, bindingContext); 28 } 29 30 return (from provider in this 31 let binder = provider.GetBinder(modelBindingExecutionContext, bindingContext) 32 where binder != null 33 select binder).FirstOrDefault(); 34 } 35 GetRequiredBinder(ModelBindingExecutionContext modelBindingExecutionContext, ModelBindingContext bindingContext)36 internal IModelBinder GetRequiredBinder(ModelBindingExecutionContext modelBindingExecutionContext, ModelBindingContext bindingContext) { 37 IModelBinder binder = GetBinder(modelBindingExecutionContext, bindingContext); 38 if (binder == null) { 39 throw Error.ModelBinderProviderCollection_BinderForTypeNotFound(bindingContext.ModelType); 40 } 41 return binder; 42 } 43 InsertItem(int index, ModelBinderProvider item)44 protected override void InsertItem(int index, ModelBinderProvider item) { 45 if (item == null) { 46 throw new ArgumentNullException("item"); 47 } 48 49 base.InsertItem(index, item); 50 } 51 InsertSimpleProviderAtFront(ModelBinderProvider provider)52 private void InsertSimpleProviderAtFront(ModelBinderProvider provider) { 53 // Don't want to insert simple providers before any that are marked as "should go first," 54 // as that might throw off other providers like the exact type match provider. 55 56 int i = 0; 57 for (; i < Count; i++) { 58 if (!ShouldProviderGoFirst(this[i])) { 59 break; 60 } 61 } 62 63 base.InsertItem(i, provider); 64 } 65 RegisterBinderForGenericType(Type modelType, IModelBinder modelBinder)66 public void RegisterBinderForGenericType(Type modelType, IModelBinder modelBinder) { 67 InsertSimpleProviderAtFront(new GenericModelBinderProvider(modelType, modelBinder)); 68 } 69 RegisterBinderForGenericType(Type modelType, Func<Type[], IModelBinder> modelBinderFactory)70 public void RegisterBinderForGenericType(Type modelType, Func<Type[], IModelBinder> modelBinderFactory) { 71 InsertSimpleProviderAtFront(new GenericModelBinderProvider(modelType, modelBinderFactory)); 72 } 73 RegisterBinderForGenericType(Type modelType, Type modelBinderType)74 public void RegisterBinderForGenericType(Type modelType, Type modelBinderType) { 75 InsertSimpleProviderAtFront(new GenericModelBinderProvider(modelType, modelBinderType)); 76 } 77 RegisterBinderForType(Type modelType, IModelBinder modelBinder)78 public void RegisterBinderForType(Type modelType, IModelBinder modelBinder) { 79 RegisterBinderForType(modelType, modelBinder, false /* suppressPrefixCheck */); 80 } 81 RegisterBinderForType(Type modelType, IModelBinder modelBinder, bool suppressPrefixCheck)82 internal void RegisterBinderForType(Type modelType, IModelBinder modelBinder, bool suppressPrefixCheck) { 83 SimpleModelBinderProvider provider = new SimpleModelBinderProvider(modelType, modelBinder) { 84 SuppressPrefixCheck = suppressPrefixCheck 85 }; 86 InsertSimpleProviderAtFront(provider); 87 } 88 RegisterBinderForType(Type modelType, Func<IModelBinder> modelBinderFactory)89 public void RegisterBinderForType(Type modelType, Func<IModelBinder> modelBinderFactory) { 90 InsertSimpleProviderAtFront(new SimpleModelBinderProvider(modelType, modelBinderFactory)); 91 } 92 SetItem(int index, ModelBinderProvider item)93 protected override void SetItem(int index, ModelBinderProvider item) { 94 if (item == null) { 95 throw new ArgumentNullException("item"); 96 } 97 98 base.SetItem(index, item); 99 } 100 ShouldProviderGoFirst(ModelBinderProvider provider)101 private static bool ShouldProviderGoFirst(ModelBinderProvider provider) { 102 ModelBinderProviderOptionsAttribute options = provider.GetType() 103 .GetCustomAttributes(typeof(ModelBinderProviderOptionsAttribute), true /* inherit */) 104 .OfType<ModelBinderProviderOptionsAttribute>() 105 .FirstOrDefault(); 106 107 return (options != null) ? options.FrontOfList : false; 108 } 109 TryGetProviderFromAttributes(Type modelType, out ModelBinderProvider provider)110 private static bool TryGetProviderFromAttributes(Type modelType, out ModelBinderProvider provider) { 111 ExtensibleModelBinderAttribute attr = TypeDescriptorHelper.Get(modelType).GetAttributes().OfType<ExtensibleModelBinderAttribute>().FirstOrDefault(); 112 if (attr == null) { 113 provider = null; 114 return false; 115 } 116 117 if (typeof(ModelBinderProvider).IsAssignableFrom(attr.BinderType)) { 118 provider = (ModelBinderProvider)SecurityUtils.SecureCreateInstance(attr.BinderType); 119 } 120 else if (typeof(IModelBinder).IsAssignableFrom(attr.BinderType)) { 121 Type closedBinderType = (attr.BinderType.IsGenericTypeDefinition) ? attr.BinderType.MakeGenericType(modelType.GetGenericArguments()) : attr.BinderType; 122 IModelBinder binderInstance = (IModelBinder)SecurityUtils.SecureCreateInstance(closedBinderType); 123 provider = new SimpleModelBinderProvider(modelType, binderInstance) { SuppressPrefixCheck = attr.SuppressPrefixCheck }; 124 } 125 else { 126 string errorMessage = String.Format(CultureInfo.CurrentCulture, SR.GetString(SR.ModelBinderProviderCollection_InvalidBinderType), 127 attr.BinderType, typeof(ModelBinderProvider), typeof(IModelBinder)); 128 throw new InvalidOperationException(errorMessage); 129 } 130 131 return true; 132 } 133 134 } 135 } 136