简体   繁体   English

复杂模型在操作中返回null?

[英]Complex model return null in action?

A strongly typed view has a <form> and on submitting <form> I am expecting it should return updated value in model but it is not the case. 强类型视图具有<form>并且在提交<form>我希望它应在模型中返回更新的值,但事实并非如此。 I couldn't figure out what it is happening. 我不知道发生了什么。

View Mode: 查看模式:

public class HomeLoanViewModel
{
    public Lead_Options leadOption { get; set; }       
    public Lead HomeLoanLead {get;set;}

    public HomeLoanViewModel()
    {
        this.leadOption= new Lead_Options();
        this.HomeLoanLead= new Lead();
    }
}

and Lead class inside ViewModel is as below: ViewModel内部的Lead类如下:

public partial class Lead
{
    public string Lead_id { get; set; }      
    public string Income { get; set; }

    [NotMapped]
    public List<SelectListItem> Income_Binder
    {
        get
        {
            return new List<SelectListItem>()
            {
                new SelectListItem(){ Value="", Text="Please select...", Selected=true },
                new SelectListItem(){ Value="$0 - $30,000", Text="$0 - $30,000" },
                new SelectListItem(){ Value="$30,001 - $40,000", Text="$30,001 - $40,000" },
                new SelectListItem(){ Value="$40,001 - $50,000", Text="$40,001 - $50,000"},
                new SelectListItem(){ Value="$50,001 - $60,000", Text="$50,001 - $60,000"},
                new SelectListItem(){ Value="$60,001 - $70,000", Text="$60,001 - $70,000"},
                new SelectListItem(){ Value="$70,001 - $80,000", Text="$70,001 - $80,000"},
                new SelectListItem(){ Value="$80,001 - $90,000", Text="$80,001 - $90,000"},
                new SelectListItem(){ Value="$90,001 - $100,000", Text="$90,001 - $100,000"},
                new SelectListItem(){ Value="$100,001 - $150,000", Text="$100,001 - $150,000"},
                new SelectListItem(){ Value="$150,000+", Text="$150,000+"}
            };
        }
    }
}

Controller & Action: 控制器和动作:

public class HomeLoanController : ParentController
{
    [HttpGet]
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Submit(FormCollection form)
    {
        Session["loan_type"] = form.GetValue("Type").AttemptedValue;
        Session["m_I_need_to"] = form.GetValue("LoanPurpose").AttemptedValue;
        Session["m_The_property_is_a"] = form.GetValue("LoanFor").AttemptedValue;
        Session["m_My_time_frame_to_buy_or_refinance_is"] = form.GetValue("LoanTimeFrame").AttemptedValue;

       // return View("LeadContact", new HomeLoanViewModel());
       return RedirectToAction("LeadContact");
    }

    [HttpGet]
    public ActionResult LeadContact(HomeLoanViewModel model)
    {
        return View(model);
    }
}

View: 视图:

@using HMC.Common.Utilities;
@model HMC.Common.ViewModel.HomeLoanViewModel
@{
    ViewBag.Title = "LeadContact";
    Layout = "~/Views/_Base.cshtml";
}

<form class="wrapper minheight homeloan-form border-top" id="homeloan-form" method="post" action="" novalidate="novalidate">
<label>Total Annual Income</label>
@Html.DropDownListFor(m => m.HomeLoanLead.Income, Model.HomeLoanLead.Income_Binder, new { required = "", aria_required = "true", name = "interestratetype" })
@Html.HiddenFor(m => m.HomeLoanLead.Income)
<div class="formnav row">
     <button class="btn btn-large">Show Top Home Loans <i class="fa fa-chevron-right"></i></button>
</div>
</form>

EDIT: From previous page/ view request come to Submit Action of controller, then it redirect to LeadContact. 编辑:从上一页/视图请求来到控制器的Submit Action,然后将其重定向到LeadContact。 This is view where I m passing model and post back want to receive updated values. 这是我传递模型并发回要接收更新值的视图。

This type of issue is common when using ViewModels or strongly typed views with models. 在模型中使用ViewModels或强类型视图时,这种类型的问题很常见。 Here's why... When a post back happens the model binder eventually gets called prior to the controller getting called for the post back. 这就是为什么...当发生回发时,最终在调用控制器进行回发之前调用了模型绑定程序。 If the controller is accepting a class (model or viewmodel) as an input parameter, then MVC will first create an instance of the class using the null constructor. 如果控制器接受类(模型或视图模型)作为输入参数,则MVC将首先使用null构造函数创建该类的实例。 Then the model binder will take the HTML Query string (name value pairs) and attempt to fill in the model/view model properties based on the name value pairs. 然后,模型绑定器将采用HTML查询字符串(名称/值对),并尝试基于名称/值对填写模型/视图模型属性。 If the binder cannot find the proper Name matches it simply doesn't do anything (which is proper behavior), as a result the symptoms of this are "Hey I missing data that I know I posted from the view". 如果活页夹找不到正确的名称匹配,它将根本不执行任何操作(这是正确的行为),其结果是“嘿,我丢失了从视图中发布的数据”。

The best way to debug this is 1) Set a breakpoint on the controller's action method. 调试此错误的最佳方法是1)在控制器的action方法上设置一个断点。 2) Go to the client side and press F12 to view the network post. 2)转到客户端,然后按F12查看网络帖子。 3) Start the post back and notice the name value pairs sent from the browser. 3)开始发回邮件,并注意从浏览器发送的名称/值对。 Upon breaking at the controller entry go do Debug/Windows/Locals and look at the model portion of the controller parameters. 在控制器入口处断开后,请执行Debug / Windows / Locals并查看控制器参数的模型部分。 You will see the same thing there as in the network side (proof they all made it back). 您将在那里看到与在网络端相同的东西(证明他们都回来了)。 Now look at the typed value, if anything is not there that should be there, it is simply because the post back and the model (Name values) did not match. 现在查看输入的值,如果没有应该存在的任何内容,那仅仅是因为回发和模型(名称值)不匹配。

90% of the time the root cause is the first parameter of the DisplayFor, HiddenFor or other "For" elements is not pointing to the correct thing to be returned. 90%的根本原因是DisplayFor,HiddenFor或其他“ For”元素的第一个参数未指向要返回的正确内容。 This is why I like to use ViewModels.. 这就是为什么我喜欢使用ViewModels。

Given: 鉴于:

public class HomeLoanViewModel
{
  public Lead_Options leadOption { get; set; }       
  public Lead HomeLoanLead {get;set;}
  public String SelectedValue {get;set;}

  public HomeLoanViewModel()
  {
    this.leadOption= new Lead_Options();
    this.HomeLoanLead= new Lead();
  }
  public void Post(){
     //do all your post logic here
     if(SelectedValue > XYZ) //do this
  }
}

I would create the controller signature like this: 我将这样创建控制器签名:

 [HttpPost]
public ActionResult Submit(HomeLoanViewModel vm)
{
     if (ModelState.IsValid){
               vm.Post();
               return View(vm);
     }
  return View(vm);
}

I would create the view like this: 我将创建这样的视图:

@using HMC.Common.Utilities;
@model HMC.Common.ViewModel.HomeLoanViewModel
@{
  ViewBag.Title = "LeadContact";
  Layout = "~/Views/_Base.cshtml";
}
@Using Html.BeginForm(){

    <label>Total Annual Income</label>
     @Html.DropDownListFor(m => m.HomeLoanLead.SelectedValue, Model.HomeLoanLead.Income_Binder, new { required = "", aria_required = "true"})

     <input type="submit/>

}

<div class="formnav row">
 <button class="btn btn-large">Show Top Home Loans <i class="fa fa-chevron-right"></i></button>
</div>

Finally one other pointer, no sense in the SelectListItems Text and Value being the same, you could just as easily have set the value to in Int such as [1,2,3,4,5] for each of the choices. 最后是另一个指针,在SelectListItems文本和值中没有意义是相同的,您可以很容易地将Int的值设置为Int,例如[1,2,3,4,5]的每个选择。 Look at the value as the identifier of the text field, this works especially well with databases that have ID for looking up field values. 将值视为文本字段的标识符,这尤其适用于具有用于查找字段值的ID的数据库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM