I've started with asp mvc 3, with c# and razor, then. I want to use forms with security for send petitions POST.
I want to with razor render some like that
<form action="/sass/" method="post">
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
<div class="form-group">
<label>Ingresa tu Nombre</label>
<input class="form-control" name="nombre" />
</div>
<div class="form-group">
<input type="submit" value="Enviar mi duda" class="btn btn-primary btn-sm" />
</div>
}
And in C# I dont know how to validate that csrf token, is valid.
I work with C#, asp mvc3 and razor.
Please help me!
In your action method you need to add the respective attribute [ValidateAntiForgeryToken], and it validate the input for you.
You have a problem with the state of your code. There are two embedded forms: the outer one and the one produced by Html.BeginForm. However, the way to validate the token is to decorate the target action or controller with [ValidateAntiForgeryToken].
So either:
[ValidateAntiForgeryToken]
public ActionResult Index()
{
return View();
}
or to validate all methods in the controller:
[ValidateAntiForgeryToken]
public class MyController : Controller
{
}
Related
I'm using ASP.NET Core 2.2.
I'm trying to pass an ID (Guid) from my view to my controller Index using a submit button decorated with asp tag helpers like below:
<input type="submit" value="Go" asp-controller="MyController" asp-action="Index" asp-route-id="#Model.Id" />
My controller action method looks like this:
public IActionResult Index(Guid id)
{
return View();
}
The id is always coming through as Guid.Empty when the submit button is clicked.
I've switched over to using an anchor tag with the same tag helper values and the id comes through populated correctly:
<a asp-controller="MyController" asp-action="Index" asp-route-id="#Model.Id">Go</a>
I can get around this by styling an anchor to look like a button, but for the sake of understanding, can someone explain why an anchor would work in this situation but a submit button will not?
UPDATED (with generated HTML)
HTML with submit
<form>
<div class="d-flex">
<input type="submit" value="Go" formaction="" />
</div>
</form>
HTML with anchor
<form>
<div class="d-flex">
Go
</div>
</form>
put the asp-route-id="..." in the form tag, not in the button.
I have a small problem with routing and forms on ASP.NET Core 1.0.0. I have the following actions:
[Route("delete/{id:int}")]
[HttpGet]
public async Task<IActionResult> Delete(int id)
{
Post post = await _postsRepository.GetPost(id);
return View(new DeletePostViewModel
{
PostId=post.Id,
Title=post.Title
});
}
[Route("delete"),HttpPost,ValidateAntiForgeryToken]
public async Task<IActionResult> Delete([FromForm]DeletePostViewModel vm,string option)
{
if (option == "Delete")
await _postsRepository.DeletePost(vm.PostId);
return RedirectToAction("Index");
}
And in my view I have the following:
<form asp-action="Delete" asp-controller="AdminPosts" asp-area="Admin" method="post" role="form">
<div class="form-group">
<input type="hidden" asp-for="PostId"/>
<label asp-for="Title"></label>
<input type="text" asp-for="Title" class="form-control" readonly="readonly"/>
</div>
<p>
<input type="submit" name="option" value="Delete" class="btn btn-danger" />
<input type="submit" name="option" value="Cancel" class="btn btn-default" />
</p>
</form>
But it does not resolve the route correctly. The route I get for the form post has also the id, and so it does not resolve the id. I have to either add the id to the form method:
[Route("delete/{id:int}"),HttpPost,ValidateAntiForgeryToken]
public async Task<IActionResult> Delete(int id,[FromForm]DeletePostViewModel vm,string option)
or I have to remove the id explicitly in the form taghelper:
<form asp-action="Delete" asp-controller="AdminPosts" asp-area="Admin" asp-route-id="" method="post" role="form">
What might I be doing wrong here? Why is it not resolving the route correctly?
Yes, you would have to remove the id explicitly as you have already figured out. This is because id is an ambient value which is why its being used during link generation.
Regarding why this is happening:
In general (either regular or attribute routes), when routes are to be ordered, most specific routes need to come before less specific routes and also routes with larger number of segments come before routes with lesser number of segments. So in your scenario the route delete/{id:int} would be automatically ordered to come before delete. Now since the value for id is ambient, the first route's conditions are met and hence your are seeing the link generated in that way, so to fix it you would need to clear it.
I am trying to call an action from the controller using onclick method. For some reason it's not returning action I want, it's always jumping to public ActionResult Index() by default.
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Register" class="btn btn-default" onclick="location.href='#Url.Action("RegisterIndex", "Register")'"/>
</div>
</div>
NOTE
I have created view automatically with a model. It's validating input for me by using already generated javascripts. If I change input tag to button it's not gonna do the required validation.
window.location.href does a GET request, that's why it didn't pass your input values to the server.
When you have <input type="submit"> inside a form, clicking it will submit the form with all data you need. I think this is what you want, but you just want it to submit to another action.
To achieve this, I suggest this solution:
Create a hidden field in the form. Its data will be sent to the server.
In your server, base on that hidden value, you can redirect to the appropriate action
Please feel free to ask me if you find anything unclear :)
The <input type="submit">, when inside a form element, will submit the form when clicked unless you return false or event.preventDefault();
returning false will prevent the default behavior for your submit.
EDIT
window.location.href will cause a GET request so your data will not be posted using this method.
HTML
#using (Html.BeginForm())
{
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" id="btnSubmit" value="Register" class="btn btn-default"/>
</div>
</div>
}
Javascript
<script>
$(document).ready(function () {
$("#btnSubmit").click(function () { window.location.href = '#Url.Action("RegisterIndex", "Register")'; return false; });
});
</script>
I'll admit I'm new to MVC and this question might be a single case of RTFM. But I'm googling this problem and I can't seem to find a solution.
I've got a simple view used to fill out some details for a specific model. I need to render part of the form using Html.Partial (in truth this is a wrapper which renders old non-MVC controls used from another project).
I've no problems getting data FROM the controller INTO the view.
So what's the issue? How do I get user input from the partial view back to the controller after the user pressed the submit button?
Here's the view and controller I've currently got:
#model Poll
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Poll</h4>
<hr />
#*#Html.ValidationSummary(true)*#
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.Name)
#Html.Partial("~/ControlPlaceholder/QuestionPlaceholder.ascx", Model, new ViewDataDictionary(Model))
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Fill" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The view has been copied almost one-to-one from the standard generated edit view available in MVC5. Note that this is currently just a PoC - normally the whole thing should render a QuestionPlaceholder for every question in a Poll.
Here's the relevant part of the controller:
//
// GET: /Poll/Fill
[HttpGet]
public ActionResult Fill(Guid id)
{
var poll = pollRepository.Get(id);
return View(poll);
}
//
// POST: /Poll/Fill
[HttpPost]
public ActionResult Fill(Poll poll, FormCollection collection)
{
try
{
return RedirectToAction("Index");
}
catch
{
return View(poll);
}
}
it is so simple, just set name of inputs same as corresponding action parameters and let MVC ModelBinder do it's job. it's not important to render a partial in the form, it's input elements value would be passed to the action on submitting form.
another way is to use Request.Form["InputName"] that is not my first recommendation.
I am beginner in MVC3 and building one application, i need to make confirmation page where all details of user will display for confirmation.
I have build wizards to fill this information using javascript & divs and in final wizard i would like to put all details which have been filled by user
#using (Html.BeginForm("Confirm", "Home", FormMethod.Get))
{
<div>
//user details goes here...
</div>
<input type="submit" name="name" value="confirm" />
}
how can i load data here?, i need to make some method call before form will render or something else? please guide me.
thanks in advance.
The best way would be to load those data in action that return this page. Load user data into a model object and pass that object to a view:
// Return view
return View( new SomeViewModel(userData));
And than you handle those data in view, like (Razor):
#this.Model.UserFirstName ...
#using (Html.BeginForm("Confirm", "Home", FormMethod.Get))
{
<div id="userDetailDiv">
</div>
<input type="submit" name="name" value="confirm" />
}
you can use .load
$(function(){
$("#userDetailDiv").load(#Url.Action('UserDetail'));
}
or you can use RenderAction
#using (Html.BeginForm("Confirm", "Home", FormMethod.Get))
{
<div id="userDetailDiv">
#Html.RenderAction("_UserDetail", "Cintroller");
</div>
<input type="submit" name="name" value="confirm" />
}