// 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.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNet.Mvc.ModelBinding.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding { public sealed class KeyValuePairModelBinder : IModelBinder { public async Task BindModelAsync(ModelBindingContext bindingContext) { ModelBindingHelper.ValidateBindingContext(bindingContext, typeof(KeyValuePair), allowNullModel: true); var keyResult = await TryBindStrongModel(bindingContext, "key"); var valueResult = await TryBindStrongModel(bindingContext, "value"); if (keyResult.Success && valueResult.Success) { bindingContext.Model = new KeyValuePair(keyResult.Model, valueResult.Model); } return keyResult.Success || valueResult.Success; } internal async Task> TryBindStrongModel(ModelBindingContext parentBindingContext, string propertyName) { var propertyBindingContext = new ModelBindingContext(parentBindingContext) { ModelMetadata = parentBindingContext.MetadataProvider.GetMetadataForType(modelAccessor: null, modelType: typeof(TModel)), ModelName = ModelBindingHelper.CreatePropertyModelName(parentBindingContext.ModelName, propertyName) }; if (await propertyBindingContext.ModelBinder.BindModelAsync(propertyBindingContext)) { var untypedModel = propertyBindingContext.Model; var model = ModelBindingHelper.CastOrDefault(untypedModel); parentBindingContext.ValidationNode.ChildNodes.Add(propertyBindingContext.ValidationNode); return new BindResult(success: true, model: model); } return new BindResult(success: false, model: default(TModel)); } internal sealed class BindResult { public BindResult(bool success, TModel model) { Success = success; Model = model; } public bool Success { get; private set; } public TModel Model { get; private set; } } } }