这里的代码很明显地说明了modelBinder由ModelBinderFactory类的CreateBinder方法创建。
public IModelBinder CreateBinder(ModelBinderFactoryContext context) { ... IModelBinder binder; if (TryGetCachedBinder(context.Metadata, context.CacheToken, out binder)) { return binder; } var providerContext = new DefaultModelBinderProviderContext(this, context); binder = CreateBinderCoreUncached(providerContext, context.CacheToken); ... AddToCache(context.Metadata, context.CacheToken, binder); return binder; }CreateBinder方法内部中如果缓存可以取到值,则从缓存内取值并直接返回,否则通过CreateBinderCoreUncached方法取值。
private IModelBinder CreateBinderCoreUncached(DefaultModelBinderProviderContext providerContext, object token) { ... IModelBinder result = null; for (var i = 0; i < _providers.Length; i++) { var provider = _providers[i]; result = provider.GetBinder(providerContext); if (result != null) { break; } } ... return result; }这里的providers集合又包含哪些数据呢?可以从MvcCoreMvcOptionsSetup类中找到答案。
public void Configure(MvcOptions options) { // Set up ModelBinding options.ModelBinderProviders.Add(new BinderTypeModelBinderProvider()); options.ModelBinderProviders.Add(new ServicesModelBinderProvider()); options.ModelBinderProviders.Add(new BodyModelBinderProvider(options.InputFormatters, _readerFactory, _loggerFactory, options)); options.ModelBinderProviders.Add(new HeaderModelBinderProvider()); options.ModelBinderProviders.Add(new FloatingPointTypeModelBinderProvider()); options.ModelBinderProviders.Add(new EnumTypeModelBinderProvider(options)); options.ModelBinderProviders.Add(new SimpleTypeModelBinderProvider()); options.ModelBinderProviders.Add(new CancellationTokenModelBinderProvider()); options.ModelBinderProviders.Add(new ByteArrayModelBinderProvider()); options.ModelBinderProviders.Add(new FormFileModelBinderProvider()); options.ModelBinderProviders.Add(new FormCollectionModelBinderProvider()); options.ModelBinderProviders.Add(new KeyValuePairModelBinderProvider()); options.ModelBinderProviders.Add(new DictionaryModelBinderProvider()); options.ModelBinderProviders.Add(new ArrayModelBinderProvider()); options.ModelBinderProviders.Add(new CollectionModelBinderProvider()); options.ModelBinderProviders.Add(new ComplexTypeModelBinderProvider()); ... }以上便是.NET Core MVC中所有被框架支持的ModelBinderProvider。
以一个最典型的FormCollectionModelBinderProvider为例。它以Metadata.ModelType的类型作为判断依据,如果是IFormCollection类型的话,则返回一个FormCollectionModelBinder对象。
public IModelBinder GetBinder(ModelBinderProviderContext context) { ... var modelType = context.Metadata.ModelType; ... if (modelType == typeof(IFormCollection)) { var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>(); return new FormCollectionModelBinder(loggerFactory); } return null; }在CreateBinderCoreUncached方法的循环体内部会依次尝试ModelBinderProvider们是否能创建合适的ModelBinder,一旦能够生成ModelBinder,则跳出当前循环,以这个对象作为返回值。
ValueProvider有了ModelBinder,还需要有数据才能进行绑定。而为ModelBinder提供数据的是一些ValueProvider。
MvcCoreMvcOptionsSetup类的Configure方法里,再往下找,可以看到ValueProvider们的踪影。更确切地是与之对应的工厂类们。
public void Configure(MvcOptions options) { ... // Set up ValueProviders options.ValueProviderFactories.Add(new FormValueProviderFactory()); options.ValueProviderFactories.Add(new RouteValueProviderFactory()); options.ValueProviderFactories.Add(new QueryStringValueProviderFactory()); options.ValueProviderFactories.Add(new JQueryFormValueProviderFactory()); ... }以FormValueProviderFactory为例,看一下其内部:
public Task CreateValueProviderAsync(ValueProviderFactoryContext context) { ... var request = context.ActionContext.HttpContext.Request; if (request.HasFormContentType) { // Allocating a Task only when the body is form data. return AddValueProviderAsync(context); } return Task.CompletedTask; } private static async Task AddValueProviderAsync(ValueProviderFactoryContext context) { var request = context.ActionContext.HttpContext.Request; var valueProvider = new FormValueProvider( BindingSource.Form, await request.ReadFormAsync(), CultureInfo.CurrentCulture); context.ValueProviders.Add(valueProvider); }通过CreateValueProviderAsync方法可以得到一个FormValueProvider对象。
而这些ValueProviderFactory所创建的ValueProvider又统一被CompositeValueProvider类的CreateAsync方法聚合成CompositeValueProvider这个集合对象的内部元素。
public static async Task<CompositeValueProvider> CreateAsync( ActionContext actionContext, IList<IValueProviderFactory> factories) { var valueProviderFactoryContext = new ValueProviderFactoryContext(actionContext); for (var i = 0; i < factories.Count; i++) { var factory = factories[i]; await factory.CreateValueProviderAsync(valueProviderFactoryContext); } return new CompositeValueProvider(valueProviderFactoryContext.ValueProviders); }