【问题标题】:Form is not binding to correct object表单未绑定到正确的对象
【发布时间】:2016-02-01 08:23:39
【问题描述】:

我有类似的对象(我使用的是模型和视图模型,其中视图模型与模型对象具有相同的属性)。

当我编辑一个项目时,我为 viewmodel 设置了编辑器,而处理更新/编辑的控制器接收到 ViewModel:

[HttpPost]
public ActionResult Edit(DocumentViewModel model) {
 Mapper.CreateMap < DocumentViewModel, BE.Document > ();
 BE.Document instanceOfDestination = Mapper.Map < BE.Document > (model);

 Container < BE.Document > container = BL.DocumentBL.UpdateDocument(instanceOfDestination);
 if (!container.HasErrors) {
  SetInfo("Saved!");
 } else {
  SetError(container.ErrorMessage);
 }
 return RedirectToAction("Index");
}

问题是这个方法永远无法实现,因为模型绑定器构造的是 BE.Document 而不是 DocumentViewModel。

以下是浏览器发送的值:

__RequestVerificationToken:xxx-dontcare
id:36
name:test flash files
documentType.id:5
unit.id:2
reference:FLASH0016
isActive:true
isActive:false
recyclingSpan:1
selectedTopics:1
selectedTopics:2
trainer.id:615952
selectedInstallations:1
selectedInstallations:2
selectedProfessions:3
selectedProfessions:4
selectedProfessions:6

这里是返回VM制作编辑页面的Controller:

[HttpGet]
public ActionResult Edit(int id) {
 var container = BL.DocumentBL.GetAllDocument(new BE.Document() {
  id = id
 });
 if (!container.HasErrors) {
  Mapper.CreateMap < BE.Document, DocumentViewModel > ();
  DocumentViewModel instanceOfDestination = Mapper.Map < DocumentViewModel > (container.Value);
  // fill values for dropdowns and co
  instanceOfDestination.FillPredefinedValuesForUser(GetAdminOrVisibilityUnits());
  return View(instanceOfDestination);
 } else {
  SetError(container.ErrorMessage);
  return RedirectToAction("Index");
 }
}

还有用于文档的模型和视图模型:

文档视图模型:

public int id { get; set; }
[Required]
public string name { get; set; }
[Required]
public string reference { get; set; }
[Required]
[Range(0, 100)]
public int recyclingSpan { get; set; }
[Required]
public bool isActive { get; set; }

[DocumentTypeValidator("DocType is required")] // custom validator
public DocumentType documentType { get; set; }
public PersonnelAM trainer { get; set; }
public List<DocumentVersion> versions { get; set; }
public List<Installation> installations { get; set; }
public List<Profession> professions { get; set; }
public List<Topic> topics { get; set; }
public Unit unit { get; set; }

// not used for edit or create
public PersonnelAM createdBy { get; set; }
public DateTime createdOn { get; set; }
public PersonnelAM editedBy { get; set; }
public DateTime editedOn { get; set; }

// to fill dropdowns
public IEnumerable<SelectListItem> documentTypeSelect { get; set; }
public IEnumerable<SelectListItem> personnelSelect { get; set; }
public IEnumerable<SelectListItem> installationsSelect { get; set; }
public IEnumerable<SelectListItem> professionsSelect { get; set; }
public IEnumerable<SelectListItem> topicTypeSelect { get; set; }
public IEnumerable<SelectListItem> unitSelect { get; set; }


// for multi-selects - uses FillListsFromIds to fill Lists from Ids
public int[] selectedProfessions { get; set; }
public int[] selectedInstallations { get; set; }
public int[] selectedTopics { get; set; }

// For file upload
[MinLengthAttribute(1)]
public HttpPostedFileBase[] files { get; set; }
// for file get
public List<string> filesList { get; set; }

BE.文档

public int id { get; set; }
public string name { get; set; }
public string reference { get; set; }
public int recyclingSpan { get; set; }
public bool isActive { get; set; }

public DocumentType documentType { get; set; }
public PersonnelAM trainer { get; set; }
public List<string> filesList { get; set; }
public List<Installation> installations { get; set; }
public List<DocumentVersion> versions { get; set; }
public List<Profession> professions { get; set; }
public List<Topic> topics { get; set; }
public Unit unit { get; set; }

public PersonnelAM createdBy { get; set; }
public DateTime createdOn { get; set; }
public PersonnelAM editedBy { get; set; }
public DateTime editedOn { get; set; }

感谢帮助我:-)

编辑:

这是完整的 Get/id 控制器

[HttpGet]
        public ActionResult Edit(int id)
        {
            if (User.IsInRole("Admin") || User.IsInRole("Moderator") || SessionManager.matricule.IsDocumentCreator(id))
            {
                var container = BL.DocumentBL.GetAllDocument(new BE.Document() { id = id });
                if (!container.HasErrors)
                {
                    Mapper.CreateMap<BE.Document, DocumentViewModel>();
                    DocumentViewModel instanceOfDestination = Mapper.Map<DocumentViewModel>(container.Value);
                    // fill values for dropdowns and co
                    instanceOfDestination.FillPredefinedValuesForUser(GetAdminOrVisibilityUnits());
                    return View(instanceOfDestination);
                }
                else
                {
                    SetError(container.ErrorMessage);
                    return RedirectToAction("Index");
                }
            }
            else
            {
                SetError("Vous n'avez pas le droit d'accéder à l'édition de ce document.");
                return RedirectToAction("Index");
            }
        }

编辑 2:

[HttpPost]
        public ActionResult Edit(DocumentViewModel model)
        {
            if (User.IsInRole("Admin") || User.IsInRole("Moderator") || SessionManager.matricule.IsDocumentCreator(model.id))
            {
                Mapper.CreateMap<DocumentViewModel, BE.Document>();
                BE.Document instanceOfDestination = Mapper.Map<BE.Document>(model);

                Container<BE.Document> container = BL.DocumentBL.UpdateDocument(instanceOfDestination, new PersonnelAM() { id = SessionManager.matricule });
                if (!container.HasErrors)
                {
                    SetInfo("Modifications suavegardées");
                }
                else
                {
                    model.FillPredefinedValuesForUser(GetAdminOrVisibilityUnits());
                    SetError(container.ErrorMessage);
                    return View(instanceOfDestination);
                }
            }
            return RedirectToAction("Index");
        }

【问题讨论】:

  • 在调用 Edit actionmethod 时是否将正确的模型传递给 View?
  • @Vini 谢谢。是的,我正在使用 ViewModel 来构建编辑页面,如果您想查看控制器,请查看已编辑的问题
  • ModelBinder 不构造 BE.Document。 POST 方法中的参数是DocumentViewModel,所以这就是初始化的内容。你是什​​么意思这个方法永远达不到
  • @StephenMuecke 我在控制器中放了一个断点,并且我有一个服务器错误(白页和黄页)带有这种消息(翻译自我的语言(:-():元素通过字典中的类型为 BE.Document,但此字典请求 DocumentViewModel 类型的模型
  • 我看到你这样做了:)。将return View(instanceOfDestination); 更改为return View(model); 即可正常工作(instanceOfDestination 是 POST 方法中的Document 类型,而不是DocumentViewModel

标签: c# asp.net asp.net-mvc modelbinders


【解决方案1】:

您的视图模型绑定正确,但在您的 POST 方法中,这行代码

return View(instanceOfDestination);

返回Document 的实例(由BE.Document instanceOfDestination = Mapper.Map&lt;BE.Document&gt;(model); 定义,而不是导致异常的DocumentViewModel 实例

字典中传递的模型是 BE.Document 类型,但是这个字典需要 DocumentViewModel 类型的模型

改成

return View(model);

以便将正确的类型传递回视图。

【讨论】:

    【解决方案2】:

    请确保在视图文件(例如 edit.cshtml)之上将视图模型绑定到视图(您的 cshtml 文件),而不是模型:

    @model your.namespace.DocumentViewModel
    

    而不是

    @model your.namespace.BE.Document
    

    但是,如果视图模型与您的模型相同,为什么还要使用视图模型?为什么不直接使用你的模型呢

    【讨论】:

    • OP 已经在使用@model DocumentViewModel(查看浏览器发送的值!)。如果没有使用视图模型,代码将无法工作。
    • 感谢您的帮助。在视图中,ViewModel 是您建议的参考。我正在使用 ViewModel 来拥有干净的业务对象。我的业务对象在一个单独的层中,我不能将验证器和资源文件与此业务对象一起使用。 ViewModel 位于 Web 层,用于验证(数据注释)和资源。这就是原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 2023-03-07
    • 2012-03-26
    • 2012-08-22
    相关资源
    最近更新 更多