I have a webapplication made in ASP.NET Core (latest version) which needs to use a pop-up form where 1 value has to be filled in and then send it back to the controller to later use that value.
So the process is like this: Button > Click on button > Pop-up form pops up (Image: pop-up form which is a partial view) > Fill in value > Submit > Send result back to controller.
But whenever I press the submit button it sends me to a 400 error not found page. What could go wrong?
Here is the partial view pop-up form code:
#model IEnumerable<ApplicationName.Models.Moederblad>
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#addTagHelper *, AuthoringTagHelpers
#Html.AntiForgeryToken()
<div id="element_to_pop_up">
<a class="b-close">x</a>
//Actionresult > Controller
#using (Html.BeginForm("Incassodatum", "Moederblads", FormMethod.Post))
{
<br />
<div class="row">
<div class="col-md-6">
<label for="Incassodatum">Incassodatum</label>
<input class="form-control" placeholder="Bijvoorbeeld: 19-02-2020" type="text" data-val="true" data-val-regex="Dat is geen geldige datum" data-val-regex-pattern="^(0[1-9]|[12][0-9]|3[01])[/](0[1-9]|1[012])[/](19|20)[0-9]{2}$, " id="Incassodatum" name="Incassodatum">
</div>
</div>
<div class="row">
</div>
<br>
<input name="__RequestVerificationToken" type="submit" class="btn btn-primary submit" value="Toevoegen" id="submit">
}
</div>
Here is the corresponding controller:
[HttpGet]
public ActionResult Incassodatum()
{
return View();
}
//Automatisch de datum van vandaag in het Incassodatum veld zetten nadat er op een knop is gedrukt
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Incassodatum(string Incassodatum)
{
string date= "";
if (ModelState.IsValid)
{
date = Incassodatum;
}
else
{
date = "Something went wrong.";
}
TempData["Incassodatum"] = $"{Incassodatum}";
return RedirectToAction("Index");
}
Then later I can use the tempdata to read out the value but its not working at all so that is actually useless for now.
I tried adding the [Route("Moederblads/Incassodatum")] property above the post.
I tried it in a normal view (So not a partial view) and there I could see the value with F12.
Tried changing object names as I thought it might conflict with other names.
Don't know what to do now. Any of you have a guess?
But whenever I press the submit button it sends me to a 400 error not found page.
A 400 error is a Bad Request. A 404 is a Not Found. As such, I'm not sure which you're actually getting here. However, based on the fact that you have an input with __RequestVerificationToken as the name, and you're using it wrong at that, I'm leaning towards the 400.
Since you're trying to use this input as a button, you've set a value on it to apply that text to the button. However, that's going to actually post that value for __RequestVerificationToken, and it's not a valid token. As such, you're going to always get a 400 Bad Request because of the failed request verification.
The request verification token should be on a hidden input, so the simplest solution is to remove the name from that button and add a hidden input specifically for the request verification token: #Html.AntiForgeryToken().
Even better would be to use the built-in FormTagHelper instead, which automatically takes care handling antiforgery tokens:
<form asp-action="Incassodatum" asp-controller"Moederblads" method="post">
...
</form>
Finally, while it doesn't technically effect anything, using input for buttons is an anti-pattern that should be avoided. Use <button type="submit"> instead.
Was something very easy in the end: I just had to delete the: [HttpPost] tag above the method and the [HttpGet] method as it did nothing in the end. After that it hit my break point and could verify that the value is coming through fine :)
Related
I need to remove an item in Cart with razor page. For this i used a form with asp-page-handler.
Cart.cshtml :
<td class="text-center">
<form asp-page-handler="Remove" method="post">
<input type="hidden" name="id" value="#line.Product.Id" />
<input type="hidden" name="returnUrl" value="#Model.ReturnUrl" />
<button type="submit" class="btn btn-sm btn-danger">
Remove
</button>
</form>
</td>
And my Cart.html.cs has a OnPostRemove method like this:
public IActionResult OnPostRemove(int id, string returnUrl)
{
Cart.RemoveLine(Cart.Lines.First(cl =>
cl.Product.Id == id).Product);
return RedirectToPage(new { returnUrl = returnUrl });
}
When i cliked remove button i got a 400 Error and my OnPostRemove method doesn't trigger.
Update
I included tag helper in my _ViewImports.cshtml and issue resolved.
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Put the page handler inside the submit button tags.
<form method="post">
...
<button type="submit" asp-page-handler="Remove">
Remove
</button>
</form>
The code snippet that you shared seems ok, which work well with testing data on my side.
When i cliked remove button i got a 400 Error and my OnPostRemove method doesn't trigger.
To troubleshoot the issue, please check the actual request with the posted data in F12 developer tool Network tab.
And please note that if the antiforgery token validation is enabled, but the request does not include a valid antiforgery token or something wrong with the antiforgery cookies, which would also cause 400 Bad Request error.
For testing purpose, you can try to skip antiforgery token validation by applying IgnoreAntiforgeryTokenAttribute on page model class, then check if the request can be handled as expected.
[IgnoreAntiforgeryToken]
public class CartModel : PageModel
{
I am trying to save input (an address) from an html form in order to use in other cshtml pages in my asp.net core web application. I am also using Razor as a template language. I have a web application in which the user will enter an address on one page and then on another page I want to use that input and place it into an api call. My html form is below.
<form method="post" action="/Features">
<p>
Address: <input type="text" name="searchString"/>
<input type="submit" value="Search" />
</p>
</form>
I have previously used sessions but it was for an asp.net project using web forms (I believe) and am not sure if this is the route I should go. The address being entered doesn't need to be kept secure. Thanks for any help.
You have two options here:
Submit the form to your page, store the address in TempData then redirect to the second page where you would use your submitted value (Here you use the Post/Redirect/Get pattern in order to avoid your form being submitted again by mistake via a page reload).
Submit the form directly to the second page.
Going with the first option is recommended.
Page:
<form method="post" asp-page-handler="Features">
<p>
Address: <input type="text" name="searchString"/>
<input type="submit" value="Search" />
</p>
</form>
Handler:
public IActionResult OnPostFeatures(string searchString)
{
TempData["Key"] = searchString;
return RedirectToPage("/SecondPage");
}
Then on your second page you get the searchString in the same way via:
string value = TempData["Key"] as string;
As i said you can also submit your form to the second page where you can do what ever you want with your value. Just be careful of multiple submissions.
Here is a demo to use TempData in Razor page:
cshtml:
<form method="post" asp-page-handler="Features">
<p>
Address: <input type="text" name="searchString"/>
<input type="submit" value="Search" />
</p>
</form>
cshtml.cs:
public IActionResult OnPostFeatures(string searchString) {
TempData["searchString"] = searchString;
xxxxxxx
}
Other Page you want to use searchString:
string searchString=TempData["searchString"];
//TempData.Keep(); can help you keep the value,and you can still use the searchString value in other place
TempData.Keep();
or you can use
string searchString=TempData.Peek("searchString");
So that you can still keep the searchString value
The main problem is that a method from controller is not called when i press a button.
I have this in my Index view for MyController :
#using (Html.BeginForm())
{
#* .... *#
<form action="DoSomethingAction" method="post">
<input type="text" id="IdString" name="IdString" placeholder="Enter id"/>
<input id="Submit1" name="Submit1" type="submit" value="DoSomething1" />
<input id="Submit2" name="Submit2" type="submit" value="DoSomething2" />
</form>
#* ..... *#
}
In MyController I have DoSomethingAction method. I want to call this method and be able to see IdString when I press a button: DoSomething1 or DoSomething2. This is DoSomethingAction method from controller:
public ActionResult DoSomethingAction()
{
string id= Request.Form["IdString"];
//string button=...
// ...
}
When I put a breakpoint for DoSomethingAction method, I observed that it's never called.
I tried to put [Httppost] attribute for this method, but it didn't solve my problem.
What am I doing wrong?
After that, how can I see in DoSomethingAction method which button was pressed?
a HTML form can not nest a HTML form. Please read https://www.w3.org/TR/html5/forms.html#the-form-element
If you need multiple form you can define them as siblings.
Either use html.BeginForm or type="Submit". Next thing to keep in mind, html.BeginForm is a post method, so if u want to use it, give an attribute over Action and if u don't state what view action should return, he will assume that view is of the same name as action, in ur case DoSomethingAction, that's why u get server error. Either make that view or state in return View() which view u want to return (Index or some other).
I actually found a solution. It was trying to run validation. But only the last validation was added. The message for validation was not displaying.
I can NOT figure this out. I have a form that is created using razor like this
#using (Html.BeginForm("Search", "WellSearch", FormMethod.Post))
{
#Html.Partial("_DropDownList_Operator", Model)
#Html.Partial("_DropDownList_Lease", Model)
<input type="submit" id="buttonClearAllFields" class="btn btn-small submit" name="Command" value="ClearAllFields" />
<input type="submit" id="buttonSearch" class="btn btn-small submit" name="Command" value="Search" />
}
What is wired is this I can ONLY submit form when the last DropDown is populated with a value. If I leave both drop downs blank can't post to a controller. Also if I switch the order of the drop downs around make Operator last it is the same thing.
I my actual code I have 10 total drop down boxes the same thing only the last one is populated. I know MVC pretty well but not an expert.
My question is this what should I check to troubleshoot this behavior. I check everything no errors, no exceptions. Not sure how to troubleshoot this need an advice what to be aware of or maybe someone was in a same situation.
This is a code for a partial view
#model [removed].Models.[removed]
#Html.TextBoxFor(a => a.[removed].LeaseKey, new { id = "lease"})
[removed] - removed those because it contains personal information
I actually found a solution. It was trying to run validation. But only validation for lease drop down was added. The message for validation was not displaying.
I have a single form in ASP.NET MVC (v1) that has 2 input buttons. Each submit button has to be contained within this single form and I need to know which one the user pressed.
I know about the trick to check the FormCollection values which will be returned based on the button pressed. For example, if I have and and the user clicks Button2, I should be able to say Request.Form["Button2"] != null and that will evaluate to true in which case I know that the user clicked that button.
However, this is not working for me. The values of all my buttons is null as non of them are contained within the Request.Form values. Is there a bug in ASP.NET MVC which swallows these values?
Here is my form code:
<% using (Html.BeginForm()) {%>
<% Html.RenderPartial( "EditAreaControl", Model ); %>
<div class="form-layout-command-container">
<div class="form-layout-command-area-alpha"><button type="submit" name="submit1" value="Save">Save</button></div>
<div class="form-layout-command-area-alpha"><button type="submit" name="submit2" value="SaveAndCopy">Save and Create Copy</button></div>
<div class="form-layout-command-area-beta"><%= Html.ActionLink("Cancel", "list") %></div>
</div>
<% } %>
Here is my controller code:
[AcceptVerbs( HttpVerbs.Post )]
public ActionResult Add(FormCollection values )
{
if (values["submit1"] != null)
// always false
if (values["submit2"] != null)
// always false as well
}
From w3schools:
Important: If you use the button element in an HTML form, different browsers will submit different values. Internet Explorer will submit the text between the and tags, while other browsers will submit the content of the value attribute. Use the input element to create buttons in an HTML form.
It seems that this is not standardized. You should stick to
<input type="submit" name="submitButton" value="Save" />
<input type="submit" name="submitButton" value="Cancel" />
I would use inputs of type submit instead of buttons. Non-inputs may not passed back in a form post or at least can be passed back inconsistently. Note that they can have the same name with different values so that you can use the same parameter for any button that submits the form.
<input type="submit" name="submitButton" value="Save" />
<input type="submit" name="submitButton" value="SaveAndCopy" />
public ActionResult Save( string submitButton, ... )
{
if (submitButton == "Save")
{
...
}
else if (submitButton == "SaveAndCopy")
{
...
}
....
}
Using Firebug, I found that the submit buttons were not being sent in the response and because of that, there isn't much I can do on the MVC side. I decided to use a client side hack to populate a hidden input field on the client side which would be passed to the controller values.
I changed the input buttons to be:
<input type="submit" value="Save" onclick="actions.copyValues($(this), $('#submitAction'));" />
<input type="submit" value="Save and Copy" onclick="actions.copyValues($(this), $('#submitAction'));" />
<input type="hidden" id="submitAction" name="submitAction" />
The jquery script simply copies the values:
Actions.prototype.copyValues = function(from, to) {
$(to).val($(from).val());
};
The controller action then looks for the hidden input values:
var request = HttpContext.Request;
return request.Form["submitAction"];
This solves the issue from above but I realize it is not that clean.
Put them in two different forms and you will know which one submitted based on which action was called on the controller.