I have the following form in my View.
#using (Html.BeginForm("PostComment", "Blog")) name)
{
<fieldset id="frmTester">
<div class="formContainer">
<span><input id="username" name="username" /></span>
<input id="submit" name="submit" type="submit" value="Submit" />
</div>
</fieldset>
}
Now I have the following Method in my BlogController...
public ActionResult PostComment(string username)
{
return View();
}
I really don't get MVC very well. I dont see why I cant get the above ActionResult method to execute. I'm just trying to handle a postback. Anyone have any idea why this doesn't work or an alternative approach.
use [HttpPost] :
[HttpPost]
public ActionResult PostComment(string username)
{
string u = Request.Form["username"] ;
// return Content(u); //if you want dispaly username use this
return View();
}
Change your view code to this...
#using (Html.BeginForm("PostComment", "Blog", FormMethod.Post))
{
<fieldset id="frmTester">
<div class="formContainer">
<span><input id="username" name="username" type="text" /></span>
<input id="submit" name="submit" type="submit" value="Submit" />
</div>
</fieldset>
}
and your action method to....
[HttpPost]
public ActionResult PostComment(string username)
{
return View();
}
Related
I am trying to make a validation for my report form where the report can only be submited if the email = to "Sample#email.com". My problem is the code works perfectly without the validation but when I include the validation code if (!ModelState.IsValid){return View("Create");} into the my controller the validation works perfectly but when the email is correct it just refreshes the page without submiting it or redirecting it to the submit view
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Submit(Reports report)
{
if (!ModelState.IsValid)
{
return View("Create");
}
_reportRepository.CreateReport(report);
return View();
Validation Code:
public class EmailValidation : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var report = (Reports)validationContext.ObjectInstance;
if (report.Email == "Sample#email.com")
{
return ValidationResult.Success;
}
return new ValidationResult("Invalid email");
}
}
Report:
public class Reports
{
[Key]
public int ReportId { get; set; }
[Required(ErrorMessage = "Please enter email.")]
[Display(Name = "Email :")]
[EmailValidation(ErrorMessage ="enter valid email")]
public string Email { get; set; }
}
Create View:
#model Reports
#using Microsoft.AspNetCore.Identity
#inject UserManager<IdentityUser> UserManager
<body>
<form asp-action="Submit" method="post" role="form">
<div class="container1">
<div class=" form-group row">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-3">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group row float-right">
<div class="col-md-offset-2 col-md-5 float-md-left">
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
</div>
I have this in my cshtml file
<div class="login">
#await Html.PartialAsync("_Login")
</div>
<div class="register">
#await Html.PartialAsync("_Register")
</div>
And my partials look like this
_Login:
#using Microsoft.AspNetCore.Identity
#using project.Models
#model LoginViewModel
#inject SignInManager<ApplicationUser> SignInManager
#inject UserManager<ApplicationUser> UserManager
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post" class="form-horizontal">
...
<button id="loginBtn" type="submit" class="btn btn-default">Log in</button>
</form>
_Register:
#using Microsoft.AspNetCore.Identity
#using project.Models
#model RegisterViewModel
#inject SignInManager<ApplicationUser> SignInManager
#inject UserManager<ApplicationUser> UserManager
<form asp-controller="Account" asp-action="Register" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post" class="form-horizontal">
...
<button id="registerBtn" type="submit" class="btn btn-default">Register</button>
</form>
My idea is to have one of the two divs always with display:none (Initially it's the second one with this property), so the user interacts with only one form at a time. However, when I click the button [Log In] I get this error:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'cartoondrawme.Models.AccountViewModels.LoginViewModel', but this ViewDataDictionary instance requires a model item of type 'cartoondrawme.Models.AccountViewModels.RegisterViewModel'.
My question is, do I have a flaw and what is it, or is this method entirely wrong, in which case - what is the right way?
I don't understand how the submit button from one form triggers the other form. If I delete the second div, it works fine.
Thank you.
i hope its not too late..i used this method to solve the problem.
1) Create a class
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultipleButtonAttribute : ActionNameSelectorAttribute
{
public string Name { get; set; }
public string Argument { get; set; }
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
var isValidName = false;
var keyValue = string.Format("{0}:{1}", Name, Argument);
var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);
if (value != null)
{
controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
isValidName = true;
}
return isValidName;
}
}
Edit your views
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post" class="form-horizontal">
...
<button id="loginBtn" type="submit" class="btn btn-default" name="action:Login">Log in</button>
</form>
<form asp-controller="Account" asp-action="Register" method="post" class="form-horizontal">
...
<button id="registerBtn" type="submit" class="btn btn-default" name="action:Register">Log in</button>
</form>
Add these to controller
[HttpPost]
[MultipleButton(Name = "action", Argument = "Login")]
public IActionResult Login(LoginViewModel model) { ... }
[HttpPost]
[MultipleButton(Name = "action", Argument = "Register")]
public IActionResult Register(RegisterViewModel model) { ... }
Here is my ViewModel
public class VideoViewModel
{
public string Movie { get; set; }
public int Order { get; set; }
public IList<VideoContent> VideoContents { get; set; }
}
How can I pass data from fields in view to controller mapped to my collection in my viewModel?
This code in my view is passing Movie and Order to controller but I can't figure out hos to send the collection too.
#model ViewModels.VideoViewModel
<form method="post">
<div class="form-group">
<label for="movie">Movie</label>
<input type="text" name="Movie" id="movie" class="form-control">
</div>
<div class="form-group">
<label for="order">Order</label>
<input type="text" name="Order" id="order" class="form-control">
</div>
<button type="submit" class="btn btn-primary">Add to database</button>
</form>
Thanks in advance!
/ Kalle
ASP .NET Core uses the name attribute to bind the data from the input fields to the view model.
This should work for passing the collection.
for(int c = 0; c < VideoContents.Count; c++)
{
<input name="VideoContents[#c].FirstProperty" value="#Model.VideoContents[#c].FirstProperty"/>
<input name="VideoContents[#c].SecondProperty" value="#Model.VideoContents[c].SecondProperty"/>
}
login.jsp
<div id="login" class="animate form">
<form action="${loginUrl}" method="POST">
<h1>Log in</h1>
<c:url var="loginUrl" value="/login" />
<c:if test="${param.error != null}">
<input type="text" class="alert-danger" id="danger" name="danger"
placeholder="Invalid username and password." disabled />
<br />
</c:if>
<c:if test="${param.logout != null}">
<input type="text" class="alert-success" id="success"
name="success"
placeholder="You have been logged out successfully." disabled />
<br />
</c:if>
<p>
<label for="username" class="uname" data-icon="u"> Your
email </label> <input id="username" name="login" required="required"
type="text" placeholder="mymail#atos.net" />
</p>
<p>
<label for="password" class="youpasswd" data-icon="p">
Your password </label> <input id="password" name="password"
required="required" type="password" placeholder="eg. X8df!90EO" />
</p>
<p class="keeplogin">
<input type="checkbox" name="remember-me" id="rememberme"
value="rememberme" /> <label for="rememberme">Remember
Me</label>
</p>
<p class="login button">
<input type="submit" value="Login" />
</p>
<p class="change_link"></p>
</form>
</div>
userlist.jsp
<div class="generic-container">
<%#include file="authheader.jsp" %>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading"><span class="lead">List of Users </span></div>
<table class="table table-hover">
<thead>
<tr>
<th>Prenom</th>
<th>Nom</th>
<th>Matricule</th>
<th>Login</th>
<sec:authorize access="hasRole('ADMIN') or hasRole('READ')">
<th width="100"></th>
</sec:authorize>
<sec:authorize access="hasRole('ADMIN')">
<th width="100"></th>
</sec:authorize>
</tr>
</thead>
<tbody>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.prenom}</td>
<td>${user.nom}</td>
<td>${user.matricule}</td>
<td>${user.login}</td>
<sec:authorize access="hasRole('ADMIN') or hasRole('READ')">
<td>edit</td>
</sec:authorize>
<sec:authorize access="hasRole('ADMIN')">
<td>delete</td>
</sec:authorize>
</tr>
</c:forEach>
</tbody>
</table>
</div>
<sec:authorize access="hasRole('ADMIN')">
<div class="well">
Add New User
</div>
</sec:authorize>
</div>
AppController.java
#Controller
#RequestMapping("/")
#SessionAttributes("roles")
public class AppController {
#Autowired
IService_User<USER> userService;
#Autowired
IService<COMPTE> compteService;
#Autowired
MessageSource messageSource;
#Autowired
PersistentTokenBasedRememberMeServices persistentTokenBasedRememberMeServices;
#Autowired
AuthenticationTrustResolver authenticationTrustResolver;
#RequestMapping(value = { "/", "/list" }, method = { RequestMethod.GET, RequestMethod.POST })
public String listUsers(ModelMap model) {
List<USER> users = userService.findAllOBJECTS();
model.addAttribute("users", users);
model.addAttribute("loggedinuser", getPrincipal());
return "userslist";
}
#RequestMapping(value = {"/login"}, method = { RequestMethod.GET, RequestMethod.POST })
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
}
There are 2 pages: login.jsp - start page which includes form to be populated with login and password - userlist.jsp list of results "display all users persisted in DB"..
First the login page is shown, when i click on submit button i got this error:
org.springframework.web.servlet.PageNotFound - Request method 'POST' not supported
In your login.jsp you are using http method POST
<form action="${loginUrl}" method="POST">
and in controller, you are using http method GET
#RequestMapping(value = {"/login"}, method = RequestMethod.GET)
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
Problem will be solved after changing method = RequestMethod.POST in your controller like this
#RequestMapping(value = {"/login"}, method = RequestMethod.POST)
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
In your login form you are explicitly making an POST request... and in your controller the the url is mapped to GET request.. this is the issue... Please make the controller as POST... like
#RequestMapping(value = {"/login"}, method = RequestMethod.POST)
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
Add post method in #RequestMapping annotation, like following;)
#RequestMapping(value = {"/login"}, method = {RequestMethod.GET, RequestMethod.POST})
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:/list";
}
}
if you are using spring security 4.x.x. , CSRF is enabled by default. therefore you have to provide the csrf filed in your form.
Adding the csrf token as hidden fields does the trick:
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
I have been banging my head against the wall trying to solve this issue.
I have this view controller
public class LoginController : Controller
{
public ActionResult Index(LoginClass model)
{
return View(model);
}
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
if (!this.ModelState.IsValid)
{
return this.View(model);
}
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
{
return Redirect(ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError(string.Empty, "The user name or password provided is incorrect");
}
}
return RedirectToAction("Index", "Login", model);
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
}
and here is my view:
<section id="login">
<div class="container">
<form action="~/Login/Login" id="Login" method="post">
<div class="row">
<div class="col-md-12">
<p>
<label for="username">Username</label>
<input type="text" id="username" name="username" class="form-control" />
</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
<label for="password">Password</label>
<input type="password" id="password" name="password" class="form-control" />
</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
<input type="submit" id="submit" name="submit" value="Login" class="btn btn-default" />
</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
<label for="password">Remember Me?</label>
<input type="checkbox" id="chkPersist" name="chkPersist" />
</p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
#Html.ValidationSummary()
</p>
</div>
</div>
</form>
</div>
</section>
My issue is that my error message is not appearing when I enter the wrong username and password. Why is not displaying?
The problem is with the last line in your Login method. You are calling RedirectToAction instead of View. This has the consequence that you lose all your view specific state including the model state and validation errors that you built up in your Login Action. You can change your Login method like so (I simplified it a little), really the only change is replacing RedirectToAction("Index", "Login", model) with View(model) on the last line.
If you do want to redirect in the event of authentication failure and you did want to use RedirectToAction then see my other answer I posted here.
[HttpPost]
public ActionResult Login(LoginClass model, string ReturnUrl)
{
if (!this.ModelState.IsValid)
return this.View(model);
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/")
&& !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\"))
{
return Redirect(ReturnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
ModelState.AddModelError(string.Empty, "The user name or password provided is incorrect");
return this.View(model); // return to the same view to show your error message
// return RedirectToAction("Index", "Login", model); // do not redirect
}
You need to add a placeholder by using the Html Helper function to display the message.
<div>#Html.ValidationMesssage("KeyName")</div>
to your view so that you can display the validation message.
The KeyName comes from controller
ModelState.AddModelError("KeyName", "The user name or password provided is incorrect");
Also you may need to ensure client side validation is enabled in your web.config.(usually they are)
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>