ASP.NET MVC: Why request is being caught by the wrong method? - c#

I'm using to wrap my forms the following helper:
#using (Html.BeginForm("Edit", "MyController", FormMethod.Post)) { ... }
In my Controller I have two methods, one for loading my partial view and another one for processing the Post request:
[SomeFilter]
[ChildActionOnly]
[AcceptVerbs(HttpVerbs.Get)]
public PartialViewResult Edit(int id)
{
//Some Code
}
[SomeFilter]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MyViewModel model, string submit) {
//Some Code
}
Everything seems to be working fine except when users submit an empty form. In that case request is being caught by GET Method instead of POST one. I know it's calling the GET method because I get an exception as:
"The action 'Edit' is accessible only by a child request."
And only the GET overload has [ChildActionOnly] filter. I don't understand why is this happening. Both are different and both are decorated.
Any suggestions?
Partial View code:
#model MVC.Models.MyViewModel
#using (Html.BeginForm("Edit", "MyController", FormMethod.Post))
{
#Html.HiddenFor(m => m.Id)
#Html.AntiForgeryToken()
<div class="row margin-top-20 form-group text-center">
<div class="col-md-3 col-lg-offset-2">
#Html.LabelFor(m => m.ManyItemsAvailable)
#Html.ListBox("ManyItemsAvailable", Model.ItemsAvailable)
</div>
<input type="submit" class="btn btn-default" value=">" id="add" name="submit" />
<input type="submit" class="btn btn-default margin-top-10" value="<" id="remove" name="submit" />
<div class="col-md-3">
#Html.LabelFor(m => m.ManyItemsSelected)
#Html.ListBox("ManyItemsSelected", Model.ItemsSelected)
</div>
</div>
}

So, I replaced both submit buttons with these:
<input type="submit" class="btn btn-default" value=">" id="add" name="submit" />
<input type="submit" class="btn btn-default margin-top-10" value="<" id="remove" name="submit" formmethod="post" />
Explicitly specifying formmethod="post" and it's now working as expected.

Related

Why is my HTTP edit post method not working?

When I try to submit my form, my request is not reaching the Post-method 'Edit and is returning HTTP Error Code 415.
My Razor page does not fire an action, I am using metronic theme integration and then not working post method. The following is the server-side code:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [FromForm] Firma firma)
{
//code here[enter image description here][1]
}
And the following is the client side code:
#model satinalma.Models.Firma
#{
ViewData["Title"] = "Edit";
}
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Baslik" class="control-label"></label>
<input asp-for="Baslik" class="form-control" />
<span asp-validation-for="Baslik" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
You've got the asp-action tag helper for the method, but not one for the controller. Try adding that and see if it routes properly.
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1

ASP.NET core 2.2 Unhandled exception when creating a form

I am currently creating a web application that takes in a new user, adds their information to a list, and then displays the users. When I follow the link to my form with validation (a form I have used many times before in other projects) I am getting an unhandled exception.
Here is the specific error code
AspNetCore.Views_Home_RegisterNewUser.<ExecuteAsync>b__12_0() in RegisterNewUser.cshtml, line 15
To this point, I have double checked that the model is correct and has the correct validation. I have made sure the controller and action are correct.
Here is the page for the form
#{
ViewData["Title"] = "RegisterNewUser";
}
<h1>RegisterNewUser</h1>
#model Lab20.Models.RegisterUser
#Html.ValidationSummary()
<form asp-controller="Home" asp-action="ListAllUser" method="post" class="bg-dark">
<div class="col-12">
First Name:
<input type="text" name="FirstName" value="#Model.FirstName" placeholder="#Model.FirstName" class="col-5" />
#Html.ValidationMessageFor(m => m.FirstName)
</div>
<div class="col-12">
Last Name: <input type="text" name="Last Name" value="#Model.LastName" placeholder="#Model.LastName" class="col-5" />
#Html.ValidationMessageFor(m => m.LastName)
</div>
<div class="col-12">
Birthday: <input type="datetime" name="Birthday" value="#Model.Birthday" placeholder="#Model.Birthday" class="col-5" />
#Html.ValidationMessageFor(m => m.Birthday)
</div>
<div class="col-12">
Email: <input type="text" name="Email" value="#Model.Email" placeholder="#Model.Email" class="col-5" />
#Html.ValidationMessageFor(m => m.Email)
</div>
<div class="col-12">
Password: <input type="text" name="Password" value="#Model.Password" placeholder="#Model.Password" class="col-5" />
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="col-12">
Favorite Color: <input type="text" name="FavoriteColor" value="#Model.FavoriteColor" placeholder="#Model.FavoriteColor" class="col-5" />
#Html.ValidationMessageFor(m => m.FavoriteColor)
</div>
<input type="submit" value="Add User" />
</form>
Here is the HomeController
public class HomeController : Controller
{
List<RegisterUser> listOfUsers = new List<RegisterUser>() { };
public IActionResult Index()
{
return View();
}
[HttpGet]
public IActionResult RegisterNewUser()
{
return View();
}
[HttpPost]
public IActionResult RegisterNewUser(RegisterUser newUser)
{
if (!ModelState.IsValid)
{
return View(newUser);
}
else
{
return View("AddNewUser", newUser);
}
}
public IActionResult AddNewUser(RegisterUser user)
{
listOfUsers.Add(user);
return View("Index");
}
public IActionResult ListAllUsers()
{
return View();
}
}
I would like my page to firstly, display, secondly, catch the validation I have added, and thirdly take the new user's information and display it in the ListAllUsers View.
<form asp-controller="Home" asp-action="RegisterNewUser" method="post" class="bg-dark">
</form>
your form post action will be in RegisterNewUser method, you're pointing it wrong in ListAllUsers.
hope, you get it
You form is posing to the action ListAlluser in the controller Home. Now according to your code, you don't have an action method by that name.
The correct asp-action parameter should be RegisterNewUser. So the code becomes
<form asp-controller="Home" asp-action="RegisterNewUser" method="post" class="bg-dark">
</form>

File upload ASP.NET MVC in multiple submits form

I have a small tool that downloads reports based on the specified options. The download works well. And now, I want to also upload a file to the folder and then further use it.
The problem is that I already have one submit button on the form that is used for the download and when I am adding another button for the upload, only download is triggered.
I tried to resolve it using an #Html.ActionLink(), but no success. Is there any proper way to resolve the issue? I know that there is a possibility to capture the submit value and then check in one main ActionResult in the Controller and redirect to the respective ActionResult, but I don't want to do it, since there are too many POST Actions in one controller.
Here is my View - download.cshtml:
#using (Html.BeginForm())
{
<fieldset>
<div class="title">Click to download report</div>
<div class="field">
<input id="downloadBtn" type="submit" class="button" value="Download" />
</div>
</fieldset>
<fieldset id="Option_ClientInfo">
<div class="title">
Image
</div>
<div class="field">
<input type="file" name="ImageUpload" accept="image/jpeg" />
<p>#Html.ActionLink("Upload", "UploadImage", new { controller = "Home", enctype = "multipart/form-data"}, new { #class = "button" })</p>
</div>
</fieldset>
}
And the controller - HomeController.cs:
public partial class HomeController : Controller
{
// some functions
// ....
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UploadImage(HttpPostedFileBase imageFile)
{
string path = Path.Combine(this.GetImageFolder, Path.GetFileName(imageFile.FileName));
imageFile.SaveAs(path);
return null;
}
// additional POST functions for other forms
// ....
[HttpPost]
public ActionResult Download(Info downloadInfo)
{
// perform checks and calculations
return new reportDownloadPDF(downloadInfo);
}
}
Any suggestion in appreciated.
The solution is just separate upload and download functionalities using two forms so it wont conflict while submitting.
#using (Html.BeginForm())
{
<fieldset>
<div class="title">Click to download report</div>
<div class="field">
<input id="downloadBtn" type="submit" class="button" value="Download" />
</div>
</fieldset>
<fieldset id="Option_ClientInfo">
<div class="title">
Image
</div>
</fieldset>
}
#using (Html.BeginForm("UploadImage", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<fieldset>
<div class="field">
<input type="file" name="ImageUpload" accept="image/jpeg" />
<p>
<input id="uploadBtn" type="submit" class="button" value="Upload" />
</p>
</div>
</fieldset>
}
There is another issue as well. Image control name and Post Action method parameter name should be same.
So your upload image Post Action method will be:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UploadImage(HttpPostedFileBase imageUpload)
{
string path = Path.Combine(this.GetBasePath + "/img/tmp/", Path.GetFileName(imageFile.FileName));
imageFile.SaveAs(path);
return null;
}

Model not getting passed to controller

I have this index view:
#model LeadManager.Models.ProspectingApprovalViewModel
#{
ViewBag.Title = "Index";
}
<h2>Approve Or Reject</h2>
<div class="form-horizontal">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-group">
<div>
<input type="submit" name="ApprovalAction" value="Approve" class="btn btn-default" />
<input type="submit" name="ApprovalAction" value="Reject" class="btn btn-default" />
</div>
</div>
}
</div>
//model details are below form
I am trying to read the model inside controller like so:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(ProspectingApprovalViewModel prospectingApprovalViewModel, string ApprovalAction)
{
//access model
}
I can read ApprovalAction but the prospectingApprovalViewModel is null on the postback.
Why is the model not being attached?
Your helper must be inside the form.
When you use two class in parameter in name of html helper must be
name="className.propetyName".
When you want to post two classes you must use ViewModel.

How I can use html tags with bootstrap in asp.net mvc for get a result from controller?

Hey Guys I have a problem with my ASP.NET MVC Application. I want to make a Search textfield and a image button in my application. If I input a valu in the textfield I want use this value for search in a list and send the result to the View. I use bootstrap because it looks fine.
here is my code: Index.cshtml
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("Search", "HomeController"))
{
<div class="container">
<div class="row">
<h2>Suche</h2>
<div id="custom-search-input">
<div class="input-group col-md-12">
<input type="text" id="txtSearch" class=" search-query form-control" placeholder="Search" name="txtSearch" />
<span class="input-group-btn">
<button class="btn btn-danger" type="submit">
<span class=" glyphicon glyphicon-search"></span>
</button>
</span>
</div>
</div>
</div>
</div>
}
Here is my Controller:
[HttpPost]
public ActionResult Search(string txt)
{
List<string> petList = new List<string>();
petList.Add(txt);
ViewBag.liste = petList;
return View();
}
Your input does not have a name attribute that matches the parameter in the method so it is not bound. Change it to
<input type="text" id="txtSearch" class="..." name="txt" />
or change the method to match the current name attribute
[HttpPost]
public ActionResult Search(string txtSearch)
Side note: Assuming your controller is named HomeController then it should be #using (Html.BeginForm("Search", "Home")), not #using (Html.BeginForm("Search", "HomeController")) (which would only work if you have a controller named HomeControllerController)

Categories