ASP.NET模型绑定到基类型

时间:2010-10-31 09:14:59

标签: asp.net-mvc types derived defaultmodelbinder

我有一个我的View Models都继承自的BaseViewModel。

public class MagazineViewModel : BaseOutputViewMode
{
    public string TitleOfPublication { get; set; }
}

在我的控制器中,我使用工厂方法根据输入提供相应的View Model:

// e.g. viewModel contains an instance of MagazineViewModel 
BaseOutputViewModel viewModel = BaseOutputViewModel.GetOutputViewModel(output);

当我使用TryUpdateModel尝试绑定到我知道包含“TitleOfPublication”键的FormCollection时,它从未在我的视图模型中设置:

if (!TryUpdateModel(viewModel, form))

我认为这与使用BaseOutputViewModel绑定FormCollection键的DefaultModelBinder有关 - 它不包含派生的MagazineViewModel的“TitleOfPublication”。

我正在尝试滚动自己的模型绑定器,以覆盖DefaultModelBinder的BindModel行为。它全部连线正确,我可以在TryUpdateModel调用后直接调试它:

 public class TestModelBinder : DefaultModelBinder, IFilteredModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // Tried the following without success ....
        // 1. Quick hardcoded test
        // bindingContext.ModelType = typeof(MagazineViewModel);
        // 2. Set ModelMetadata, hardcoded test again
        // bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(MagazineViewModel));
        // 3. Replace the entire context
        // ModelBindingContext context2 = new ModelBindingContext();
        // context2.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(MagazineViewModel));
        // context2.ModelName = bindingContext.ModelName;
        // context2.ModelState = bindingContext.ModelState;            
        // context2.ValueProvider = bindingContext.ValueProvider;
        // bindingContext = context2;
    }
}

但是我不确定如何使用bindingContext?需要更新什么才能告诉DefaultModelBinder使用派生的View Model属性进行绑定? 或者我完全误解了这个!

我确实尝试重写CreateModel - 就像MvcContrib中的DerivedTypeModelBinder一样,但我认为因为我给了一个模型的实例来使用,所以从不调用CreateModel。在Mvc DLL上使用了Reflector,它是一个“BindComplexModel”,仅当模型为null时才调用CreateModel:

if (model == null)
{
    model = this.CreateModel(controllerContext, bindingContext, modelType);
}

任何指针都很受欢迎!

干杯

1 个答案:

答案 0 :(得分:1)

好的 - 终于到了最底层! 实际上我的模型绑定器没有任何问题,问题最终导致了几个没有名称/ id的输入标签:

<input id="" name="" type="text">

关键是DefaultModelBinder中的这个测试:

// Simple model = int, string, etc.; determined by calling TypeConverter.CanConvertFrom(typeof(string))
// or by seeing if a value in the request exactly matches the name of the model we're binding.
// Complex type = everything else.
if (!performedFallback) {
     ValueProviderResult vpResult =
            bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (vpResult != null) {
                return BindSimpleModel(controllerContext, bindingContext, vpResult);
            }
        }

如果没有id / name,表单集合的键为“”,这意味着GetValue正确返回该字段的值,继续绑定为简单模型。

当添加id / name时,表单集合不包含“”的键,(现在我们正在使用TryUpdateModel,这是我的模型的名称)。这意味着DefaultModelBinder正确地将我的模型视为complexm在我的派生类型中成功绑定属性!

干杯