【问题标题】:ViewModel's parameters are null in postbackViewModel 的参数在 postback 中为空
【发布时间】:2017-11-21 01:45:49
【问题描述】:

我知道这个问题被问过很多次,但很遗憾,没有一个答案对我有帮助。

我有树 POCO 模型,它们是 Pharmacy、Address 和 Company 聚集到一个 ViewModel PharmacyVM 中:

public class PharmacyVM
{
    public Pharmacy pharmacyProp { get; set; }
    public Address addressProp { get; set; }
    public Company companyProp { get; set; }
    public int CityId { get; set; }

    public PharmacyVM()
    {
        pharmacyProp = new Pharmacy();
        addressProp = new Address();
        companyProp = new Company();
    }
}

不要嘲笑属性名称;一开始,他们是正常的(地址,公司和药房)我根据这里的很多答案之一改变了他们,但是......它没有帮助:(

在 Create 方法的 Get 操作中,我尝试手动创建 PharmacyVM 对象并将其传递给视图:

public ActionResult Create()
{
    ViewBag.CityId = new SelectList(db.Cities, "Id", "Name");
    ViewBag.CompanyId = new SelectList(db.Companies, "Id", "Name");
    ViewBag.AddressId = new SelectList(db.Addresses, "Id", "Name");
    ViewBag.CityId = new SelectList(db.Cities, "Id", "Name");
    ViewBag.RegionId = new SelectList(db.Regions, "Id", "Name");
    ViewBag.DistrictId = new SelectList(db.Districts, "Id", "Name");
    ViewBag.MicrodistrictId = new SelectList(db.Microdistricts, "Id", "Name");
    ViewBag.StreetId = new SelectList(db.Streets, "Id", "Name");
    ViewBag.VillageId = new SelectList(db.Villages, "Id", "Name");
    var pharmacyVM = new PharmacyVM();
    return View(pharmacyVM);
}

视图中有一个标准的 Razor 代码:

@model MEDONET.Models.PharmacyVM
@{
    ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm("Create", "Pharmacies", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    <div class="form-horizontal">
        <h4>pharmacyProp</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="form-group">
            @Html.LabelFor(model => model.companyProp, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("CompanyId", null, "", htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.companyProp.Id, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.pharmacyProp.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.pharmacyProp.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.pharmacyProp.Name, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.addressProp.City, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("CityId", null, "", htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.CityId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.CityId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("CityId", null, "", htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.CityId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.addressProp.Village, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("VillageId", null, "", htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.addressProp.VillageId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.addressProp.District, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("DistrictId", null, "", htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.addressProp.DistrictId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.HiddenFor(model => model.addressProp.RegionId)
            @Html.LabelFor(model => model.addressProp.Region, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("RegionId", null, "", htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.addressProp.RegionId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.addressProp.Microdistrict, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("MicrodistrictId", null, "", htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.addressProp.MicrodistrictId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.addressProp.Building, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.addressProp.Building, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.addressProp.Building, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.addressProp.Street, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("MicrodistrictId", null, "", htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.addressProp.MicrodistrictId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.pharmacyProp.IsGov, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                <div class="checkbox">
                    @Html.EditorFor(model => model.pharmacyProp.IsGov)
                    @Html.ValidationMessageFor(model => model.pharmacyProp.IsGov, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.companyProp, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("companyId", null, "", htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.pharmacyProp.CompanyId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.pharmacyProp.LargeImage, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                <input type="file" name="LargeImageFile" required />
            </div>
        </div>



        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}
<div> @Html.ActionLink("Back to List", "Index")</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

然后在 Create 方法的 Post 动作中,我尝试创建 b 和 c 变量:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(PharmacyVM model, HttpPostedFileBase LargeImageFile)
{
    if (ModelState.IsValid)
    {
        string LargeImageFileName = Path.GetFileNameWithoutExtension(LargeImageFile.FileName);
        string LargeImageExtansion = Path.GetExtension(LargeImageFile.FileName);

        LargeImageFileName = LargeImageFileName + DateTime.Now.ToString("yymmssfff") + LargeImageExtansion;
        LargeImageFileName = Path.Combine(Server.MapPath("~/Images/Pharmacy/Banners/"), LargeImageFileName);
        int b = model.CityId;

        int c = model.addressProp.RegionId.Value;
        //Address address = new Address()
        //{
        //    Id = 12,//db.Addresses.AsEnumerable().Last().Id + 1,
        //    RegionId = PharmacyVM.Address.RegionId,
        //    DistrictId = PharmacyVM.Address.DistrictId,
        //    CityId = PharmacyVM.Address.CityId,
        //    MicrodistrictId = PharmacyVM.Address.MicrodistrictId,
        //    StreetId = PharmacyVM.Address.StreetId,
        //    VillageId = PharmacyVM.Address.VillageId,
        //    Building = PharmacyVM.Address.Building,
        //    Cab = PharmacyVM.Address.Cab
        //};
        //Address address = new Address
        //{
        //    Id = 12,//db.Addresses.AsEnumerable().Last().Id + 1,
        //    RegionId = 1,
        //    DistrictId = 1,
        //    CityId = 1,
        //    MicrodistrictId = 1,
        //    StreetId = 1,
        //    VillageId = 1,
        //    Building = "1",
        //    Cab = "1"
        //};
        //db.Addresses.Add(address);
        db.SaveChanges();
        var pharmacy = new Pharmacy
        {
            Name = model.pharmacyProp.Name,
            //AddressId = address.Id,
            IsGov = model.pharmacyProp.IsGov,
            CompanyId = model.pharmacyProp.CompanyId,
            LargeImage = "~/Images/Pharmacy/Banners/" + LargeImageFileName
        };
        LargeImageFile.SaveAs(LargeImageFileName);
        db.Pharmacies.Add(pharmacy);
        db.SaveChanges();
        ModelState.Clear();
        return RedirectToAction("Index");
    }

}

与第一个变量 b 不同,第二个变量 c 将是 null,因为 addressProp 属性是 null

那为什么这么奇怪呢?如何在不复制原始模型字段的情况下使用 ViewModel?

【问题讨论】:

  • 这里有太多糟糕的代码,很难知道从哪里开始。查看模型包含数据模型。它们包含视图中所需的各种模型的属性。当使用视图模型时,您将从不使用ViewBag(您的视图模型将包含下拉列表的IEnumerable&lt;SelectListItem&gt; 属性)。而且您没有创建与您的addressProp 模型相关的任何表单控件,因为您的命名然后VillageId 和您的PharmacyVM 模型不包含名为VillageId 的属性(但您的addressProp 模型包含)
  • 建议您首先查看this Q/A 中的代码,以了解如何正确定义视图模型并在视图中生成下拉列表
  • 你能举个小例子吗?我只想在我的视图模型中使用这三个字段代表三个 POCO 类。
  • 我给你的链接包含一个例子。您的视图模型将包含属性(例如)int? CompanyIdIEnumerable&lt;SelectListItem&gt; CompanyList,然后将 @Html.DropDownList("CompanyId", null, ...) 替换为 @Html.DropDownListFor(m =&gt; m.CompanyId, Model.CompanyList, ...)。它将包含(比如)int? MicrodistrictIEnumerable&lt;SelectListItem&gt; MicrodistrictList,您将用 @Html.DropDownListFor(m =&gt; m.Microdistrict, Model.IEnumerable, ...) 替换 @Html.DropDownList("MicrodistrictId", null, ... ),所有其他属性同上
  • 它还将包含一个属性HttpPostedFileBase LargeImageFile 和视图@Html.TextBoxFor(m =&gt; m.LargeImageFile, new { type = "file" }) 用于强绑定到文件输入

标签: c# asp.net model-view-controller viewmodel


【解决方案1】:

你为什么要使用

int b= model.addressProp.RegionId.Value

而不是

int b=model.addressProp.RegionId

即使为了你的好绳子,最好和好的方法是移除所有 View bag 和 将所有 View bag 属性添加到 PharmacyVM 类 不要使用两个属性来绑定视图

例子

 public class PharmacyVM
    {
        public Pharmacy pharmacyProp { get; set; }
        public Address addressProp { get; set; }
        public Company companyProp { get; set; }
        public int CityId { get; set; }

        public SelectList CityIdList { get; set; }     

        public PharmacyVM()
        {
            pharmacyProp = new Pharmacy();
            addressProp = new Address();
            companyProp = new Company();
            CityIdList =new SelectList(db.Cities, "Id", "Name");
        }
    }

    public ActionResult Create()
        { 
            var pharmacyVM = new PharmacyVM();
            return View(pharmacyVM);
        }

@model PharmacyVM
@using (Html.BeginForm())
{
    @Html.HiddenFor(m => m.CityId )

    <div class="editor-label">
        @Html.LabelFor(m => m.Name)
    </div>
    <div class="editor-field">
        @Html.EditorFor(m => m.Name)
        @Html.ValidationMessageFor(m => m.Name)
    </div> 

    <button type="submit">Create</button>
}

       [HttpPost]
        public ActionResult Create(PharmacyVM model)
        {
            int c = model.addressProp
            return View(viewModel);
        }

More Information

【讨论】:

  • 我的所有属性(addressProp、pharmacyProp 和 companyProp)都是空的(null)。可以举个小例子吗
  • 我改了答案
  • 谢谢。但这不是我所期待的。我只想使用 pharmacyProp、addressProp、companyProp。字段 CityId 实际上位于 Address 类中。由于它们是空的,我只是尝试在 ViewModel 中创建该字段。但我认为复制原始类中的所有字段并不是一个好主意。
猜你喜欢
  • 1970-01-01
  • 2022-09-27
  • 1970-01-01
  • 1970-01-01
  • 2019-12-03
  • 2015-01-11
  • 1970-01-01
  • 2019-12-28
  • 1970-01-01
相关资源
最近更新 更多