MVC 5 Delete Action in Details Page

Lernas picture Lernas · Jan 3, 2017 · Viewed 18.2k times · Source

In this MVC5 project, I want my Details page to also serve as Edit page and Delete page.

I'm tackling this task by creating 2 forms, one with everything needed to update the data, including the submit button.

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

    @Html.HiddenFor(model => model.EmpresaID)
    ...
    <input type="submit" class="btn btn-primary" value="Submeter" />
}

Now, for my second form, I basicly have a Delete button:

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(model => model.EmpresaID)
    <input type="submit" class="btn btn-danger" value="Delete" />
}

Error:

The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Threading.Tasks.Task`1[System.Web.Mvc.ActionResult] DeleteConfirmed(Int32)'

I tried to use a ActionLink, but then I get a HTTP 404. Which is odd, since I am being sent to the correct destination:

@Html.ActionLink("Delete", "Delete", new { id = Model.EmpresaID })

Sends to

.../Empresa/Delete/6

EDIT1

Action Method:

// POST: Empresa/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> DeleteConfirmed(int id)
        {
            Empresa empresa = await db.Empresas.FindAsync(id);
            db.Empresas.Remove(empresa);
            await db.SaveChangesAsync();
            return RedirectToAction("Index");
        }

EDIT2

Action Method

// POST: Empresa/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Delete([Bind(Include = "EmpresaID,Nome,Estado,Severidade,Inicio,Fim")] Empresa empresa)
{
    //Do something with the posted viewModel
    Empresa e = await db.Empresas.FindAsync(empresa.EmpresaID);

    db.Empresas.Remove(e);

    return RedirectToAction("Index");
}

Details.cshtml:

@using (Html.BeginForm("Delete", "Empresa", FormMethod.Post))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(model => model.EmpresaID)
    @Html.ActionLink("Delete", "Delete", new { id = Model.EmpresaID })
    <button type="submit" class="btn btn-danger" value="Delete">Delete</button>
}

The ActionLink does not show any errors, but it doesn't delete anything either.

The Button gives me a HTTP 404. What am I doing wrong here?

EDIT3

    // POST: Empresa/Delete/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Delete([Bind(Include = "EmpresaID,Nome,Estado,Severidade,Inicio,Fim")] Empresa empresa)
    {
        //Do something with the posted viewModel
        Empresa e = await db.Empresas.FindAsync(empresa.EmpresaID);

        db.Empresas.Remove(e);
        await db.SaveChangesAsync();
        return RedirectToAction("Index");
    }

The only problem with EDIT2 was that I forgot to save the changes.

It's now working properly.

Answer

Gareth picture Gareth · Jan 3, 2017

You need to tell the form which action to complete along with the FormMethod i.e. GET or POST. So for your delete action for example, something like this:

@model MyProject.SomeViewModel

@using (Html.BeginForm("Delete", "Empresa", FormMethod.Post))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(model => model.EmpresaId)

    <button type="submit" class="btn btn-danger" value="Delete">Delete</button>
}

And then in your controller something like:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Delete(SomeViewModel viewModel)
    {
        //Do something with the posted viewModel

        return RedirectToAction("Index");
    }