简体   繁体   中英

Clarification on wiring up button to an ActionResult

I'm still in the learning process of MVC coming from a long time with Web Forms. One of the things I'm trying to understand is the appropriate way to associate a button/input with an ActionResult.

One of the projects I've been using as an example is Contoso University. In that project they have a CourseController and in the Course/Edit.cshtml page they use a form that doesn't specify the controller or action method. So I'm not completely clear on how the form knows where it needs to go to since neither the form or the button points to the controller/action method. Is it because the page is named Edit and the ActionResult is also named Edit?

This is the Contoso .cshtml and the ActionResult in the controller.

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

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

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

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

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

        <div class="form-group">
            <label class="control-label col-md-2" for="DepartmentID">Department</label>
            <div class="col-md-10">
                @Html.DropDownList("DepartmentID", null, htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.DepartmentID, "", 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>
}

 [HttpPost, ActionName("Edit")]
        [ValidateAntiForgeryToken]
        public ActionResult EditPost(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var courseToUpdate = db.Courses.Find(id);
            if (TryUpdateModel(courseToUpdate, "",
               new string[] { "Title", "Credits", "DepartmentID" }))
            {
                try
                {
                    db.SaveChanges();

                    return RedirectToAction("Index");
                }
                catch (RetryLimitExceededException /* dex */)
                {
                    //Log the error (uncomment dex variable name and add a line here to write a log.
                    ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
                }
            }
            PopulateDepartmentsDropDownList(courseToUpdate.DepartmentID);
            return View(courseToUpdate);
        }

Also another thing I've found with some searching is developers calling the controller/action method in the form as well as pointing to the controller/action method directly in a button or input.

Here they are adding it in the form.

@using (Html.BeginForm("SignUp", "Account", FormMethod.Post))
{
    <!-- form goes here -->

    <input type="submit" value="Sign Up" />
}

Here it is directly in the button.

<button type="button" onclick="location.href='@Url.Action("MyAction", "MyController")'" >

Are there any advantages/disadvantages to using any of these methods? It seems more clear to me if you put the control/method in the form declaration or directly on the button.

Those are simply different overloads of BeginForm method.

@using (Html.BeginForm()) {} will render a form tag where the action attribute value is set to the current page. That means, If you are rendering the create page (Post/Create), This overload will render the below html

<form action="/Post/Create" method="post"></form>

By default, the BeginForm will render the form tag with method value set as " POST ".

The second overload allows you to explicitly specify the target action value

So if you have the below code inside your Create razor view ( Post/Create )

@using (Html.BeginForm("Edit", "Post"))
{
    <input type="text" name="postName" />
}

This will render

<form action="/Post/Edit" method="post">
   <input type="text" name="postName" />
</form>

You need to make sure that you have action method decorated with [HttpPost] attribute to handle the form posting in your controller

[HttpPost]
public ActionResult Edit(string postName)
{
 //to do  : Do something useful
  return View();
}

We have another overload which allows us to specify the Form posting method explicitly. The default is POST and you can use this overload to change it to GET ( But 99% times, you will be using the POST type.)

@using (Html.BeginForm("Edit","Post",FormMethod.Get))
{    
}

You can see all the available overloads here . Try different ones and see the html output generated by those ( You can do "view source" on the page).

Finally, the form will be submitted to the target action when you click a submit button inside the form.

That means, you do not need (and should not do this on normal use cases)

<button type="button" onclick="location.href='@Url.Action("MyAction", "MyController")'" >

but this is enough

@using (Html.BeginForm("Edit", "Post"))
{
  <input type="submit" />
}

Every method have some advantages 1) actionresult name will be display in url also its directly pickup that action result abd its sync call or its directly server call 2) @url.action we use for relative path sometime url not recognized the second level for handling those problem we used @url.action for better understanding for it check absolute and relative path 3) you can make ajax call for async call to get better performance. hope it will help for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM