ASP.NET 模型绑定到基本类型

发布于 2024-09-30 03:37:41 字数 2223 浏览 1 评论 0原文

我有一个 BaseViewModel,我的视图模型都继承自它。

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

在我的控制器中,我使用工厂方法根据输入返回正确的视图模型:

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

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

if (!TryUpdateModel(viewModel, form))

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

我正在尝试滚动我自己的模型绑定器,以覆盖 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 使用派生视图模型属性进行绑定? 或者我完全误解了这一点!

我确实尝试重写 CreateModel - 很像 MvcContrib 中的 DerivedTypeModelBinder,但我认为因为我为活页夹提供了要使用的模型实例,所以永远不会调用 CreateModel。在 Mvc DLL 上使用 Reflector,有一个“BindComplexModel”,仅当模型为 null 时才调用 CreateModel:

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

已收到任何指针!

干杯

I have a BaseViewModel that my View Models all inherit from.

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

In my controller I use a factory method to give the corret View Model back based on an input:

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

When I use TryUpdateModel to try and bind to a FormCollection which I know contains a "TitleOfPublication" key, its never set in my view model:

if (!TryUpdateModel(viewModel, form))

I think this is something to do with the DefaultModelBinder using the BaseOutputViewModel to bind FormCollection keys to - it doesn't contain a "TitleOfPublication", the derived MagazineViewModel does.

I'm trying to roll my own model binder, to override the DefaultModelBinder's BindModel behavior. Its all wired in correctly and I can debug into it straight after the TryUpdateModel call:

 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;
    }
}

But I'm not sure how to work with the bindingContext? What needs to be updated so that I can tell the DefaultModelBinder to bind using the derived View Model properties?
Or have I just totally mis-understood this!

I did try overriding CreateModel - much like the DerivedTypeModelBinder in MvcContrib, but I think because I'm giving the binder an instance of a model to work with, CreateModel is never called. Used Reflector on the Mvc DLL, theres a "BindComplexModel" that calls CreateModel only if the model is null:

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

Any pointers greatfully received!

Cheers

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

泪冰清 2024-10-07 03:37:41

好吧——终于弄清楚了!
事实上,我的模型绑定器没有任何问题,问题最终导致了几个没有名称/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/名称,表单集合有一个键“”,这意味着 GetValue 正确返回了该字段的值,继续作为简单模型进行绑定。

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

干杯

OK - finally got to the bottom of this!
In actual fact there was nothing wrong with my model binder, the problem ultimately led back to a couple of input tags that had no name/id:

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

The crux was this test in 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);
            }
        }

With no id/name, the form collection has a key of "" which means that the GetValue correctly returned the value for that field, continuing to bind as a simple model.

When an id/name are added, the form collection contains no key of "", (which is now the name of my model as we're using TryUpdateModel). This meant the DefaultModelBinder correctly treated my model as complexm successfully binding properties in my derived type!

Cheers

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文