I'm trying to submit a simple form for my ASP.NET MVC website, but I keep getting a StackOverFlow Exception. I don't understand what I'm doing wrong; it should be a pretty straightforward process...
Here is the form code:
<form action="/Home/SubmitAnnouncements" method="post">
<textarea name="announcementcode" style="width:100%; height:800px">#Model.RawAnnouncementCode</textarea>
<div id="find_account" class="two columns"><input id="find_account_btn" class="link_button" type="submit" name="Submit" value="Submit New Announcements" /></div>
</form>
And here is the Controller code for the action:
[HttpPost, ValidateInput(false)]
public ActionResult SubmitAnnouncements(string announcementcode)
{
SubmitAnnouncements(announcementcode);
return RedirectToAction("Index", "Home");
}
This problem stated when I added [HttpPst, ValidateInput(false)], but I need to do that, because the user is submitting raw HTML code. Any ideas anyone?
The ValidateInput attribute didn't cause your error, you just never reached the point in your code that causes the StackOverflowException until it was added.
If you look at the first line of your action, you'll notice you're calling the same method.
Related
.NET Core v6
MVC Web App with Entity Framework Core
I scaffolded a database table and it created a "db context", then I scaffolded default Controller and Views.
On the home page, I want to create a search box where you put in the primary key, or id. On submit, I want the value passed to the default Edit controller. Essentially, I want someone to be able to pull up a single record to Edit, if they know the primary key (id).
Here is what I have for a search box
<form asp-controller="MyTables" asp-action="Edit">
<p>
PIN: <input type="text" name="id" />
<input type="submit" value="Find" />
</p>
</form>
Here is the default Edit method inside the Controller.
// GET: MyTables/Edit/XYZ
public async Task<IActionResult> Edit(string id)
{
if (id == null)
{
return NotFound();
}
var MyTable = await _context.MyTables.FindAsync(id);
if (MyTable == null)
{
return NotFound();
}
return View(MyTable);
}
When I run this, it doesn't work, but I don't know how to set it up. How can I make this work? The only way I've been able to pull a record is by adding method="get" to the form, but then it creates a URL structure using "id" as a parameter like this localhost/MyController/Edit?id=XYZ. This structure won't work because I'm unable to save the record when I've navigated to the page in this way.
I appreciate any pointers or ideas.
Thank you
EDIT AFTER COMMENTS:
It has been suggested that I could go ahead and use the method="get", thereby selecting the correct record. The URL would be in this format: localhost/MyController/Edit?id=XYZ. A proposed solution is to fix my POST action to be able to save the record when using such URL paths. I'm not sure why, but it will only save right now if the URL path is in this format: localhost/MyController/Edit/XYZ (no parameter ?id =).
Here is a version of my default POST Edit action in the controller.
// POST: MyTables/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(string id, [Bind("...,...,...,...,...,...,PrimaryKeyField")] MyTable myTable)
{
if (id != myTable.PrimaryKeyField)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(myTable);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MyTableExists(myTable.primaryKeyField))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(MyTable);
}
In the Edit view, to initiate the POST action, here's some of the Edit Form markup:
#model myApp.Models.MyTable
...
<form asp-action="Edit">
...
<div class="form-group">
<label asp-for="PrimaryKeyField" class="control-label"></label>
<input asp-for="PrimaryKeyField" class="form-control" />
<span asp-validation-for="PrimaryKeyField" class="text-danger"></span>
</div>
...
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
The reason I'm saying it won't Save is when I click Submit on the Edit form, it brings up this HTTP error:
This localhost page can’t be found. No webpage was found for the web address: https://localhost:7020/MyTables/Edit
HTTP ERROR 404
In the Edit View, I added a reference to the Model.
#model myApp.Models.MyTable
In the form, I added a Tag Helper.
<form asp-action="Edit" asp-route-id=#Model.PrimaryKeyField>
This is working.
I noticed in the URL pattern of /Edit/XYZ, the form's asp-action uses this pattern. I noticed with the URL pattern of /Edit/?id=XYZ, the form's action uses /Edit with NO ID. Therefore, I figured out a way to add the id to the form's action by using the asp-route-id tag helper. The form submits the data properly now.
The required anti-forgery cookie
"_RequestVerificationToken..." is not present
I am getting this error on one specific machine. On that machine user gets it in two different browsers. rebooting, restarting browser, cleaning cookies, and restarting IIS App pool didn't solve the issue.
On different machines this web app works fine.
conttroller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(MyModel thisObject)
{
}
page:
<body>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
....
<input type="submit" value="Save" class="btn btn-primary" />
}
Any idea what's going on here?
When adding the AntiForgeryToken reference in the form, it generates a hidden input marked name=__RequestVerificationToken. Get the value of that input and add that to your call as a parameter.
Check the answer to this post for details include antiforgerytoken in ajax post ASP.NET MVC
So I have a form on my shared layout page that I want to simply post a text string to. I currently have a breakpoint sitting at the beginning of that action in the controller to test the form is working but it appears that it never gets there because it never hits the breakpoint. Here is my code anyone know what I am doing wrong?
View:
<form action="/RespondentSearch/Search" method="post" class="sidebarSearch">
<input type="text" name="search" placeholder="respondent search..." id="ac" class="ui-autocomplete-input" autocomplete="off" /><span role="status" aria-live="polite" class="ui-helper-hidden-accessible"></span>
<input type="submit" value="" href="#moadalSearch" rel="lightbox" />
</form>
Controller:
public class RespondentSearchController : Controller
{
[HttpPost]
public ActionResult Search(string search)
{
string stuff = search;
return View();
}
}
My Visual Studio Debug Console though reads like there is an exception?
Following route: {controller}/{action}/{id} for request: http://localhost:56554/RespondentSearch/Search
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll
Following route: {controller}/{action}/{id} for request: http://localhost:56554/Home/Login
Following route: {controller}/{action}/{id} for request: http://localhost:56554/
My Developer Tools Browser Debug:
Request URL:http://localhost:56554/RespondentSearch/Search
Request Method:POST
Status Code:302 Found
search:asdf <--- This is what I was typing in
It appears it is getting there but I am not hitting my breakpoint still? I also added a temp view for it to just output something when its there and still nothing. It is like it is completely avoiding my controllers action.
I have a simple MVC application that retrieves DB Server, database, username and password from the user to store in an XML file. I want to add a "Test Connection" button to the screen and have it execute a method on the controller called TestConnection. The problem is the TestConnection method resets all the information on the screen when clicked since the View is being returned with no model. (because a GET operation is occurring). Here is my code:
From the Controller (named FrameworkConfigurationController.cs)
public ActionResult TestConnection()
{
return View("Index");
}
[HttpPost]
public ActionResult TestConnection(FrameworkConfigurationViewModel viewModel)
{
// TODO: Test will occur here
viewModel.DbConnectionMessage = string.IsNullOrEmpty(viewModel.DatabaseName) ? "Connection unsuccessful" : "Connection successful";
return View("Index", viewModel);
}
From my View (FrameworkConfiguration/Index):
#model Framework.ViewModels.FrameworkConfigurationViewModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>FrameworkConfigurationViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ServerName)
</div>
#* Edited for brevity *#
<button type="submit" onclick="location.href='#Url.Action("TestConnection")'">
Test Connection</button>
#Html.ValueFor(model => model.DbConnectionMessage)
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to Dashboard", "Index", "Home")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Admittedly, I am new to MVC programming. I'm coming from a Silverlight/MVVM background so the concept is not foreign to me...the disconnected nature of web programming is. I've followed some tutorials out there, but none of them seem to cover this type of thing - every example is contrived. I know how to do this with webforms and code-behind, but I would like to accomplish this with MVC.
Is there some way to "force" the POST operation instead of GET? I was under the impression that
<button type="submit">
accomplished that. Perhaps the implementation of the onclick I have written isn't correct. I am sure this is HTML 101 stuff, but I can't seem to find a simple answer to this.
Thanks for any help you can offer,
Jason
Why not have the Test Connection button trigger an Ajax action to call the controller, and display the result?
That way you avoid submitting your entire page.
In case you're not familiar with the details, here's a good overview on getting started with Ajax and MVC 4
http://ofps.oreilly.com/titles/9781449320317/ch_AJAX.html
FINAL EDIT:
After following the answer from Darin Dimitrov, I have found that the problem ended up being that the AJAX call to the Controller's method UpdateForm() was returning an empty string. This was a modification that I found necessary some time ago after experiencing a different problem. Passing an empty string was causing Firefox's parser to choke (while Chrome and IE didn't care, apparently) so I replaced the empty string with an empty div.
Edit:
Thanks to Darin Dimitrov's suggestions below, I have found that the reason I was having trouble is due to an error being thrown whenever the form in question is being submitted.
The error reads "Node cannot be inserted at the specified point in the heirarchy". This is thrown each and every time the form is submitted. I noticed in the POST data that it seems to think this is an XMLHttpRequest. Is that the cause (the AJAX request in question is just returning HTML)? Here is the POST data from Firebug:
This error reads "XML Parsing Error -- No Element Found".
FYI - the HTML being returned is always an empty string...
I have an MVC3 application running on IIS7. In one of my views, I have a form being built using a Microsoft HTML helper function:
#using (Ajax.BeginForm("UpdateForm", new AjaxOptions { UpdateTargetId = "TargetDiv", InsertionMode = InsertionMode.InsertAfter, OnSuccess = "ClearTextBox" }))
{
#Html.TextArea("txtInput", new { id = "txtInput", cols = "20", rows = "5", wrap = "virtual" })
<input id="send" class="button" type="submit" value="Send"/><br />
}
This generates the following HTML when the Controller provides this view:
<form action="/RootName/ControllerName/UpdateForm" data-ajax="true" data-ajax-mode="after" data-ajax-success="ClearTextBox" data-ajax-update="#TargetDiv" id="form0" method="post">
<textarea cols="20" id="txtInput" name="txtInput" rows="5" wrap="virtual"></textarea>
<input id="send" class="button" type="submit" value="Send"><br>
</form>
What I'm basically trying to do here is take the text inside the TextArea called txtInput and append it to the end of the Div called TargetDiv whenever the Send button above is clicked and clear out the text from txtInput after the appending is complete by means of the ClearTextBox() method (Javascript). The append always works in every browser; and when I run in Internet Explorer or Chrome, the clearing of the text works just fine. However, Firefox doesn't seem to want to call the ClearTextBox() method.
Is Firefox not compatible with this data-ajax-success option in the form signature?
Things I've Tried
I found this guy:
Ajax.BeginForm doesn't call onSuccess
The solution is to add this script:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
I am calling this script:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
...but I tried swapping it out just in case. No joy.
I was asked to try changing the method call to include parentheses by some folks in the C# chat room so that the HTML came out like this:
<form action="/WebChat/TMWC/UpdateForm" data-ajax="true" data-ajax-mode="after" data-ajax-success="ClearTextBox()" data-ajax-update="#chatText" id="form0" method="post">
<textarea cols="20" id="txtInput" name="txtInput" rows="5" wrap="virtual"></textarea>
<input id="send" class="button" type="submit" value="Send"><br>
</form>
But that didn't help.
The folks in C# Chat also suggested I replace the Javascript call with an alert - something like this:
<form action="/WebChat/TMWC/UpdateForm" data-ajax="true" data-ajax-mode="after" data-ajax-success="alert('yo!')" data-ajax-update="#chatText" id="form0" method="post">
<textarea cols="20" id="txtInput" name="txtInput" rows="5" wrap="virtual"></textarea>
<input id="send" class="button" type="submit" value="Send"><br>
</form>
While Chrome pops the message box, Firefox does not!
Status no repro in a newly created ASP.NET MVC 3 application.
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult UpdateForm()
{
return Content(DateTime.Now.ToLongTimeString());
}
}
View (~/Views/Home/Index.cshtml):
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<script type="text/javascript">
function ClearTextBox() {
$('textarea').val('');
}
</script>
<form action="/Home/UpdateForm" data-ajax="true" data-ajax-mode="after" data-ajax-success="ClearTextBox" data-ajax-update="#TargetDiv" id="form0" method="post">
<textarea cols="20" id="txtInput" name="txtInput" rows="5" wrap="virtual"></textarea>
<input id="send" class="button" type="submit" value="Send"><br>
</form>
<div id="TargetDiv"></div>
Works perfectly fine in Chrome, FF and IE.
Also you might want to ensure that the Content-Type response HTTP header matches the actual response that you are sending. For example I have seen so many people send the application/json response header with some invalid JSON in the response body which produces the more sensitive parsers to choke.