4

我希望将 UpdateModel 方法用于在运行时检索的子类,如果有人可以阐明我是否正在对其进行总哈希和/或我是否正在尝试做是可能的。

我正在使用通用操作来控制一堆局部视图的验证;我试图避免对每个部分视图进行特定操作。

每个局部视图都有一个从基础模型派生的唯一模型:

public class ModelA : ModelBase{
     [Required]
     public string SomeStringProperty{get;set;}
...
}
public class ModelB : ModelBase{
     [Required]
     public DateTime? SomeDateProperty{get;set;}
...
}
public class ModelBase{
     public Guid InstanceId{get;set;}
}

我在 Action 上使用 FormCollection 来获取提交的表单元素及其值,这包括视图应该用来验证其请求的模型类型。忽略此示例的安全隐患,我知道它们,这是内部唯一的概念证明

    [HttpPost]
    public ActionResult ChangeCaseState(int id, FormCollection formCollection)
    {
        Guid instanceId = new Guid(formCollection["instanceId"]);
        string modelType = formCollection["modelType"];
        //Return a specific Model class based on the event/modelType
        var args = GetStateModelClass(modelType, instanceId);

        try
        {
            UpdateModel(args);
            if(Model.IsValid){
             ...
        }
        catch (Exception)
        {
            return View("~/Views/Shared/StateForms/" + modelType + ".ascx", args);
        }...

这是我用来根据传递给控制器​​的模型类型返回子类的代码。

private static ModelBase StateModelClassFactory(string stateModelTypeName, Guid instanceId)
        {
            switch (stateModelTypeName)
            {
                case "modelTypeA":
                    return new ModelA(workflowInstanceId);
                case "modelTypeB":
                    return new ModelB(workflowInstanceId);
    ...
    }

由于 StateModelClassFactory 方法的返回类型是基类,即使我实际上返回的是子类,UpdateModel 方法使用的模型绑定器也只绑定基类中的值。

关于如何解决这个问题的任何想法?

更新:

我创建了一个客户模型绑定器:

public class CustomModelBinder : DefaultModelBinder
    {
      public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {

并将新的模型绑定器分配给正确的基类,以进一步了解幕后情况:

ModelBinders.Binders.Add(typeof(ModelBase), new CaseController.CustomModelBinder());

当我调试模型绑定器并检查 bindingContext 时,Model 属性表示正确的子类,但 ModelType 属性是基类的属性。我应该考虑在 BindModel 方法中更改 ModelType 吗?如果是关于如何执行此操作的任何指针,则 ModelType 上的设置器似乎已变得多余。我还注意到子类中的 SomeDateProperty 实际上在 PropertyMetadata 属性中......似乎非常接近我想要的行为。

4

3 回答 3

5

我刚刚遇到了这个特定问题,发现更好的通用方法是将模型转换为dynamic同时将其传递到UpdateModel

[HttpPost]
public ActionResult ChangeCaseState(int id, FormCollection formCollection)
{
    ...try
    {
        UpdateModel((dynamic)args);//!!notice cast to dynamic here
        if(Model.IsValid){
         ...
    }
    catch...

这似乎设置了我的类型的所有可用属性,无论我的变量是否与基本类型一起使用。

CodePlex 中有一个针对此问题的工作项:http ://aspnet.codeplex.com/workitem/8277?ProjectName=aspnet

于 2011-05-27T18:25:03.203 回答
2

所以我想我已经解决了我的问题。基本上是因为我在调用 UpdateModel 之前检索模型类的方式,模型绑定器正在绑定 BaseClass,即使模型是子类的模型 - 这是我用来解决我的特定问题的代码:

  public class SubClassModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var model = bindingContext.Model;
        var metaDataType = ModelMetadataProviders.Current.GetMetadataForType(null, model.GetType());
        bindingContext.ModelMetadata = metaDataType;
        bindingContext.ModelMetadata.Model = model;

        return base.BindModel(controllerContext, bindingContext);
    }
}

在 Global.asax 中:

ModelBinders.Binders.Add(typeof(ModelBase), new SubClassModelBinder ());

感谢达林的初始指针。

于 2010-11-29T10:28:56.973 回答
0

为了解决这个问题,您可以为基类型编写一个自定义模型绑定器,它基于字符串属性的值将返回正确的子实例。

于 2010-11-26T17:08:22.500 回答