Eon
Eon

Reputation: 3974

Why does my method not run when I attempt to delete a Record from my database using a strongly-typed Delete View?

I am currently baffled to why my method is not running. I placed a breakpoint on it because I suspect some failure to occur somewhere.

Here is my explanation:

I just started a new ASP.NET MVC 2 application. I Connected my Home/Index page to a new strongly-typed view which I have created called Categories/List. Everything Displays fine - the categories are retrieved from my Entity Data model and placed on the page. I removed the "Details" link which is automatically created with the view.

Afterwards, I added a strongly Typed Delete View to Categories/Delete. In my CategoriesController, I have the following code (Which works)

      <%: Html.ActionLink("Delete", "DeleteCategory", new { id=item.CategoryID })%>

to:

    /// <summary>
    /// Get rid of a Category
    /// </summary>
    /// <returns>Redirect to ~/Categories/Delete</returns>
    public ActionResult DeleteCategory(int id)
    {
        ViewData.Model = (from c in DataContext.Categories where c.CategoryID == id select c).FirstOrDefault();
        return View("Delete");
    }

My Delete View Looks like this:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<PracticeApp.Models.Category>" %>

Delete

<h2>Delete</h2>

<h3>Are you sure you want to delete this?</h3>
<fieldset>
    <legend>Fields</legend>

    <div class="display-label">CategoryID</div>
    <div class="display-field"><%: Model.CategoryID %></div>

    <div class="display-label">Category1</div>
    <div class="display-field"><%: Model.Category1 %></div>

</fieldset>
<% using (Html.BeginForm()) { %>
    <p>
        <input type="submit" value="Delete" /> |
        <%: Html.ActionLink("Back to List", "List") %>
    </p>
<% } %>

Ok. This will all seem familiar to MVC Experts. Mind, I just started with MVC and I do not have Extremely good knowledge with Linq Either, so I am expecting some flaming from my following Code (Which doesn't even run - the purpose of the question - I don't know why it does not run!)

It is in my categoriesController

    [HttpPost]
    public ActionResult Delete(Models.Category category)
    {
        foreach (Models.Category c in DataContext.Categories)
        {
            if (c.CategoryID == category.CategoryID)
            {
                DataContext.Categories.DeleteObject(c);
            }
        }
        DataContext.SaveChanges();

        return RedirectToAction("List", "List", "Categories");
    }

Any Ideas as to why my code refuses to run? I breakpointed at the first brace. Breakpoint never gets reached.

Upvotes: 0

Views: 134

Answers (3)

Eon
Eon

Reputation: 3974

Just thought I'd post my completed result. Pbirkoff Helped a lot with the Hidden Field which I completely forgot even existed, and Darin helped me research my problem.

    [HttpPost]
    public ActionResult Delete(int CategoryID,FormCollection FC)
    {
        DC.Categories.DeleteObject((from c in DC.Categories where c.CategoryID == CategoryID select c).FirstOrDefault());
        DC.SaveChanges();
        return RedirectToAction("list", "categories");
    }

This is a project recreation from scratch. DC is my Entity Data Model (shorted DataContext, but this is only a practice app).

I added this to my delete view.

" %>

Delete

<h2>Delete</h2>

<h3>Are you sure you want to delete this?</h3>
<fieldset>
    <legend>Fields</legend>

    <div class="display-label">CategoryID</div>
    <div class="display-field"><%: Model.CategoryID %></div>

    <div class="display-label">Category1</div>
    <div class="display-field"><%: Model.Category1 %></div>

</fieldset>
<% using (Html.BeginForm()) { %>
    <p>
        <input type="submit" value="Delete" /> |
        <%: Html.ActionLink("Back to List", "List") %>
    </p>
    **<input type="hidden" name="CategoryID" value = "<%: Model.CategoryID %>" />**
<% } %>

(the hidden field. note that the ** is not in the actual code. its to point out what I added)

Upvotes: 0

Darin Dimitrov
Darin Dimitrov

Reputation: 1038930

The problem is that your GET action (DeleteCategory) doesn't have the same as your POST action (Delete).

So you need to specify the action you want to invoke:

<% using (Html.BeginForm("Delete", "Categories")) { %>

Or if you don't want to do that you should rename your GET method to be he same as the POST method:

// Access this action with /Categories/Delete
public ActionResult Delete(int id)
{
    var model = DataContext.Categories.FirstOrDefault(x => x.CategoryID == id);
    return View(model);
}

[HttpPost]
public ActionResult Delete(Category category)
{
    ...
}

Now since both your GET and POST actions are named the same way, you could use the BeginForm helper without arguments because the distinction between those actions will be based on the HTTP verb used to invoke them:

<% using (Html.BeginForm()) { %>

As a side note inside your form you don't have any input field. So don't expect to get anything out of this Category that your POST action expects. You might need to at least include a hidden field containing the id of the category that you are willing to delete.

Upvotes: 1

Pbirkoff
Pbirkoff

Reputation: 4702

The problem is, you're not posting anything in your form on the confirmation page. Therefor, MVC isn't able to bind to the category model.

To get the id of the item you want to delete, use the same way as the normal view:

[HttpPost]
public ActionResult Delete(int id)
{
     //delete item
}

When you do this, you will probably get an error, because there are two methods with the same overloads. There, I usally create an extra parameter and give a value for that along with the posted-form, like this:

[HttpPost]
public ActionResult Delete(int id, bool confirm)
{
    foreach (Models.Category c in DataContext.Categories)
    {
        if (c.CategoryID == category.CategoryID)
        {
            DataContext.Categories.DeleteObject(c);
        }
    }
    DataContext.SaveChanges();

    return RedirectToAction("List", "List", "Categories");
}

Your form will look like this:

<% using (Html.BeginForm()) { %>
    <p>
        <input type="submit" value="Delete" /> |
        <%: Html.ActionLink("Back to List", "List") %>
    </p>
    <input type="hidden" name="confirm" value="true" />
<% } %>

One thing that always helped me is reminding myself that a MVC-page (like any webpage) is stateless. So your current request doesn't know anything about your previous request. Any data you need in the process, you will have to put it yourself. So if you want to bind the a category, you will have to provide the data for the category in your form. Because you showed a model on a page, doesn't mean that this data is still available on your next request.

Upvotes: 1

Related Questions