ASP.NET MVC Show message before redirects if success - asp.net-mvc

Here's my web api on account controller using identity that can change the password wit validation using data annotations
[HttpGet]
[AllowAnonymous]
public IActionResult ChangePassword(string email, string returnUrl)
{
return email == null || returnUrl == null ? View("Error") : View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
{
if (model == null)
{
return BadRequest();
}
if (ModelState.IsValid)
{
var result = await _changePasswordCommand.ChangePassword(model);
if (result.Succeeded)
{
ViewBag.IsSuccess = true;
ModelState.Clear();
return Redirect(model.returnUrl);
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
return View(model) ;
}
then in my div razor views
<form class="change-password-form" asp-controller="Account" asp-action="ChangePassword" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input id="email-hidden" asp-for="Email" type="hidden" />
<input id="return-url" asp-for="ReturnUrl" type="hidden" />
<div class="form-group change-password">
#if (ViewBag.IsSuccess == true)
{
<div class="alert alert-success alert-dismissible fade show text-center">Successfully Changed Password!</div>
}
<label asp-for="CurrentPassword" class="control-label"></label>
<input class="form-control" type="password" asp-for="CurrentPassword">
<span asp-validation-for="CurrentPassword" class="text-danger"></span>
</div>
<div class="form-group change-password">
<label asp-for="NewPassword" class="control-label">New password</label>
<input id="password" class="form-control" type="password" name="newPassword" asp-for="NewPassword" onkeyup="isGood(this.value)">
<span asp-validation-for="NewPassword" class="text-danger"></span>
</div>
<div class="form-group change-password">
<label asp-for="ConfirmNewPassword" class="control-label"></label>
<input asp-for="ConfirmNewPassword" class="form-control" type="password" />
<span asp-validation-for="ConfirmNewPassword" class="text-danger"></span>
</div>
<div class="change-password-footer">
<button id="btn-cancel" type="button" class="btn btn-primary cancel">
CANCEL
</button>
<button id="btn-save" type="submit" class="btn btn-secondary save" disabled>
SAVE
</button>
</div>
</form>
I want to be able to show the successfully changed password message before it redirects problem is it always redirect to account/changepassword after submit

You can write if condition outside the form tag, like this
#if (ViewBag.IsSuccess == true)
{
<div class="alert alert-success alert-dismissible fade show text-center">Successfully
Changed Password!
</div>
}
<form class="change-password-form" asp-controller="Account" asp-action="ChangePassword" method="post">
#*your code*#
</form>
Or remove method="post" then try

look at this place in your account controller.
...
if (result.Succeeded)
{
ViewBag.IsSuccess = true;
ModelState.Clear();
return Redirect(model.returnUrl);
}
...
Instead of the re-direct, use "return View(model);". then you can redirect the page ajax, (testing if the ViewBag.IsSuccess == true and model.returnUrl != null) you in the account controller, you will instead have.
...
if (result.Succeeded)
{
ViewBag.IsSuccess = true;
ModelState.Clear();
//return Redirect(model.returnUrl);
return View(model);
}
...
With this, the success alert would show. Then have a javascript method onload, test if success is true and the the return is not null. something like this (in the view)
...
#{
bool isSuccess = ViewBag.IsSuccess;
string rUrl = model.returnUrl;
}
...
<script>
function redirect(isSuccess, returnUrl)
{
//use ajax to redirect;
}
redirect(#isSuccess, #rUrl);
</script>

Related

How to get Input control value in controller's Index method asp.net core

I am working on captcha authentication. I want to get user entered captcha value in controller's Index method. Below is my cshtml file code
#{
ViewData["Title"] = "Home Page";
}
<div class="container">
<label for="captcha"><b>Enter chaptcha - </b></label>
<label id="lblshowCaptcha"><b>#ViewData["captcha"]</b></label>
<input id="txtCapValue" type="text" placeholder="Enter captcha" name="cap" required>
<br/>
<button class="button" type="submit">Login</button>
<br />
</div>
When user entering captcha value in txtCapValue and click submit button I need that value in controller. Here is my controller
public IActionResult Index()
{
randnumber = RandomString(6);
ViewData["captcha"] = randnumber;
return View();
}
how can I get txtCapValue input control value when user click on submit button ?
One of the easy ways using the Form Tag Helper:
<form asp-controller="Controller_Name" asp-action="Captcha" method="post">
<div class="container">
<label for="captcha"><b>Enter chaptcha - </b></label>
<label id="lblshowCaptcha"><b>#ViewData["captcha"]</b></label>
<input id="txtCapValue" type="text" placeholder="Enter captcha" name="cap" required>
<br />
<button class="button" type="submit">Login</button>
<br />
</div>
</form>
And on the server side:
[HttpPost]
public IActionResult Captcha(string cap)
{
... using the `cap`
return View("Index");
}
I want to get user entered captcha value in controller's Index
method.
There are two options, you can try:
Option1: use Form Tag Helper
Index method:
public IActionResult Index(string cap)
{
ViewData["captcha"] = 6;//do your staff
return View();
}
Index view:
<form method="get" asp-action="Index">
<div class="container">
<label for="captcha"><b>Enter chaptcha - </b></label>
<label id="lblshowCaptcha"><b>#ViewData["captcha"]</b></label>
<input id="txtCapValue" type="text" placeholder="Enter captcha" name="cap" required>
<br />
<button class="button" type="submit">Login</button>
<br />
</div>
</form>
Option 2: use ajax
Index method:
public IActionResult Index(string cap)
{
ViewData["captcha"] = 6;
return View();
}
Index view:
<div class="container">
<label for="captcha"><b>Enter chaptcha - </b></label>
<label id="lblshowCaptcha"><b>#ViewData["captcha"]</b></label>
<input id="txtCapValue" type="text" placeholder="Enter captcha" name="cap" required>
<br />
<button id="buttonDemo1" class="button" type="submit">Login</button>
<br />
</div>
#section scripts{
<script type="text/javascript">
$(document).ready(function () {
$('#buttonDemo1').click(function () {
var cap = $("#txtCapValue");
$.ajax({
type: 'GET',
url: '/Home/Index',
data: cap
});
});
});
</script>
}
result:

Edit action has not been hitting while I push the submit button

I have an edit button in each row of my Datatable. I have two actions for editing. One for Getting data in a Datatable and the other one for posting my information. The code behind my Edit button in the my Home Index is:
{
"data": "Id",
"render": function (data, type, full, meta) {
return `<div class="text-center"> <a class="btn btn-info"
href="/Home/EditGet/` + data + `" >Edit</a> </div> `;
}
and my home controller methods are:
/// Get Edit
[HttpGet]
[Route("{Id}")]
public IActionResult EditGet(int? id)
{
if (id == null || id == 0)
{
return NotFound();
}
var obj = _sv.OpenRecord(id);
if (obj == null)
{
return NotFound();
}
return View("EditGet", obj);
}
/// Post Edit
[HttpPost]
public IActionResult EditPost(SalesVeiwModel sales)
{
if (ModelState.IsValid)
{
var res= _sv.Update(sales.Comment);
if (res==null )
{
return Json(data: "Not found");
}
return RedirectToAction("EditGet");
}
return Json(data: "Is not valid");
}
And finally my EditGet view is like bellow:
<form id="contact-form" method="post" asp-controller="Home" asp-
action="EditPost" role="form" >
<input asp-for="Id" hidden />
<div class="form-group">
<label>Invoice Nomber</label>
<input id="form_IBNo" type="text" class="form-control" disabled asp-for="IBNo">
</div>
.
.
.
<div class="col-md-12">
<input type="submit" class="btn btn-success btn-send" value="Confirm" asp-
controller="Home" asp-action="EditGet">
</form>
You should have two buttons,one call EditGet,one call EditPost,here is a demo:
<form id="contact-form" method="post" asp-controller="Home" asp-
action="EditPost" role="form" >
<input asp-for="Id" hidden />
<div class="form-group">
<label>Invoice Nomber</label>
<input id="form_IBNo" type="text" class="form-control" disabled asp-for="IBNo">
</div>
.
.
.
<div class="col-md-12">
<input type="submit" class="btn btn-success btn-send" value="Confirm">
<a class="btn btn-success btn-send" value="Confirm" asp-controller="Home" asp-action="EditGet" asp-route-id="1">EditGet</a>
</div>
</form>

Data not populating in form upon clicking edit

I am working on this ASP.NET MVC project where I am performing simple CRUD operations. On clicking Edit button, I want to get the data from the database and populate it in the Create View (same view with the help of which I entered the data).
The issue that I have is that, though I am able to enter the data into the database using the Create.cshtml view, I am not able to populate the data back into the fields to the same View upon clicking Edit. On checking, I see that I am able to get the data from the database from the Controller and I am sending it to the View - Create. But, the fields are not getting populated in the View.
Where am I going wrong?
View - Create.cshtml
<form method="post" action="/Books/Create" id="formBooks">
<div class="form-group">
<div class="form-row">
<div class="form-group col-md-6">
<div>
<label asp-for="Title" class="label">Title</label>
<input asp-for="Title" class="form-control" id="title" name="title" required />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div>
<label asp-for="Author" class="label">Author</label>
<input asp-for="Author" class="form-control" id="author" name="author" required />
<span asp-validation-for="Author" class="text-danger"></span>
</div>
...
</div>
<div class="form-group col-md-6">
<button type="submit" value="Save" class="btn bgm-orange waves-effect mybtn">SAVE</button>
</div>
</div>
</div>
</form>
Controller - BooksController.cs
public ActionResult Create(int? Id)
{
if(Id == null)
{
return View();
}
else
{
var bookData = _context.Books
.Where(b => b.ID == Id)
.FirstOrDefault();
return View(bookData);
}
}
public ActionResult Create(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Books books= db.Books.Find(id);
if (books== null)
{
return HttpNotFound();
}
return View(books);
}
//Try this i hope this will work
The name attribute plays a vital role in binding the data to the <input></input> field. Also, value attribute gets the value to display in the Edit view.
<input asp-for="Title" class="form-control" id="title" name="title" placeholder="Enter title..." value="#(Model != null ? Model.Title : "")" required />

How can I return text to my current mvc view?

I have a login page within an ASP.NET Core App with a pop up to send a password reset email to the users email (Just using Identity):
<div class="login-body">
<div class="container">
<form asp-controller="Account" asp-action="Login" asp-route-returnurl="#ViewData["ReturnUrl"]" method="post" class="form-signin">
<h2 class="form-signin-heading">#Localizer["Sign In"]</h2>
<div class="login-wrap">
<div class="user-login-info">
<input asp-for="Email" type="email" class="form-control" placeholder="#Localizer["Email"]" autofocus/>
<span asp-validation-for="Email" class="text-danger"></span>
<input asp-for="Password" type="password" class="form-control" placeholder="#Localizer["Password"]"/>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label class="checkbox">
<input asp-for="RememberMe"/> Remember me
<span class="pull-right">
<a data-toggle="modal" href="#forgotPassModal">Reset Password</a>
</span>
</label>
<button class="btn btn-lg btn-login btn-block" type="submit">#Localizer["Sign In"]</button>
<div class="registration">
#Localizer["No Account"]
<a asp-area="" asp-controller="Account" asp-action="Register">#Localizer["Create Account"]</a>
</div>
</div>
<!-- Modal -->
<div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="forgotPassModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Reset Password</h4>
</div>
<div class="modal-body">
<p>Enter your e-mail address below to reset your password.</p>
<input type="text" name="email" placeholder="Email" autocomplete="off" class="form-control placeholder-no-fix">
</div>
<div class="modal-footer">
<button data-dismiss="modal" class="btn btn-default" type="button">Cancel</button>
<button class="btn btn-success" asp-controller="Account" asp-action="ForgotPassword" method="post">Submit</button>
#*<input type="button" class="btn btn-success" asp-controller="Account" asp-action="ForgotPassword" formmethod="post">Submit<input>*#
</div>
</div>
</div>
</div>
<!-- modal -->
</form>
</div>
When I input the email address it does the right thing, sends an email with a code, but it redirects me to a separate view stating to go check your emails.
Is it possible to just return a message either to the popup window or login page saying the same thing?
This is the ForgotPassword Action:
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user)))
{
return View("ForgotPasswordConfirmation");
}
var code = await UserManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action(nameof(ResetPassword), "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailAsync(model.Email, "Reset Password",
$"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
return View("ForgotPasswordConfirmation");
}
return View(model);
}
What you can use is TempData. TempData can hold data for one more additional request and only for one additional request. So you can store this information in the TempData. It is meant for things like your use case. It could look something like this.
public IActionResult Login()
{
var loginModel = new LoginModel();
loginModel.ForgotPassWordModel = (ForgotPassWordModel) TempData["ForgotPassword"];
return View(loginModel);
}
public IActionResult ForgotPassword()
{
if (valid)
{
TempData["ForgotPassword"] = new ForgotPassWordModel() {callbackUrl = "Go to this"};
return RedirectToAction("Login");
}
return View();
}
Here is my example LoginModel and my ForgottonPasswordModel. Ofcourse, yours will be more complicated.
public class ForgotPassWordModel
{
public string callbackUrl;
}
public class LoginModel
{
public ForgotPassWordModel ForgotPassWordModel { get; set; }
}
When someone makes a request to ForgotPassword, if it is valid, store the result in TempData and Redirect back to Login. Now you can read the TempData["ForgotPassword"] that you just set in the previous request. In my example, I put the data in my LoginModel. If there is no tempData, it would be null. Now in your view you can check for this ForgotPassword property.
#if (Model.ForgotPassWordModel != null)
{
// Show message/modal
}
The great thing about TempData is that when you set data, it is only held for one more additional request so it works for situations like these.

Bad Request MVC HttpPost

I have the following cshtml file.
#model Models.AuthorizeUser
#{
ViewBag.Title = "Authorize";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container">
<div class="card card-container">
<img class="profile-img-card" src="~/Content/images/rblogo_reverse-pms348_000.gif" />
<p> </p>
<form method="POST">
<p>Hello, #Model.Name</p>
<p>A third party application want to do the following on your behalf:</p>
<ul>
#foreach (var scope in Model.Scopes)
{
<li>#scope.ScopeDescription</li>
}
</ul>
<div class ="row">
<div class="col-md-4">
<button class="btn btn-block btn-primary btn-signin" name="submit" type="submit" value="authorize">Grant</button>
</div>
<div class="col-md-8">
<button class="btn btn-block btn-primary btn-signin btn-small-text" name="submit" type="submit" value="logout">Sign in as different user</button>
</div>
</div>
</form>
</div>
</div>
I have my controller file as follows:
public class OAuthController : Controller
{
[HttpGet]
public ActionResult Authorize()
{
logger.Trace("Authorize method entered");
AuthorizeUser authorizeUser;
......
return View(authorizeUser);
}
[HttpPost]
public ActionResult Authorize(AuthorizeUser authorizeUser, string submit)
{
logger.Trace("Authorize with object");
if (Response.StatusCode != 200)
{
logger.Trace("status code " + Response.StatusCode);
logger.Trace("status description " + Response.StatusDescription);
return View("AuthorizeError");
}
..............
}
When the form is displayed, the info is displayed correctly. After I click Grant button, I got Response.StatusCode == 400. Both authorizeUser and submit are null. I am expecting StatuCode == 200 with values of authrizeUser and submit.
Have you tried using Html.BeginForm()?
Instead of using <form method="POST"> you could use Html.BeginForm("Action", "Controller")

Resources