Data being sent as query string instead of Form data - asp.net-mvc

In my form I see that the data is being sent as Querystring instead of form data (that I expect it to).
My page:
#using (Html.BeginForm("AAForm", "Test", FormMethod.Post, new { id = "myAForm" }))
{
<label for="a">A</label>
<input id="aid" name="aname" style="width: 300px" required validationMessage="Select"/>
<button type="submit" class="btn btn-primary" value="aa" > Go </button>
}
ControllerSignature
public ActionResult GetValues(FormCollection formCollection){
//Some code }
And I am making an AJAX call to GetValues().
What could I be doing wrong? Pls let me know if I should be posting more information.
Another question: What is "_:" in the query string? And it has some random number value.
Thanks.

add an [HttpPost] attribute on your ActionResult.

Related

Retain query string param after submit

On my website I use MVC Authentication, if a user wants to reset his password, he clicks on 'Forgot Password' then he gets by email a link with a unique code to reset his password.
My issue is if for some reason the reset fails (for example- password and password confirmation don't match etc) then it returns to the View without the unique code that was generated in the link that the user got by email and the reset password won't work afterwards (code query string param)
How can I keep the query string unique code when the reset fails and return it to the View?
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await UserManager.FindByNameAsync(model.Email);
if (user != null)
{
var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
if (result.Succeeded)
{
return RedirectToAction("ResetPasswordConfirmation", "Account");
}
}
ViewBag.Error = "Password reset failed";
return View();
}
And this is the form:
<form id="reset-form" method="post" action="Account/ResetPassword">
#Html.AntiForgeryToken()
<div class="header">
<h2>Reset Password</h2>
#if (!String.IsNullOrEmpty(ViewBag.Error))
{
<div class="invalid">
#ViewBag.Error
</div>
}
</div>
<div class="inputField">
<input type="email" id="email" name="email" placeholder="USERNAME" />
</div>
<div class="inputField">
<input type="password" id="password" name="password" placeholder="PASSWORD" />
</div>
<div class="inputField">
<input type="password" id="confirm-password" name="confirmPassword" placeholder="CONFIRM PASSWORD" />
<input type="submit"/>
</div>
</form>
I need it to return to the View like this:
~/account/resetpassword?code=xyz
The URL will remain the same as what you post when the view is returned unless you do a redirect (not recommended).
However, the issue isn't that you need the URL to change after the action method runs. You need to change the URL that is posted to the action method to include the query string so it is there when the action method returns the view. This can be done by simply changing the URL of the form.
Note that you should never hard code the URL in MVC views. Instead, you should always use controller, action, and other route values to resolve the URL using the UrlHelper (and related extension methods such as ActionLink). The routing infrastructure should be the only place where URLs exist so they can be changed in one place.
In this case the solution is to use Html.BeginForm to build up the form tag based on routing.
#using (Html.BeginForm("ResetPassword", "Account", new { code = "xyz" }, FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="header">
<h2>Reset Password</h2>
#if (!String.IsNullOrEmpty(ViewBag.Error))
{
<div class="invalid">
#ViewBag.Error
</div>
}
</div>
<div class="inputField">
<input type="email" id="email" name="email" placeholder="USERNAME" />
</div>
<div class="inputField">
<input type="password" id="password" name="password" placeholder="PASSWORD" />
</div>
<div class="inputField">
<input type="password" id="confirm-password" name="confirmPassword" placeholder="CONFIRM PASSWORD" />
<input type="submit"/>
</div>
}
Of course, you shouldn't hard code "xyz" here either, it should be passed to the view from the HttpGet ResetPassword method either in a Model or in ViewBag.
Note that if the url parameter of the route definition (typically in RouteConfig.cs) does not contain a parameter for code, it will automatically be added to the URL as a query string parameter.
I'm using Thymeleaf and had a similar issue. Here's how I solved it using the thymeleaf functionality:
HTML:
<form class="forms-sample" action="/login"
!!! th:action="#{/reset_password(token=${token})}" !!!
th:object="${passwordDto}" method="post">
**INSERT CODE HERE**
</form>
MVC Controller:
if(bindingResult.hasErrors()) {
model.addAttribute("token", tokenStr); !!!!!!!!
return "create_password";
}
try {
PasswordResetToken token = passwordResetTokenService.getByToken(tokenStr);
User user = token.getUser();
user = userMapper.setNewPassword(user, passwordDto);
userService.update(user);
passwordResetTokenService.delete(token);
return "home";
}catch (PasswordNotMatchException e) {
bindingResult.rejectValue("confirmNewPassword", "password_error",
"Confirm password did not match.");
model.addAttribute("token", tokenStr); !!!!!!!!
return "create_password";
}
catch (EntityNotFoundException e) {
return "create_password";
}
What I do is I put the token in the Model and if the post method encounters an error I make sure to add it again, before returning the view for creating a password.
The important thing to note is, as NightOwl mentioned, that the url stays the same, only the Model changes. Thats why we need to readd the token as a model attribute.

How can I filter my partial views with a radio button in asp.net-core w/o javascript?

I want my users to be able to sort the content of the page thus displaying a partial view depending on what they click. This would be a clear case to use radio buttons as only one can be selected at a time.
However I'm not sure how to call an action method on just a radio button.
This is my current implementation without radiobuttons
<a asp-action="Bookings" asp-controller="User" class="btn btn-primary" asp-route-sortOrder="All">Alle lektioner</a>
<a asp-action="Bookings" asp-controller="User" class="btn btn-primary" asp-route-sortOrder="Upcoming">Kommende lektioner</a>
<a asp-action="Bookings" asp-controller="User" class="btn btn-primary" asp-route-sortOrder="History">Historik</a>
Using bootstrap radio buttons this is my template but I'm not able to make these hit an actionmethod in my controller. I've thought about creating onclick on the input but I'm not sure that possible and additionally I don't know how to asp-route-sortOrder in an onclick
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary active">
<input type="radio"id="option1" autocomplete="off" checked> All
</label>
<label class="btn btn-primary">
<input type="radio" autocomplete="off"> Upcoming
</label>
<label class="btn btn-primary">
<input type="radio" autocomplete="off"> History
</label>
</div>
I prefer to not use javascript if possible.
It might be easier to just highlight the link indicating the current route (sortOrder) by conditionally adding a class name. Refer How to add “active” class to Html.ActionLink in ASP.NET MVC for some examples of how to do that, but to answer your question, start with a view model to represent what you want in the view
public class BookingsVM
{
public string SortOrder { get; set; } // to bind to the radio buttons
public IEnumerable<Booking> Bookings { get; set; } // the collection of records to display in the view
}
Then the controller method would be
[HttpGet]
public ActionResult Bookings(string sortOrder)
{
var bookings = .... // your code to get Bookings based on the value of sortOrder
BookingsVM model = new BookingsVM
{
SortOrder = sortOrder,
Bookings = bookings
}
return View(model);
}
And the view
#model BookingsVM
....
#using(Html.BeginForm("Bookings", "User", FormMethod.Get))
{
<label>
#Html.RadioButtonFor(m => m.SortOrder, "All", new { id = "" })
<span>Alle lektioner</span>
</label>
<label>
#Html.RadioButtonFor(m => m.SortOrder, "Upcoming", new { id = "" })
<span>Kommende lektioner</span>
</label>
// .... ditto for History
<input type="submit value="Sort" />
}
#foreach(var booking in Model.Bookings)
{
// .... display results here
}
Note that because the browser has no knowledge of your route definitions, submitting the form will result in a url that is ../User/Bookings?sortOrder=All (i.e using a query string value). If you want ../User/Bookings/All, then you will need to use some javascipt to make the redirect.
As a side note, the fact the your possible values are "All", "Upcoming" and "History" suggests that you actually filtering the results (i.e. using a .Where() clause) rather that sorting the results (using an .OrderBy()) so a more appropriate property name might be Filter rather than SortOrder.
there are two ways to solve your problem
convert your partial views to View Components then load them
by JavaScript
make that view act like a layout (NESTED LAYOUT) then load the
different sections as views according to selected option
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/layout
Nested Layout Pages with Razor

Pass argument to controller on submit

So, i started learning MVC, and i need to pass an email to a controller. (Trying to make a standard email signup)
Therefore i have an input and a button which (should) pass the input to an argument accepting controller and then redirect to another view.
I have the following controllers:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string mail)
{
person = new EmailSignup{Email = mail};
return RedirectToAction("details");
}
public ActionResult details()
{
return View(person);
}
This is what i have in my View:
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<form class="col-md-12">
<div class="form-group form-inline">
<label class="margin20">Sign up for newsletter</label>
<input type="Email" class="form-control" style="display:inline-block; max-width:200px" id="mail" placeholder="Example#Example.com" />
<button type="submit" class="btn btn-default" style="display:inline-block" id="emailSignup">Signup</button>
</div>
</form>
}
It redirects to my "details" view, but my email is not showing.
Furthermore, is this best practice? would i want to do it like this?
#using (Html.BeginForm("Index", "Home", FormMethod.Post)) renders a form, you don't need a second one inside it (if you need to add the class, you can use an overload of Html.BeginForm). Your input contains an id property, but not a name property. name is what's used when an action happens inside a form.

ASP.NET MVC: Using EditorFor in a loop - ModelBinding to a single entity

I think I may be a little confused :-\
I have a basic scenario whereby I need to render out a list of forms. I have a basic ViewModel that contains a collection of entities. I have an EditorFor template for the entity in question that renders a basic set of inputs.
It looks as follows:
#for (var i = 0; i < Model.Count(); i++)
{
using (Html.BeginForm("Update", "VehicleLog", new { id = Model[i].id }, FormMethod.Post, new { #class = "vehicle-update-form std-form", data_ajaxpost = "true", data_refreshcontainer = "#vehicle-ajax-holder" }))
{
#Html.EditorFor(model => model[i])
<div class="buttons right">
<input type="submit" value="Save" name="action" class="btn-ok btn" />
<input type="submit" value="Delete" name="action" class="btn-warning btn" />
</div>
}
}
I have a for loop that then dumps out these editor template. So far so good.
My issue is that I wish to use UpdateModel in my POST action to update the entity. However, the data being sent to the controller takes the following format:
My incomplete action looks as follows:
[HttpPost]
public ActionResult Update(int id, FormCollection data, string action)
{
var response = new JsonResponse();
if (action == "Update")
{
var v = UnitOfWork.VehicleRepository.GetById(id);
UpdateModel(v);
}
return Json(response);
}
My issue is that the EditorFor helpers is (and rightly so) prefixing names with array indexes, eg [0].name. As such I am unable to use the UpdateModel method to update an entity.
Any advice appreciated!

ASP.NET MVC ActionLink and post method

Can anyone tell me how can I submit values to Controller using ActionLink and POST method?
I don't want to use buttons.
I guess it has something with jquery.
If you're using ASP MVC3 you could use an Ajax.ActionLink(), that allows you to specify a HTTP Method which you could set to "POST".
You can't use an ActionLink because that just renders an anchor <a> tag.
You can use a jQuery AJAX post.
Or just call the form's submit method with or without jQuery (which would be non-AJAX), perhaps in the onclick event of whatever control takes your fancy.
You can use jQuery to do a POST for all your buttons. Just give them the same CssClass name.
Use "return false;" at the end of your onclick javascript event if you want to do a server side RedirectToAction after the post otherwise just return the view.
Razor Code
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.ID)
#Html.ActionLink("Save", "SaveAction", "MainController", null, new { #class = "saveButton", onclick = "return false;" })
}
JQuery Code
$(document).ready(function () {
$('.saveButton').click(function () {
$(this).closest('form')[0].submit();
});
});
C#
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveAction(SaveViewModel model)
{
// Save code here...
return RedirectToAction("Index");
//return View(model);
}
#Aidos had the right answer just wanted to make it clear since it is hidden inside a comment on his post made by #CodingWithSpike.
#Ajax.ActionLink("Delete", "Delete", new { id = item.ApkModelId }, new AjaxOptions { HttpMethod = "POST" })
Here was an answer baked into the default ASP.NET MVC 5 project I believe that accomplishes my styling goals nicely in the UI. Form submit using pure javascript to some containing form.
#using (Html.BeginForm("Logout", "Account", FormMethod.Post, new { id = "logoutForm", #class = "navbar-right" }))
{
<a href="javascript:document.getElementById('logoutForm').submit()">
<span>Sign out</span>
</a>
}
The fully shown use case is a logout dropdown in the navigation bar of a web app.
#using (Html.BeginForm("Logout", "Account", FormMethod.Post, new { id = "logoutForm", #class = "navbar-right" }))
{
#Html.AntiForgeryToken()
<div class="dropdown">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="ma-nav-text ma-account-name">#User.Identity.Name</span>
<i class="material-icons md-36 text-inverse">person</i>
</button>
<ul class="dropdown-menu dropdown-menu-right ma-dropdown-tray">
<li>
<a href="javascript:document.getElementById('logoutForm').submit()">
<i class="material-icons">system_update_alt</i>
<span>Sign out</span>
</a>
</li>
</ul>
</div>
}
ActionLink will never fire post. It always trigger GET request.
Use the following the Call the Action Link:
<%= Html.ActionLink("Click Here" , "ActionName","ContorllerName" )%>
For submitting the form values use:
<% using (Html.BeginForm("CustomerSearchResults", "Customer"))
{ %>
<input type="text" id="Name" />
<input type="submit" class="dASButton" value="Submit" />
<% } %>
It will submit the Data to Customer Controller and CustomerSearchResults Action.
This is taken from the MVC sample project
#if (ViewBag.ShowRemoveButton)
{
using (Html.BeginForm("RemoveLogin", "Manage"))
{
#Html.AntiForgeryToken()
<div>
#Html.Hidden("company_name", account)
#Html.Hidden("returnUrl", Model.returnUrl)
<input type="submit" class="btn btn-default" value="Remove" title="Remove your email address from #account" />
</div>
}
}
Use this link inside Ajax.BeginForm
#Html.ActionLink(
"Save",
"SaveAction",
null,
null,
onclick = "$(this).parents('form').attr('action', $(this).attr('href'));$(this).parents('form').submit();return false;" })
;)
My Solution to this issue is a fairly simple one. I have a page that does a customer search one by the whole email and the other by a partial, the partial pulls and displays a list the list has an action link that points to a actionresult called GetByID and passes in the id
the GetByID pulls the data for the selected customer then returns
return View("Index", model);
which is the post method
This has been a difficult problem for me to solve. How can I build a dynamic link in razor and html that can call an action method and pass a value or values to a specific action method? I considered several options including a custom html helper. I just came up with a simple and elegant solution.
The view
#model IEnumerable<MyMvcApp.Models.Product>
#using (Html.BeginForm()) {
<table>
<thead>
<tr>
<td>Name</td>
<td>Price</td>
<td>Quantity</td>
</tr>
</thead>
#foreach (Product p in Model.Products)
{
<tr>
<td>#p.Name</td>
<td>#p.Price.ToString()</td>
<td>#p.Quantity.ToString()</td>
</tr>
}
</table>
}
The action method
public ViewResult Edit(Product prod)
{
ContextDB contextDB = new ContextDB();
Product product = contextDB.Products.Single(p => p.ProductID == prod.ProductId);
product = prod;
contextDB.SaveChanges();
return View("Edit");
}
The point here is that Url.Action does not care whether the action method is a GET or a POST. It will access either type of method. You can pass your data to the action method using
#Url.Action(string actionName, string controllerName, object routeValues)
the routeValues object. I have tried this and it works. No, you are not technically doing a post or submitting the form but if the routeValues object contains your data, it doesnt matter if its a post or a get. You can use a particular action method signature to select the right method.
I have done the same issue using following code:
#using (Html.BeginForm("Delete", "Admin"))
{
#Html.Hidden("ProductID", item.ProductID)
<input type="submit" value="Delete" />
}
This is my solution for the problem.
This is controller with 2 action methods
public class FeedbackController : Controller
{
public ActionResult Index()
{
var feedbacks =dataFromSomeSource.getData;
return View(feedbacks);
}
[System.Web.Mvc.HttpDelete]
[System.Web.Mvc.Authorize(Roles = "admin")]
public ActionResult Delete([FromBody]int id)
{
return RedirectToAction("Index");
}
}
In View I render construct following structure.
<html>
..
<script src="~/Scripts/bootbox.min.js"></script>
<script>
function confirmDelete(id) {
bootbox.confirm('#Resources.Resource.AreYouSure', function(result) {
if (result) {
document.getElementById('idField').value = id;
document.getElementById('myForm').submit();
}
}.bind(this));
}
</script>
#using (Html.BeginForm("Delete", "Feedback", FormMethod.Post, new { id = "myForm" }))
{
#Html.HttpMethodOverride(HttpVerbs.Delete)
#Html.Hidden("id",null,new{id="idField"})
foreach (var feedback in #Model)
{
if (User.Identity.IsAuthenticated && User.IsInRole("admin"))
{
#Html.ActionLink("Delete Item", "", new { id = #feedback.Id }, new { onClick = "confirmDelete("+feedback.Id+");return false;" })
}
}
...
</html>
Point of interest in Razor View:
JavaScript function confirmDelete(id) which is called when the link generated with #Html.ActionLink is clicked;
confirmDelete() function required id of item being clicked. This item is passed from onClick handler confirmDelete("+feedback.Id+");return false; Pay attention handler returns false to prevent default action - which is get request to target. OnClick event for buttons could be attached with jQuery for all buttons in the list as alternative (probably it will be even better, as it will be less text in the HTML page and data could be passed via data- attribute).
Form has id=myForm, in order to find it in confirmDelete().
Form includes #Html.HttpMethodOverride(HttpVerbs.Delete) in order to use the HttpDelete verb, as action marked with the HttpDeleteAttribute.
In the JS function I do use action confirmation (with help of external plugin, but standard confirm works fine too. Don't forget to use bind() in call back or var that=this (whatever you prefer).
Form has a hidden element with id='idField' and name='id'. So before the form is submitted after confirmation (result==true), the value of the hidden element is set to value passed argument and browser will submit data to controller like this:
Request URL:http://localhost:38874/Feedback/Delete
Request Method:POST Status Code:302 Found
Response Headers
Location:/Feedback
Host:localhost:38874
Form Data X-HTTP-Method-Override:DELETE id:5
As you see it is POST request with X-HTTP-Method-Override:DELETE and data in body set to "id:5". Response has 302 code which redirect to Index action, by this you refresh your screen after delete.
I would recommend staying pure to REST principles and using an HTTP delete for your deletes. Unfortunately HTML Specs only has HTTP Get & Post. A tag only can a HTTP Get. A form tag can either do a HTTP Get or Post. Fortunately if you use ajax you can do a HTTP Delete and this is what i recommend. See the following post for details: Http Deletes
Calling $.post() won't work as it is Ajax based. So a hybrid method needs to be used for this purpose.
Following is the solution which is working for me.
Steps:
1. Create URL for href which calls the a method with url and parameter
2. Call normal POST using JavaScript method
Solution:
In .cshtml:
View
Note: the anonymous method should be wrapped in (....)()
i.e.
(function() {
//code...
})();
postGo is defined as below in JavaScript.
Rest are simple..
#Url.Action("View") creates url for the call
{ 'id': #receipt.ReceiptId } creates parameters as object which is in-turn converted to POST fields in postGo method. This can be any parameter as you require
In JavaScript:
(function ($) {
$.extend({
getGo: function (url, params) {
document.location = url + '?' + $.param(params);
},
postGo: function (url, params) {
var $form = $("<form>")
.attr("method", "post")
.attr("action", url);
$.each(params, function (name, value) {
$("<input type='hidden'>")
.attr("name", name)
.attr("value", value)
.appendTo($form);
});
$form.appendTo("body");
$form.submit();
}
});
})(jQuery);
Reference URLs which I have used for postGo
Non-ajax GET/POST using jQuery (plugin?)
http://nuonical.com/jquery-postgo-plugin/
jQuery.post() will work if you have custom data. If you want to post existing form, it's easier to use ajaxSubmit().
And you don't have to setup this code in the ActionLink itself, since you can attach link handler in the document.ready() event (which is a preferred method anyway), for example using $(function(){ ... }) jQuery trick.
Came across this needing to POST from a Search (Index) page to the Result page. I did not need as much as #Vitaliy stated but it pointed me in the right direction. All I had to do was this:
#using (Html.BeginForm("Result", "Search", FormMethod.Post)) {
<div class="row">
<div class="col-md-4">
<div class="field">Search Term:</div>
<input id="k" name="k" type="text" placeholder="Search" />
</div>
</div>
<br />
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn btn-default">Search</button>
</div>
</div>
}
My Controller had the following signature method:
[HttpPost]
public async Task<ActionResult> Result(string k)

Resources