HttpPost not getting triggered - asp.net-mvc-3

I have a website where I need to redirect the users according to their role. On button click, if the user is admin, redirect to another page; else reload the same page. On button click, the index page is loaded no matter who logs in. On debugging I found out, the [HttpPost] attribute is not triggered at all.
View:
#model namespace.ViewModels.LoginVM
#{
ViewBag.Title = "Login";
}
<h1>User Login</h1>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<br />
<div style="background-color: skyblue; width: 50%">
<div style="padding-left: 1em">
<div class="display-label" style="font-size: large">
Enter User Info<br />
<br />
</div>
<div>
<div class="editor-label">#Html.LabelFor(model => model.empID)</div>
<div class="editor-field">#Html.TextBoxFor(model => model.empID)
#Html.ValidationMessageFor(model => model.empID)
</div>
<br />
</div>
<br />
<div>
<input id="submit" type="submit" value="Submit" />
</div>
</div>
</div>
<br />
}
Controller:
public class LoginController : Controller
{
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(LoginVM model)
{
MySQL msql = new MySQL();
var empID= model.empID
var role = msql.Select("Select `role` from empDB where `eID` = '" + empID + "'");
if(role == "admin")
{
return RedirectToAction("Index","Home");
}
else
{
return View();
}
}
}

Your HttpPost action method name is Login. But your razor view, you used Index!
Update your Html.BeginForm method call to have the correct action method name and controllername values. Then when you click on submit, it will post the form data to /Login/Login
#using (Html.BeginForm("Login", "Login", FormMethod.Post))
{
}

Related

Form not reloaded with new ViewModel when posting on .Net Core 3.1

I am trying to change the value on a screen after calling a post method. It seems even with the ModelState.Clear(); method added it still does not reflect the new value on the screen. Note that I am using jQuery Unobtrusive AJAX v3.2.6 library.
Please see my razor page and controller code below.
#model TestApp.ViewModels.EmployeeViewModel
<form method="post"
data-ajax="true"
data-ajax-method="post"
data-ajax-url="#Url.Action("Detail", "Employee")">
<input asp-for="EmployeeFirstName" />
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Controller
public IActionResult Detail()
{
EmployeeViewModel employeeViewModel= new EmployeeViewModel ();
employeeViewModel.EmployeeFirstName = "John";
return View(employeeViewModel);
}
[HttpPost]
public IActionResult Detail(EmployeeViewModel employeeViewModel)
{
employeeViewModel.EmployeeFirstName = "Brian";
ModelState.Clear();
return View(employeeViewModel);
}
Since you use unobtrusive ajax,so it will return the html code of the partial view,but it will not refresh the partial view.If you want to refresh the partial view,you can try to replace the html code with data-ajax-complete.Here is a working demo:
Controller:
public IActionResult Detail()
{
EmployeeViewModel employeeViewModel = new EmployeeViewModel();
employeeViewModel.EmployeeFirstName = "John";
return View(employeeViewModel);
}
[HttpPost]
public IActionResult Detail(EmployeeViewModel employeeViewModel)
{
employeeViewModel.EmployeeFirstName = "Brian";
ModelState.Clear();
return PartialView("~/Views/_Partial.cshtml", employeeViewModel);
}
View:
#model WebApplication107.Models.EmployeeViewModel
<div class="row main-section-border">
<div id="div1" class="col-sm-12">
#{
await Html.RenderPartialAsync("~/Views/_Partial.cshtml", Model);
}
</div>
</div>
#section scripts{
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ajax-unobtrusive/3.2.6/jquery.unobtrusive-ajax.js"></script>
<script>
completed = function (xhr) {
$("#div1").html(xhr.responseText);
};
</script>
}
_Partial view:
#model WebApplication107.Models.EmployeeViewModel
<form method="post"
data-ajax="true"
data-ajax-method="post"
data-ajax-url="#Url.Action("Detail", "Test")"
data-ajax-complete="completed"
>
<input asp-for="EmployeeFirstName" />
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Result:

Validation error message not displayed in Asp.Net Core 2 MVC partial view

I have an index page with a list of "workbooks" titles and for each workbook, there is a "share" button. When pressing the button a bootstrap model (i.e. dialog) appears which displays the title of the workbook and a textarea allowing the user to type in a sharees email addresses.
When the user presses on the "share" button, I am calling a javascript function which calls a controller action that returns a partial view containing the modal dialog with a form inside it. The problem is that after pressing the submit button (i.e. "Share") there are no validation errors being shown to the user and I am not sure why that is. Could anyone provide some ideas, please?
That is my main (index.cshtml) page:
#model DNAAnalysisCore.Models.WorkBookModel
#{
}
#section BodyFill
{
<script type="text/javascript">
function showSharingView(title) {
var url = "#Url.Action("ShowShareDialog", "Home")" + "?workbookTitle=" + encodeURI(title);
$('#shareFormContainer').load(url,
function() {
$('#shareFormModal').modal("show");
});
}
function hideSharingView() {
$('#shareFormModal').modal("hide");
}
</script>
<div id="shareFormContainer" >
<!--PLACEHOLDER FOR SHARE DIALOG -->
</div>
<div class="workbook-container">
<table class="table">
<tbody>
#foreach (var workbook in Model.Workbooks)
{
<tr>
<td>#Html.ActionLink(workbook.Name, "Open", "OpenAnalytics", new {id = Model.Id, workbook = workbook.Name})</td>
<td>
<button title="Share" class="share-button" onclick='showSharingView("#workbook.Name")'> </button>
</td>
</tr>
}
</tbody>
</table>
</div>
}
That is my Controller:
public class HomeController : Controller
{
[HttpGet]
public IActionResult ShowShareDialog(string workbookTitle)
{
var shareModel = new ShareModel
{
Title = workbookTitle
};
return PartialView("_ShareView", shareModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult ShareWorkbook(string emails, string title)
{
var share = new ShareModel
{
Emails = emails
};
// TODO EMAIL THE SHARED WORKBOOK using the 'title' of the workbook and the 'email' string value
// return no content to avoid page refresh
return NoContent();
}
}
This is my partial view/modal dialog (_ShareView):
#using DNAAnalysisCore.Resources
#model DNAAnalysisCore.Models.ShareModel
<!-- Modal -->
<div class="modal fade" id="shareFormModal" role="dialog">
<div class="modal-dialog modal-md">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Share Workbook - #Model.Title</h4>
</div>
#using (Html.BeginForm("ShareWorkbook", "Home", FormMethod.Post))
{
<div class="modal-body">
<label>#BaseLanguage.Share_workbook_Instruction_text</label>
<div class="form-group">
<textarea class="form-control" asp-for="Emails" rows="4" cols="50" placeholder="#BaseLanguage.ShareDialogPlaceholder"></textarea>
#* TODO add client-side validation using jquery.validate.unobtrusive.js. See US268276 *#
<span asp-validation-for="Emails" class="text-danger"></span>
</div>
<input asp-for="Title" />
</div>
<div class="modal-footer">
<button type="submit" onclick="hideSharingView()" class="btn btn-primary">Share</button>
<button id="btnCancelDialog" type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
}
</div>
</div>
</div>
#section Scripts {
#{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
This is my ShareModel:
public class ShareModel
{
[HiddenInput]
public string Title { get; set; }
[Required]
public string Emails { get; set; }
}
The form is not added to the page when the page loads, the unobtrusive validation will not pick it up.A simple solution is to use $.validator.unobtrusive.parse("#id-of-the-form");.Refer to here.
1.Add id to your form in _ShareView partial view:
#using (Html.BeginForm("ShareWorkbook", "Home", FormMethod.Post,new { #id="partialform"}))
2.Introduce validation file _ValidationScriptsPartial.cshtml into main page(Index.cshtml) and manually register the form with the unobtrusive validation.
#section Scripts
{
#await Html.PartialAsync("_ValidationScriptsPartial")
<script type="text/javascript">
function showSharingView(title) {
var url = "#Url.Action("ShowShareDialog", "Home")" + "?workbookTitle=" + encodeURI(title);
$('#shareFormContainer').load(url,
function() {
$('#shareFormModal').modal("show");
$.validator.unobtrusive.parse("#partialform");
});
}
function hideSharingView() {
$('#shareFormModal').modal("hide");
}
</script>
}

AJAX Model Validation with Partial View

I have a partial view, which is a login that functions as a popup. All I want to do is have my model do the validation (server side) and return any errors via AJAX. The code below returns the partial view only with the errors. I want my action result to not return a a view, but only the errors. In old ASP.NET, this would be a Partial Post back. I am not sure how to accomplish this in MVC.
Here is the Model
public class LoginModel
{
[Required]
public String Email { get; set; }
[Required]
[DataType(DataType.Password)]
public String Password { get; set; }
}
Here is the Partial View
#model MySite.Models.LoginModel
#using (Ajax.BeginForm("Authenticate", "Account", null, new AjaxOptions { OnFailure = "error" }, new { id = "LoginForm" }))
{
<div class="modal-body" id="LoginPopupDialogMessage">
The page you have requested requires you to login. Please enter your credentials and choose your country:
<br />
<br />
<div class="row">
<div class="form-group col-lg-offset-2 col-lg-8">
<label>Email Address</label>
#Html.TextBoxFor(u => u.Email, new { #class = "form-control input-lg input-sm", id = "Email", name = "Email" })
#Html.ValidationMessageFor(u => u.Email)
</div>
</div>
<div class="row">
<div class="form-group col-lg-offset-2 col-lg-8 ">
<label>Password</label>
#Html.PasswordFor(u => u.Password, new { #class = "form-control input-lg input-sm", name = "Password" })
#Html.ValidationMessageFor(u => u.Password)
</div>
</div>
<div style="text-align: center; padding-top: 20px;" class="ImageGroup">
<button name="companyCode" value="LB_US" class="btn-link" type="submit">
<img src="../../WebContent/Images/icon-flag-usa.png" />
</button>
<button name="companyCode" value="LB_CA" class="btn-link" type="submit">
<img src="../../WebContent/Images/icon-flag-canada.png" />
</button>
<button name="companyCode" value="LB_EU" class="btn-link" type="submit">
<img src="../../WebContent/Images/icon-flag-europe.png" />
</button>
</div>
</div>
}
I call the parial view from _layout.cshtml.
<div class="modal fade" id="LoginPopupDialog" tabindex="-1" role="dialog" aria-labelledby="myModalLabel1" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header" style="background: #e7e3e7; color:#000;">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" style="color:#000;">
<span aria-hidden="true">×</span>
</button>
<div class="modal-title" id="LoginPopupDialogHeader">Please Login</div>
</div>
#Html.Action("Login", "Account")
</div>
</div>
</div>
My Controller Action:
[HttpPost]
[Route("account/authenticate")]
public ActionResult Authenticate(String companyCode, LoginModel model)
{
if (!ModelState.IsValid)
{
// ??
}
return PartialView("Login", model);
}
Since your code is doing an ajax form submission for the login, you should try to return a JSON response from the server. If model validation fails, you may read the validation errors from the model state dictionary and store that in a collection of strings (error messages) and return that as part of the json response. If model validation passes, you can continue executing your code to verify the login credentials and if those looks good, send back a json response with the next url for the user (to which we can redirect the user).
[HttpPost]
public ActionResult Authenticate(String companyCode, LoginModel model)
{
if (!ModelState.IsValid)
{
var errors = ViewData.ModelState.Values
.SelectMany(x => x.Errors.Select(c => c.ErrorMessage));
return Json(new { Status = "Error", Errors = errors });
}
//to do :Verify login, if good, return the below respose
var url=new UrlHelper(Request.RequestContext);
var newUrl = url.Action("About");
return Json(new { Status="Success", Url = newUrl});
}
Now in your view, you may specify a OnSuccess handler as part of the AjaxOptions. This will be a javascript object to which the json response from the server will come. We basicallly need to check the Status property value and do the appropriate things.
new AjaxOptions { OnFailure = "error" , OnSuccess="loginDone"}
The below implementation of loginDone simply alerts the error messages. You can update it to show it as part of the DOM.
function loginDone(d) {
if (d.Status === "Success") {
window.location.href = d.Url;
} else {
$.each(d.Errors,function(a, b) {
alert(b);
});
}
}
You may also consider enabling the unobtrusive client side validation which does the client side validation before trying to make a call to server. This will also show the error messages in the validation error spans (same as the normal mvc model validation does)

MVC Updating Partial View with Ajax.BeginForm

The Ajax form does update selected div, but instead of just reloading a partial view in that div it inserts the whole page content into that div.
.cshtml file
<fieldset>
<legend>File(s)</legend>
<div id="filesBody">
#Html.Action("Action", "Controller", new {id=Model.Id})
</div>
<br />
#using (Ajax.BeginForm("UploadFile", "Controller", null, new AjaxOptions { UpdateTargetId="filesBody"}, new { enctype = "multipart/form-data", #id = "myForm" }))
{
#Html.HiddenFor(model => model.ComplaintId)
<div>
<label for="File">Add File:</label>
<input type="file" name="FileAttachment" />
<input type="submit" value="Upload" />
#Html.ValidationMessage("FileAttachment")
</div>
}
</fieldset>
Controller
public PartialViewResult GetFilesData(long? Id)
{
Model Model = new Model(Id);
TryUpdateModel(Model);
return PartialView(Model);
}
Partial view
#model Models
<div id="reloadField">
#foreach (var ph in Model.docs)
{
///code
}
</div>
In your partial view set the Layout equal to null.
#model Models
#{
Layout = null;
}
UPDATE
Change your Ajax.BeginForm to call the GetFilesData action.

pass a value of the form from view to controller

how do i pass the value of the form, which is (i assume) a string of date to the controller...
here is my view:
<script type="text/javascript" language="javascript">
$(function () {
$(".datepicker").datepicker({ onSelect: function (dateText, inst) { $("FORM").submit(); },
altField: ".alternate"
});
});
</script>
#model IEnumerable<CorReservation.Models.Reservation>
#{
ViewBag.Title = "Index";
}
<div class="divRightSide">
<div>
<div class="datepicker">
</div>
<form action="/" title="fff">
<input type="text" class="alternate" readonly="readonly" />
</form>
</div>
// do something eg. foreach (var item in Model)
{ #Html.DisplayFor(modelItem => item.Date)}
here is my controller: i want to pass the date selected from the datepicker to the controller and then the controller would return an Ienumerable of reservations...
DateTime date = System.DateTime.Now;
private ReservationEntities db = new ReservationEntities();
public ViewResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string dateInput)
{
date = Convert.ToDateTime(dateInput);
var reservations = db.Reservations.Where(r=> r.Date ==date).Include(r => r.Employee).Include(r => r.Room).OrderByDescending(r => r.Date);
return View(reservations);
}
There are 2 ways to do this. Make the form input name attribute match the expected attribute in your controller.
For example:
<input type="text" class="alternate" readonly="readonly" name="dateInput" />
Or if there's going to be a lot of input values, use a Model.
It's automatically done based on the 'name' attribute of the HTML fields you want to submit.
Change your form to
<form action="/" title="fff">
<input name="dateInput" type="text" class="alternate" readonly="readonly" />
</form>
And it should work just like that.
Also, as you are using Razor syntax, you could use the Razor HTML helpers like so
#model IEnumerable<CorReservation.Models.Reservation>
#{
ViewBag.Title = "Index";
}
<div class="divRightSide">
<div>
<div class="datepicker">
</div>
#using(#Html.BeginForm("<your controller name>", "<your action name e.g. Index>"){
Html.TextBox("dateInput", "", new { #readonly="readonly", #class="alternate" })
}
</div>
// do something eg. foreach (var item in Model)
{ #Html.DisplayFor(modelItem => item.Date)}

Resources