仅在视图中编辑对象的一部分,但将整个obj传递给ActionListener

时间:2018-01-04 02:58:03

标签: c# asp.net razor asp.net-mvc-5 azure-cosmosdb

我有一个带有提交按钮的表单,该表单应该将项目传递给actionlistener。我认为这可能与@Html.HiddenFor does not work on Lists in ASP.NET MVC中的问题相似,但没有一个答案似乎有效。你甚至可以从那里的一个答案中看到我的for循环。

[ 编辑:我已经摆脱了大量的隐藏循环并替换为@ Html.EditorFor,以便您可以看到,即使没有隐藏,标志列表也不会到达actionlistener。这是一个问题,因为当有人编辑标志时,无法更新数据库,因为我无法更新标志的ID。 ]

控制器中的ModelState永远不会有效,无论我是否保留" [Bind(包括="有没有。因为教程为 ASP.NET MVC Tutorial: Web application development with Azure Cosmos DB

ItemController.cs:

    [HttpPost]
    [ActionName("ProductEdit")]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> EditProductAsync( [Bind(Include = "Id, Name, Flags")] Item model)
    {
        Item product = await DocDBRepo<Item>.GetItem(model.Id);
        model.Organisations = product.Organisations;

        if (ModelState.IsValid) //Checks item validation via "required" set on properties
        {
            await DocDBRepo<Item>.UpdateItemAsync(model.Id, model);
            return RedirectToAction("Index");
        }

        return View(model);
    }

    [HttpGet]
    [ActionName("ProductEdit")]
    public async Task<ActionResult> EditProductAsync(string id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        Item item = await DocDBRepo<Item>.GetItem(id);
        if (item == null)
        {
            return HttpNotFound();
        }

        return View(item);
    }

ProductEdit.cs:

@model RRPortal.Models.Item

@{
    ViewBag.Title = "ProductEdit";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>ProductEdit</h2>


@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.Id)

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

    <div class="form-group">
        @Html.LabelFor(model => model.Flags, htmlAttributes: new { @class = "control-label col-md-2 " })
    </div>

    @*Flags list*@
    @for (int i = 0; i < Model.Flags.Count; i++)   //foreach (var flag in Model.Flags)
    {

        <div class="form-group">
            //@Html.HiddenFor(modelItem => Model.Flags[i].Id)
            @Html.Label(Model.Flags[i].Name, htmlAttributes: new { @class = "control-label col-md-3" })
            @Html.LabelFor(modelItem => Model.Flags[i].Enabled, htmlAttributes: new { @class = "control-label col-md-1" })
            <div class="col-md-8">
                @Html.EditorFor(modelItem => Model.Flags[i].Enabled, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(modelItem => Model.Flags[i].Enabled, "", new { @class = "text-danger" })
            </div>
        </div>
    }

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
</div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Item.cs:

public class Item
{
    [JsonProperty(PropertyName = "id")]
    public string Id { get; set; }

    [Required]
    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "flags")]
    public List<Flag> Flags { get; set; }

    [JsonProperty(PropertyName = "organisations")]
    public List<Organisation> Organisations { get; set; }
}

public class Flag
{
    [JsonProperty(PropertyName = "id")]
    public int Id { get; set; }

    [Required]
    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [Required]
    [JsonProperty(PropertyName = "enabled")]
    public bool Enabled { get; set; }
}

public class Organisation
{
    [JsonProperty(PropertyName = "id")]
    public int Id { get; set; }

    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "users")]
    [Display(Name ="Users")]
    public List<User> UserStore { get; set; }
}

public class User
{
    [JsonProperty(PropertyName = "id")]
    public int Id { get; set; }

    [Required]
    [JsonProperty(PropertyName = "fname")]
    public string FName { get; set; }

    [Required]
    [JsonProperty(PropertyName = "lname")]
    public string LName { get; set; }

    [Required]
    [Display(Name = "Admin?")]
    [JsonProperty(PropertyName = "isadmin")]
    public bool IsAdmin { get; set; }
}

当我调试控制器时,项目的ID和名称通过并且不为空,但标志列表始终为空。 ModelState显示以下异常:{&#34;参数转换类型&#39; System.String&#39;输入&#39; RRPortal.Models.Flag&#39;失败,因为没有类型转换器可以在这些类型之间进行转换。&#34;}

flags obj still empty

我也被问到ModelState在哪里显示异常,所以下面是截图: Exception on modelstate

如果有人有任何问题,我会很乐意更新这个问题。我一直在调整视图2天,仍然无法获得包含任何内容的项目。渲染的HTML似乎完全包含组织和内部对象。

感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

我的猜测是,在HttpGet视图中,您有以下内容:

[HttpGet]
public ActionResult EditProductAsync()
{
    var model = new ProductViewModel()
    {
        Flags = _uow.Products.GetFlags(),
        Organisations = _uow.Products.GetOrganisations()
    };

    return View(model);
}

因为这些对象也不是作为表单的一部分返回的,所以它们将返回到服务器为空,这会为您抛出错误,从而使模型无效。在检查模型是否有效之前,您应该首先执行以下操作:

[HttpPost]
[ActionName("ProductEdit")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> EditProductAsync( [Bind(Include = "Id, Name, Flags, Organisations")] Item model)
{
    model.Organisations = _uow.Products.GetOrganisations();
    model.Flags = _uow.Products.GetFlags();

    if (ModelState.IsValid)
    {
        await DocDBRepo<Item>.UpdateItemAsync(model.Id, model);

        return RedirectToAction("Index");
    }

    return View(model);
}

通过填充这些字段,您所遇到的任何模型错误都是您提交表单时客户的错误。