ASP.NET MVC上

时间:2016-09-06 12:03:20

标签: asp.net asp.net-mvc model-binding asp.net-mvc-viewmodel

我有以下viewmodel结构: ItemViewModel包含属性Model的类型BaseViewModel。

在此具体示例中,Model的类型为WeekManagerWorkScheduleViewModel。这个视图模型由一个IEnumerable类型的ManagerWorkScheduleViewModel组成。

在ItemView.cshtml中使用以下内容:

<form class="form-horizontal" id="@Model.FormName" name="@Model.FormName" onsubmit="@Model.OnSubmitFunction">
    <div class="form-group form-group-sm">
        @Html.EditorFor(model => model.Model, Model.ItemViewName + "View")
    </div>
    <button class="btn pull-left" type="submit" style="margin: 2px;">
      <span class="glyphicon glyphicon-save"></span>
        @Model.ViewConfiguration.SaveText @Model.ItemTitle
     </button>
 </form>

我省略了一些细节(基本上是一堆是否确定是否添加CRUD按钮.Mode.ItemViewName是typename(在本例中是WeekManagerWorkScheduleViewModel)。

public class WeekManagerWorkScheduleViewModel : BaseViewModel
{ 
    [HiddenInput]
    public int RegionId { get; set; }
    [HiddenInput]
    public IEnumerable<DateTime> Dates { get; set; }

    public IEnumerable<ManagerWorkScheduleViewModel> WorkSchedules { get; set; } 
}

WeekManagerWorkScheduleView.cshtml如下所示:

@using DRSTransportPortal.ViewModels
@model WeekManagerWorkScheduleViewModel
@{
   ViewBag.Title = "Ugentlig arbejdsplan - ledere";
}

@Html.HiddenFor(m => m.RegionId)

<table class="table">
    <thead>
        <tr>
           <th><b>Leder</b></th>
           <th><b>Uge</b></th>
           <th><b>Mandag</b></th>
           <th><b>Tirsdag</b></th>
           <th><b>Onsdag</b></th>
           <th><b>Torsdag</b></th>
           <th><b>Fredag</b></th>
           <th><b>Lørdag</b></th>
           <th><b>Søndag</b></th>
       </tr>
       <tr>
           <th></th>
           <th></th>
              @foreach (var date in Model.Dates)
              {
                  <th><i><small>@date.Date.ToString("dd-MM-yyyy")</small></i></th>
              }
       </tr>
  </thead>
  <tbody>
     @Html.EditorFor(m => m.WorkSchedules)
  </tbody>
</table>

我有一个名为ManagerWorkScheduleViewModel.cshtml的视图驻留在Views / imalazysod / EditorTemplates中(MVC知道这个位置,因为我使用的是自定义视图引擎,源自Razor):

@using DRSTransportPortal.ViewModels
@model ManagerWorkScheduleViewModel
<tr id="@Model.Id">
    <td>@Html.HiddenFor(m => m.Id)</td>
    <td>@Html.DisplayFor(m => m.ManagerName, new { htmlAttributes = new { @class = "form-control editoritem" } })</td>
    <td>@Html.DisplayFor(m => m.DateWeekText, new { htmlAttributes = new { @class = "form-control editoritem" } })</td>
     <td>@Html.EditorFor(m => m.MondayCodeChoice, new { @class = "form-control editoritem" })</td>
     <td>@Html.EditorFor(m => m.TuesdayCodeChoice, new { @class = "form-control editoritem" })</td>
     <td>@Html.EditorFor(m => m.WednesdayCodeChoice, new { @class = "form-control editoritem" })</td>
     <td>@Html.EditorFor(m => m.ThursdayCodeChoice, new { @class = "form-control editoritem" })</td>
     <td>@Html.EditorFor(m => m.FridayCodeChoice, new { @class = "form-control editoritem" })</td>
     <td>@Html.EditorFor(m => m.SaturdayCodeChoice, new { @class = "form-control editoritem" })</td>
     <td>@Html.EditorFor(m => m.SundayCodeChoice, new { @class = "form-control editoritem" })</td>
 </tr>

&#34;选择&#34;属性都是使用ChoiceViewModel.cshtml的ChoiceViewModel类型。

现在,一切都很好: Screenshot (names omitted). Red box indicates 1 (one) nested viewmodel

生成的HTML看起来像这样(这里只显示第一行和前几个单元格):

<tr id="134">
    <td><input name="Model.WorkSchedules[0].Id" id="Model_WorkSchedules_0__Id" type="hidden" value="134" data-val-required="Feltet Id skal udfyldes." data-val="true" data-val-number="The field Id must be a number."></td>
    <td>OMITTED</td>
    <td>2016 - 36</td>
    <td>
    <select name="Model.WorkSchedules[0].MondayCodeChoice.SelectedValue" class="form-control editoritem dropdown" id="SelectChoices" onchange="">
       <option value="1">06:00 - 14:00</option>
       <option value="19">06:00 - 18:00</option>
       <option value="31">08:00 - 16:00</option>
       <option value="2">10:00 - 18:00</option>
       <option value="32">10:00 - 18:00</option>
       <option value="23">Bagvagt</option>
       <option value="22">Ferie</option>
       <option value="8">Fri</option>
       <option value="3">Kontor</option>
       <option value="15">Kussus</option>
       <option value="16">Syg</option>
     </select>
   </td>  
REST OF HTML IS OMMITTED (CONTINUES FOR 12 ROWS WITH 10 CELLS EACH)
</tr>

然而,当我回发(使用jQuery,ajax顺便说一句)这是我得到的: Controller breakpoint, after modelbinding

我已经尝试在BaseViewModel上放置一个自定义模型绑定器,并调试那些看不到任何不合适的东西。它解析了正确的类型(WeekManagerWorkScheduleViewModel等)。 使用它,来自ControllerContext-&gt; ...-&gt; Request的我的Forms元素是: {Model.Id = 141&安培; ModelType = DRSTransportPortal.ViewModels.WeekManagerWorkScheduleViewModel%2C + DRSTransportPortal%2C +版%3d1.0.0.0%2C +文化%3dneutral%2C +公钥%3dnull&安培; Model.RegionId = 1&安培; Model.WorkSchedules %5b0%5d.Id = 134&安培; Model.WorkSchedules%5b0%5d.MondayCodeChoice.SelectedValue = 22&安培; Model.WorkSchedules%5b0%5d.TuesdayCodeChoice.SelectedValue = 1&安培; Model.WorkSchedules%5b0%5d.WednesdayCodeChoice.SelectedValue = 1和; Model.WorkSchedules%5b0%5d.ThursdayCodeChoice.SelectedValue = 1&安培; Model.WorkSchedules%5b0%5d.FridayCodeChoice.SelectedValue = 1&安培; Model.WorkSchedules%5b0%5d.SaturdayCodeChoice.SelectedValue = 1&安培; Model.WorkSchedules%5b0%5D .SundayCodeChoice.SelectedValue = 1&amp; .....继续使用所有12个嵌套的视图模型}

我已确定以下情况属实: 所有绑定都是对属性进行的(默认即。{get; set;}) 没有视图模型,包括BaseViewModel,都有构造函数(即应该创建默认构造函数) 所有属性和类都是公共的

所以...我的问题是,为什么modelbinder无法创建列表的视图模型?我在其他地方使用模板没有问题,编辑pr。人,即。一次一行)。 是的,我知道有很多问题和许多答案与MVC模型绑定有关,但似乎没有一个完全属于这一类(书籍也是如此)。让我感到困惑的是,我们认识到需要列出12个项目,但它并没有被填充。

编辑:

public class BaseViewModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        var typeValue = bindingContext.ValueProvider.GetValue("ModelType");
        var type = Type.GetType((string) typeValue.ConvertTo(typeof (string)), true);
        if(!typeof(BaseViewModel).IsAssignableFrom(type))
            throw new InvalidOperationException("NOT A BASEVIEWMODEL");

        var model = Activator.CreateInstance(type);
        bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
        return model;
    }
}

[ModelBinder(typeof(BaseViewModelBinder))]
public class BaseViewModel
{
    [HiddenInput]
    public int Id { get; set; }
    [HiddenInput]
    public DateTime Created { get; set; }
    [HiddenInput]
    public DateTime Edited { get; set; }
    public virtual string SelectionName { get; set; }
}

编辑2:

    [HttpPost]
    public override async Task<JsonResult> Save(ItemViewModel item, string parentName, int? parentId)
    {
        if (item?.Model == null)
        {
            const int result = 0;
            return Json(new { result });
        }
        var model = item.Model as WeekManagerWorkScheduleViewModel;
        if (model == null)
        {
            const int result = 0;
            return Json(new { result });
        }

        foreach (var inner in model.WorkSchedules)
        {

        }
        return await base.Save(item, parentName, parentId);
    }

public class ManagerWorkScheduleViewModel : BaseViewModel
{
    [HiddenInput]
    public int? ManagerId { get; set; }
    [DisplayName("Leder")]
    public string ManagerName { get; set; }

    [HiddenInput]
    public int? DateWeekId { get; set; }
    [DisplayName("År / Uge")]
    public string DateWeekText { get; set; }

    [HiddenInput]
    public int? MondayCodeId { get; set; }

    [UIHint("ChoiceViewModel")]
    [DisplayName("Mandag")]
    public ChoiceViewModel MondayCodeChoice { get; set; }

    [HiddenInput]
    public int? TuesdayCodeId { get; set; }

    [UIHint("ChoiceViewModel")]
    [DisplayName("Tirsdag")]
    public ChoiceViewModel TuesdayCodeChoice { get; set; }

    [HiddenInput]
    public int? WednesdayCodeId { get; set; }

    [UIHint("ChoiceViewModel")]
    [DisplayName("Onsdag")]
    public ChoiceViewModel WednesdayCodeChoice { get; set; }


    [HiddenInput]
    public int? ThursdayCodeId { get; set; }

    [UIHint("ChoiceViewModel")]
    [DisplayName("Torsdag")]
    public ChoiceViewModel ThursdayCodeChoice { get; set; }

    [HiddenInput]
    public int? FridayCodeId { get; set; }

    [UIHint("ChoiceViewModel")]
    [DisplayName("Fredag")]
    public ChoiceViewModel FridayCodeChoice { get; set; }

    [HiddenInput]
    public int? SaturdayCodeId { get; set; }

    [UIHint("ChoiceViewModel")]
    [DisplayName("Lørdag")]
    public ChoiceViewModel SaturdayCodeChoice { get; set; }

    [HiddenInput]
    public int? SundayCodeId { get; set; }

    [UIHint("ChoiceViewModel")]
    [DisplayName("Søndag")]
    public ChoiceViewModel SundayCodeChoice { get; set; }
}

1 个答案:

答案 0 :(得分:0)

啊,傻我。 我忘了我是如何开始实现这个框架的。

我主要是为CRUD操作创建的,所以我只需要为每个业务实体定义viewmodel(派生自BaseViewModel),视图,存储库和dto类型以及空控制器。然后其他一切都使用一组标准的控制器(三个派生级别,具体取决于所需的功能),我需要做的就是为业务实体创建一个配置条目,定义vm,view,repo类型以及一些CRUD按钮和标签的选项。 所有顶级视图模型和视图都是相同的,如ItemView,ItemViewModel,ItemListView,SingleSelector,MultipleSelector等。

我有FORGOTTEN的原因是我一次限制自己只使用一个商业实体,因此输出了类(参见模型绑定器),所以我可以使用派生的视图模型......这很有效,除了在这种情况下很明显。

当绑定尝试填充列表时,它会继续尝试使用第一个viewmodel类型填充它(因为这是POST后唯一已知的)而不是派生的。该死!所以回到绘图表(没有嵌套:()