1

I'm following this tutorial >> http://www.asp.net/mvc/tutorials/mvc-4/getting-started-with-aspnet-mvc4/examining-the-edit-methods-and-edit-view

And i got a question that makes me puzzled!

In my controller class "MoviesController" I got a method Edit and an overload, one of these methods is used when the user start to editing a record and another used to post the changes.

My question is how the page knows which method it must calls, I know that's using the parameters, but looking to code I didn't find anything that could track the request.

Here goes the code:

Edit.cshtml

@model SmartJob.Models.Movie

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

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

    <div class="form-horizontal">
        <h4>Movie</h4>
        <hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.ID)

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

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

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

        <div class="form-group">
            @Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Price)
                @Html.ValidationMessageFor(model => model.Price)
            </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>

MoviesContoller class (only Edit methods)

 // GET: /Movies/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Movie movie = db.Movies.Find(id);
            if (movie == null)
            {
                return HttpNotFound();
            }
            return View(movie);
        }

        // POST: /Movies/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie)
        {
            if (ModelState.IsValid)
            {
                db.Entry(movie).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(movie);
        }
guisantogui
  • 4,017
  • 9
  • 49
  • 93

4 Answers4

1

By default, any requests without an attribute of [HttpGet] or [HttpPost] will be a GET method. You must specify that the method is a [HttpPost] if you are posting against the method(Aka submitting some type of form)

Notice that there is no [HttpGet] or [HttpPost] specified in your first Edit method. Thus it will default to [HttpGet]

// GET: /Movies/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Movie movie = db.Movies.Find(id);
            if (movie == null)
            {
                return HttpNotFound();
            }
            return View(movie);
        }

Now notice how this method has a tag of [HttpPost]. You can also specify other verbs such as [HttpPut], [HttpDelete] and many more if you need to, but these are the most popular that are used. Also notice that you have the [Bind()] method. This is used to prevent sending "Too" much data when you might only want to update a few fields of the object.

        // POST: /Movies/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include="ID,Title,ReleaseDate,Genre,Price")] Movie movie)
        {
            if (ModelState.IsValid)
            {
                db.Entry(movie).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(movie);
        }
Jon Douglas
  • 13,006
  • 4
  • 38
  • 51
0

It uses Http verbs to know which method to call. When you submit a form, it looks for an action with the HttpPost attribute, because it is a POST request. The first action has not verb specified, so the default verb used for it is HttpGet, so you get in using an url defined by your routes (like Movies/Edit/5).

Réda Mattar
  • 4,361
  • 1
  • 18
  • 19
0

It knows via a few things.

The first is on the second Edit action it has been marked as [HttpPost], this tells ASP.NET router to ignore it completely if the request is any other method besides POST. You can mark the first method as [HttpGet] also to make this a little more explicit. (Methods that aren't explicitly marked will respond to all requests to them, so you could to a POST to the first edit with an ID field and it will respond.)

The second is the model that's passed. ActionResult overloads work exactly as a normal function overload, that is that it will automatically pick the function that matches the input. (The [Bind] is just syntactical sugar for the model deserializer so that you can prevent specific database fields from being updated via specific forms.)

The thing that can trip you up is if it can not deserialize the model to the expected type you will get a run time error.

siva.k
  • 1,344
  • 14
  • 24
0

[HttpPost] is an ActionMethodSelectorAttribute which MVC will utilize to determine the correct action method to select based on the HTTP verb in the request.

Additionally MVC will deduce the correct action to call if you have the same action name with different parameters based on the http request parameters... ex:

[HttpGet]
public ActionResult ActionName() {...}

[HttpPost]
public ActionResult ActionName(string aParameter) {...}
Community
  • 1
  • 1
felickz
  • 4,292
  • 3
  • 33
  • 37