为什么即使属性设置且有效,TryUpdateModel也会返回false?

时间:2012-02-13 17:01:04

标签: c# asp.net asp.net-mvc-3 entity-framework data-annotations

我有基于ASP.Net MVC3的Web应用程序。我需要一个“创建”视图,在用户从下拉列表中选择要创建的子类型之前,该视图不会知道模型类型。为了尝试解决这个问题,我在Shared / EditorTemplates下为每个派生的模型类型创建了一个编辑器模板。这允许我创建一个强大类型的视图模型“Create.cs”。视图模型只有两个成员,一个枚举和一个复杂类型。想法是视图最初只显示一个下拉列表(枚举成员的编辑器),然后当用户最初提交指定的“模型类型”(下拉选择值)时,POST操作可以检查“模型类型” “为视图模型的单个复杂成员指定并实例化正确的派生模型类型,其类型是所有可能的”模型类型“的基本类型。

抽象+派生类型模型对象......

public abstract class MyModelBase
{
    public MyModelType_e ModelType {get; set; }
    [Required]
    public string Name { get; set; }
}

public class DerivedType1 : MyModelBase
{ ... }

public class DerivedType2 : MyModelBase
{ ... }

public class DerivedType3 : MyModelBase
{ ... }

我有一个复杂的视图模型如下......

public enum MyModelType_e
{
    DerivedType1 = 0,
    DerivedType2 = 1,
    DerivedType3 = 2
}

public class MyModelCreate
{
    public MyModelType_e ModelTypeForSelectList { get; set; }
    public MyModelBase ModelBase { get; set; }
}

我的GET控制器操作实例化视图的上述视图模型,即,仅显示包含基于MyModelType_e枚举的项目的下拉列表+模型的“ModelBase”属性的值最初为空。所以GET动作方法看起来像这样......

[HttpGet]
public ActionResult Create()
{
    return View(new MyModelCreate());
}

请注意下面关于我的问题的关键点的注释,即TryUpdateModel失败(见下文),即使它将ModelBase(派生类型)成员的属性设置为预期的相应表单值... < / p>

[HttpPost]
public ActionResult Create(MyModelCreate model)
{
    if (model.ModelBase == null || 
        (int)model.ModelTypeForSelectList != model.ModelBase.ModelType)
    {
        switch (model.ModelType)
        {
            case MyModelType_e.DerivedType1:
                model.ModelBase = new DerivedType1();
                break;
            case MyModelType_e.DerivedType2:
                model.ModelBase = new DerivedType2();
                break;
            case MyModelType_e.DerivedType3:
                model.ModelBase = new DerivedType3();
                break;
        }
        return View(model);
    }

    if (!TryUpdateModel(model.ModelBase))
        return View(model); // <<< THIS HAPPENS EVEN THOUGH ModelBase APPEARS TO BE UPDATED PROPERLY... 
    // For instance, I can see right here with intellisense that model.ModelBase.Name
    // is NOT null or empty but rather is truly updated with the correct form value(s)...

    // TODO: Insert the record, etc... (currently we never get here...)
}

所以上面的部分是问题所在,但我的观点是帮助理解......

 @model MyNamespace.MyModelCreate

 <h2>Create</h2>

 ...

 @using (Html.BeginForm())
 {
     @Html.ValidationSummary(false)
    <fieldset>
    <legend>Input</legend>
    <div class="editor-label">
    @Html.Label("Select Model Type")
    </div>
    <div>
    @Html.EnumDropDownListFor(model => model.ModelType)
    @Html.ValidationMessageFor(model => model.ModelType)
    </div>

    @* 
    Conditionally show the correct editor template... 
    There is one existing under ../Shared/EditorTemplates for each
    derived type (DerivedType1, DerivedType2, DerivedType3, etc...)
    This much is working in the sense that the correct editor fields
    are displayed based on what the user selects in the above drop-down.
    *@
    @if (Model.InputModel != null)
    {  
        @Html.EditorFor(model => model.ModelBase);
    }

    <p>
        <input type="submit" value="Continue" />
    </p>              
    </fieldset>
}

因此,一旦初始POST(选择了模型类型),我的POST操作方法就会逐渐落到TryUpdateModel行,但由于某种原因验证失败。我真正不理解的部分是验证摘要报告“名称是必需的”,即使我可以清楚地看到TryUpdateModel在视图模型的ModelBase成员上正确设置Name属性。

我非常感谢这里的任何帮助或指导......我对ASP.NET MVC还是比较陌生的,并且我愿意以不同的方式做事,因为我知道可能还有其他方法可以设计我的请求/操作+视图实现这个“多步骤”问题,但我真的只是为了最简单的事情,我为什么喜欢使用EditorTemplate方法来处理派生的模型类型等。

提前致谢...

2 个答案:

答案 0 :(得分:3)

检查ModelStateTryUpdateModel运行后应该设置错误。 我必须从某些属性中删除Required属性。

答案 1 :(得分:0)

我的解决方案基本上涉及增加两个额外的控制器操作(GET和POST)。我在../Shared/EditorTemplates下创建了单独的视图,这些视图是强类型的(每个派生模型类型一个)。这种方式初始&#34;创建&#34; POST操作仅接收所选类型(模型只是指定所需类型的枚举值),然后重定向到另一个控制器操作,如&#34; CreateByType&#34;获取所请求的具体类型的新实例并返回正确的编辑视图。额外的&#34; CreateByType&#34;控制器动作(GET和POST)只需要处理抽象基础,因为它从服务层请求实例(传递枚举值)。然后,我所要做的就是在EditorTemplates下为每个具体类型创建一个视图。

相关问题