0

My application needs to CRUD contracts, and I can attach documents to each contract. So, in my Edit/Update page, I have three forms:

  • one to update the contract properties (Edit.cshtml)
  • one to add document(s) to the contract (AddDocument.cshtml)
  • one to remove a document from the contract (not necessary to show)

and it looks like this:

Edit.cshtml

@model ContractViewModel
@Html.Action("AddDocument", "Contracts", new { id = Model.IdContract })
@Html.Action("RemoveDocument", "Contracts", new { id = Model.IdContract })
@using (Html.BeginForm("Edit", "Contracts", FormMethod.Post, new { @class = "form-horizontal", enctype = "multipart/form-data" }))
{
     @Html.AntiForgeryToken()
     @Html.ValidationSummary(true)
     @Html.HiddenFor(model => model.IdContract)
     <div class="form-group">
          @Html.LabelFor(model => model.ContractNumber, htmlAttributes: new { @class = "control-label col-md-4" })
          <div class="col-md-8">
               @Html.EditorFor(model => model.ContractNumber, new { htmlAttributes = new { @class = "form-control" } })
               @Html.ValidationMessageFor(model => model.ContractNumber)
          </div>
    </div> [...]
    <input type="submit" value="Update"/>
}

AddDocument.cshtml

@model DocumentViewModel
@using (Html.BeginForm("AddDocument","Contracts", FormMethod.Post, new { @class = "form-horizontal", enctype="multipart/form-data" }))
{
        @Html.AntiForgeryToken()
        @Html.HiddenFor(model => model.IdContract)
        <div class="form-group">
             @Html.LabelFor(model => model.DocHttp, htmlAttributes: new { @class = "control-label col-md-2" })
             <div class="col-md-10">
                  @Html.TextBoxFor(x => x.DocHttp, htmlAttributes: new { @class = "form-control", data_style = "btn-primary", type = "file", multiple = "multiple" })
                  @Html.ValidationMessageFor(model => model.DocHttp)
             </div>
        </div>
        <input type="submit" value="Add"/>
}

ContractController.cs

public ActionResult Edit(int? id)
{
    if (id == null)
    {
        throw new HttpException(400, "Bad request");
    }
    Contract contract = business.Get<Contract>(x => x.IdContract == id);
    ContractViewModel vm = new ContractViewModel(contract);
    if (contract == null)
    {
        throw new HttpException(404, "Not found");
    }            
    return View(vm);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(ContractViewModel vm)
{
    Contract contract = business.Get<Contract>(x => x.IdContract == id);
    if (ModelState.IsValid)
    {
        [...]
    }
    return View(vm);
}

public ActionResult AddDocument(int id)
{
    DocumentViewModel vm = new DocumentViewModel();
    vm.IdContract = id;
    return PartialView(vm);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddDocument(DocumentViewModel vm)
{
    Contract contract = business.Get<Contract>(x => x.IdContract == vm.IdContract);            
    if (ModelState.IsValid)
    {
        [...]
    }
    return RedirectToAction("Edit", "Contracts", new { id = vm.IdContract });
    //return View(vm);
}

Firstly, the issue is, when I submit the Edit form, the [HttpPost]Edit method is naturally called, but also the [HttpPost]AddDocument. Is that due to the Html.Action used instead of Html.RenderPartial?

If I'm right, the Html.Action is called when you have to do a treatment before generating the partial view, while Html.RenderPartial passes just parameters.

Why is the [HttpPost]AddDocument method called? and who called it?

Secondly, to bypass the problem, I have to Redirect to the Edit page instead of calling the View method. But, I'm losing the data entered. How can I manage this problem?

Thanks.

madhatterx
  • 33
  • 7

1 Answers1

0

[...] but also the [HttpPost]AddDocument. Is that due to the Html.Action used instead of Html.RenderPartial?

You can have multiple forms in a view and each form will only call the correspondent controller method.

If I'm right, the Html.Action is called when you have to do a treatment before generating the partial view, while Html.RenderPartial passes just parameters.

Check this post

Basically when calling @html.Partial you are importing the html without a controller call. If that partial view is strongly typed you need to make sure that the current model of the view where you are making the call has the model needed to that partial.

Because you have a partial view that has a diferent model from the calling view model you have two choices:

1- same as your solution, call the action method and create the model to that view

2- the model you pass to the view that calls @Html.renderPartial or @Html.Partial must include the model you need in the partial. Usage example @Html.Partial("SomePartialview",Model.thePartialViewModel)

Secondly, to bypass the problem, I have to Redirect to the Edit page instead of calling the View method. But, I'm losing the data entered. How can I manage this problem?

Data is not persisted between redirects.

You could do this and/or read this

Community
  • 1
  • 1
Kharlos
  • 21
  • 6
  • thanks but your answer didn't help me. I wanted to know why are my 3 HttpPost methods called (Edit, AddDocument, RemoveDocument) when I was supposed to call the Edit method only. – madhatterx Sep 21 '16 at 21:27
  • i couldn´t replicate your issue in a newly created project . Maybe some culry braces out of place? – Kharlos Sep 22 '16 at 08:51