Remote validation is not being executed in ASP.NET MVC5 - asp.net

I am developing an ASP.NET MVC web application. I am doing remote validation to one of my view model in controller. But it is not working. Remote validation method in controller is not even executed. I searched solutions online and that could not solve my problem. I found these (Remote Attribue Validation not firing in Asp.Net MVC and ASP.NET MVC RemoteAttribute validation not working - Action not being executed) and I tried on it.
This is my model class remote validation applied on Name property
public class CreateCategoryVM
{
public int Id { get; set; }
[Required]
[MaxLength(50)]
[Remote("IsNameUnique","Category",ErrorMessage= "Name must be unique")]
public string Name { get; set; }
[MaxLength(55)]
public string MmName { get; set; }
public IEnumerable<SelectListItem> CategorySelectItems { get; set; }
public int SelectedCategoryId { get; set; }
}
My remote validation method and action method are in the same controller.
This is my create action method and validation method in my controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateCategoryVM model)
{
if(ModelState.IsValid)
{
try
{
Category category = new Category
{
Name = model.Name,
MmName = model.MmName
};
categoryRepo.Create(category);
return RedirectToAction("Create");
}
catch
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
}
model.CategorySelectItems = categoryRepo.CategorySelectItems(model.SelectedCategoryId, "Select category", Thread.CurrentThread.CurrentCulture.Name);
return View(model);
}
public JsonResult IsNameUnique(string Name,int Id)
{
if(string.IsNullOrEmpty(Name))
{
return Json(true,JsonRequestBehavior.AllowGet);
}
else
{
var category = categoryRepo.GetCategoryByName(Name);
if(category)
{
return Json(false, JsonRequestBehavior.AllowGet);
}
else
{
return Json(true, JsonRequestBehavior.AllowGet);
}
}
}
Required JavaScript settings are enabled in web.config as well
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
But when I submit the form, IsNameUnique action is not executed for remote validation. Everything is working well except from it. New category is also created if validation is passed. Required validation is working also. Only remote validation method is not executed. I tested using break point. How can I fix this?
Update
I added jquery.validate.js and jquery.validate.unobtrusive.js. Then I run and submit the form. Now it is not even submitted. I check JavaScript code and I have no idea how to fix it. I set break point. Not get run when I click submit button.
This is the JavaScript console of browser
This is debugger of browser
This is my view
#using(Html.BeginForm())
{
#Html.AntiForgeryToken();
#Html.ValidationSummary()
#Html.HiddenFor(m=>m.Id)
<div class="form-horizontal" role="form">
<div class="form-group">
<label class="control-label col-md-3">Name</label>
<div class="col-md-9">
#Html.TextBoxFor(m => m.Name, new { #class="form-control" })
#Html.ValidationMessageFor(m=>m.Name)
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">MM Name</label>
<div class="col-md-9">
#Html.TextBoxFor(m => m.MmName, new { #class="form-control" })
#Html.ValidationMessageFor(m=>m.MmName)
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Parent</label>
<div class="col-md-9">
#Html.DropDownListFor(m => m.SelectedCategoryId, Model.CategorySelectItems, new { #class = "form-control" })
#Html.ValidationMessageFor(m=>m.SelectedCategoryId)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-3 col-md-9">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</div>
}
How can I get it work?

Related

I am getting null value in the server side from CheckBox in asp.net MVC

When I check the box, it shows it has a false value in the server side model but in the ajax call getting values it shows null values.
In the model class:
[Display(Name = "Is Buyer")]
public bool IsBuyer { get; set; }
In the Razor Page:
<div class="row g-my-4">
<div class="col-md-10 g-pl-0">
<div class="row">
<div class="col-md-1"> </div>
<div class="col-md-7 g-pl-0 g-pr-0" id="IsBuyer">
<label>
#Html.CheckBoxFor(m=>m.IsBuyer)
#*#Html.CheckBoxFor(model => model.IsBuyer, new { id = "CheckBuyer" })*#
#*#Html.CheckBox("IsBuyer")*#
Buyer
</label>
</div>
</div>
</div>
</div>
I tried to use everything but nothing is working.
Getting data values to use ajax call
Here you can see the IsBuyer attribute is null = empty, and here on the server side it's getting false value however I have checked every check box but that's what I am getting back
Try to use usual BeginForm() block and post data like below:
#model Models.ViewModel
#using (Html.BeginForm())
{
<div class="form-group row">
<p>#Html.LabelFor(l => Model.IsBuyer) </p>
#Html.CheckBoxFor(r => Model.IsBuyer)
</div>
<input id="Button" type="submit" value="Save" />
}
In the controller code:
public IActionResult IndexTest()
{
var model = new ViewModel() { IsBuyer = true };
return View(model);
}
[HttpPost]
public IActionResult IndexTest(ViewModel data)
{
if (ModelState.IsValid)
{
// your code here...
}
return RedirectToAction("IndexTest", data);
}
// View data model class
public class ViewModel
{
[Display(Name = "Is Buyer")]
public bool IsBuyer { get; set; }
// Additional propereties is defined here...
}

Razor PageModel RedirectToRouteResult does not work when calling OnPost

I'm trying to implement simple Asp.net core web application login flow.
The LoginModel
namespace Trading_System.UI.Pages.Account
{
public class LoginModel : PageModel
{
[BindProperty]
public string Username { get; set; }
[BindProperty]
public string Password { get; set; }
public string ReturnUrl { get; set; }
public string ErrorMessage { get; set; }
private IUserManager m_userManager;
public LoginModel(IUserManager userManager)
{
m_userManager = userManager;
}
public void OnGet(string returnUrl)
{
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPost()
{
var user = m_userManager.GetUser(Username, Password);
if (user == null)
{
ErrorMessage = "Username or password are invalid.";
return Page();
}
var claims = new List<Claim>()
{
new Claim(ClaimTypes.NameIdentifier, user.UserName)
};
var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
return new RedirectToRouteResult(ReturnUrl);
}
public async Task<IActionResult> OnPostLogout(string returnUrl)
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return new RedirectToPageResult("/index");
}
}
}
The cshtml code of Login
#page
#model Account.LoginModel
#{
ViewData["Title"] = "Login";
}
<div class="login-page">
<div class="page-header">
<h1>Login</h1>
</div>
<div class="row">
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Please enter your credentials</h3>
</div>
<div class="panel-body">
<form method="post">
<fieldset>
<div class="form-group">
<label asp-for="Username"></label>
<input class="form-control" placeholder="Username" asp-for="Username" autofocus>
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input type="password" class="form-control" placeholder="Password" asp-for="Password" autocomplete="off">
</div>
<div class="form-group">
<button class="btn btn-primary">Login</button>
</div>
#if(!string.IsNullOrEmpty(Model.ErrorMessage))
{
<div class="alert alert-warning">#Model.ErrorMessage</div>
}
</fieldset>
</form>
</div>
</div>
</div>
</div>
</div>
I'm setting the ReturnUrl property when OnGet is called (for example "https://localhost:44389/Account/Login?ReturnUrl=%2FSecretPage") But I've also tried to set it manually so the problem is not there.
After I'm pressing Login I get redirected to the login page no matter what is the ReturnUrl given (I can see in chrome the 302 response).
The url after the submit is "https://localhost:44389/Account/Login?Length=14"
What am I doing wrong? I just want to redirect back to the route I was at before redirected to the login page.
RedirectToRouteResult does a redirect to a route where a route is a named route that is configured through the MVC router.
As your example shows, the ReturnUrl that gets passed to your login action is a relative URL though: /Account/Login?ReturnUrl=%2FSecretPage. So ReturnUrl is "/SecretPage".
A relative URL is usually equal to a named route, so using RedirectToRoute will not work here. What you can do instead is return a LocalRedirectResult:
return LocalRedirect(ReturnUrl);

How to use MVC ValidationMessageFor into bootstrap-modal dialog

Hi everybody i've a little trouble to ask... I'm trying to get error message into a login bootstrap modal dilog using ValidationMessageFor, but actually isn't working and i don't know why.
This is my login dilog with Html.BeginForm
<div class="col-xs-2 login-btn">
<a class="btn pfologin" data-toggle="modal" data-target=".bootstrapmodal">
<span> LOGIN</span>
</a>
<!-- Modal dialog -->
<div class="modal fade bootstrapmodal">
<div class="modal-dialog">
#using (Html.BeginForm("Login", "Account"))
{
<div class="modal-content modal-pfo">
<div class="modal-body">
<p>
User:<br />
#Html.TextBoxFor(s => s.Name, new { #class = "form-control" })
#Html.ValidationMessageFor(s => s.Password, "", new { #class = "text-danger" })
</p>
<p>
Password:<br />
#Html.TextBoxFor(s => s.Password, new { #class = "form-control" })
#Html.ValidationMessageFor(s => s.Password, "", new { #class = "text-danger" })
</p>
<p style="display: flex;">
#Html.CheckBoxFor(s => s.Privacy, new { #class = "checkbox" }) Remember me
</p>
</div>
<div class="modal-footer">
<button data-dismiss="modal" class="btn btn-pfo">Cancel</button>
<input type="submit" value="Login" class="btn btn-pfo" />
</div>
</div>
}
</div>
</div>...
this is the model
public class LoginModel
{
[Required(ErrorMessage = "Username requested")]
public string Name { get; set; }
[Required(ErrorMessage = "Password requested")]
[DataType(DataType.Password)]
public string Password { get; set; }
public bool Privacy { get; set; }
}
and this is the controller
[HttpPost]
public async Task<ActionResult> Login(LoginModel loginModel)
{
if (String.IsNullOrEmpty(loginModel.Name))
{
return ModelState.AddModelError("Name", loginModel.Name);
}
if (String.IsNullOrEmpty(loginModel.Password))
{
ModelState.AddModelError("Password", loginModel.Password);
}
if (ModelState.IsValid)
{
}
return RedirectToAction("Index", "Home");
}
yes I redirect from Login/Post to Index but i don't think this is the problem... thank you!
When you return RedirectToAction, you lose all your form data (and, therefore, all validation information). Instead of redirecting to Index, return the View with the model that was passed in.
Second, because both properties are marked as Required, you do not need to explicitly check if they are null or empty. The model is already validated before it hits your [HttpPost] method, based on the attributes you set on the model. If you return the View with this model, your validation messages will appear. This is the most basic implementation, but you can probably get away with:
[HttpPost]
public async Task<ActionResult> Login(LoginModel loginModel)
{
if (ModelState.IsValid)
{
// Do work
return RedirectToAction("Index", "Home");
}
// Else, if not valid, re-render the view with the updated information and display it to the user
return View(loginModel);
}
More info on validation here

How to insert data from text box in database in asp.net mvc

Index.cshtml code for text box
#Html.LabelFor(m => m.ValidFromDate, "ValidFromDate")
#Html.TextBoxFor(m => m.ValidFromDate)
I don't get idea how to insert this text box value to database
Let's assume you have a table names Users in the db. First we will create a POCO which will represent this table as follows:
public class User
{
public string Username { get; set; }
public DateTime ValidFromDate { get; set; }
//more propteries
}
Now let's assume we have a view named Create. In this view you will pass the User class we've created as your model. So your view should look something like this.
#model Models.User
#{
ViewBag.Title = "User";
}
<div>
#using (Html.BeginForm("Create", "User"))
{
#Html.AntiForgeryToken()
#Html.LabelFor(m => m.Username)
#Html.TextBoxFor(m => m.Username)
#Html.LabelFor(m => m.ValidFromDate)
#Html.TextBoxFor(m => m.ValidFromDate)
<button type="submit">Submit</button>
}
</div>
Now you want to get all the values from this view inside your controller action. We will go ahead and create a controller named UserController and inside this controller we will provide GET and POST methods our Create
//This is our GET action for the view
public ActionResult Create()
{
User user = new User();
return View(user); //we pass in the user object to the view
}
[HttpPost]
[ValidateAntiForgeryToken]
//when you click submit this is the action that will get hit
public ActionResult Create(User model)
{
if (!ModelState.IsValid)
return View(model);
string userName = model.Username;
DateTime validFrom = model.ValidFromDate;
//save to db here. I'm not sure if you're making direct calls or using entity framework or similar framework
return RedirectToAction("Index", "Home"); //this will redirect the user to home. You can return a view or redirect user somewhere else.
}
Here we go . I tested this and it returned me the model properties along with files posted .
//-- this is the controller
public class FileUploadDemoController : Controller
{
//
// GET: /FileUploadDemo/
public ActionResult Index()
{
return View();
}
-- here you can name the method as you like to I justuse postform
[HttpPost]
public ActionResult PostForm(FileUploadModel model)
{
Request.Files is the object which contrins all files which you posted from the form when you hit submit buuton after selecting excel file.
if (Request.Files != null && Request.Files.Count > 0)
{
// here you have files attached and model propertied now you can go to db and perform operation which you need to do
}
return View("Index", model);
}
}
-- This is the model which I use to bind the form
namespace WebApplication1.Models
{
public class FileUploadModel
{
public string Name { get; set; }
public string ValidFromDate { get; set; }
}
}
-- Finaly the cshml file . The import point is to use new { enctype = "multipart/form-data" } inside BeginForm .
// the page from where you will post the data . Please change you model class in place of FileUploadModel I created ot for me .
// Please not I didnt not use any datepicket to keep it simple if you enter date like 01-01-2015 this to test .
#model WebApplication1.Models.FileUploadModel
#using (Html.BeginForm("PostForm", "FileUploadDemo", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="panel">
<div class="panel-body">
<div class="form-group row">
<div class="col-md-2 form-label">
<label>Name:</label>
</div>
<div class="col-md-6">
#Html.TextAreaFor(x => x.Name, new { #class = "form-control" })
</div>
</div>
<div class="form-group row">
<div class="col-md-2 form-label">
<label>Date</label>
</div>
<div class="col-md-6">
#Html.TextAreaFor(x => x.ValidFromDate, new { #class = "form-control" })
</div>
</div>
<div class="col-md-10">
<div class="form-group row">
<div class="col-md-2 form-label">
<label>Select File<i class="required-field">*</i>:</label>
</div>
<div class="col-md-8">
<input type="file" class="file-upload" style="margin: 0px;" hidden="hidden" accept=".xlsx" name="file" id="file" />
</div>
</div>
</div>
<div class="form-group row">
<div class="col-md-3 pull-right text-right">
<button class="btn btn-primary" id="process-submission" type="submit"
>Submit</button>
</div>
</div>
</div>
</div>
}

How to incorporate another controller's view and behavior into "this" controller's view?

I have a jQueryUI tabbed html page, and in its content area for one of the tabs, I have put as follows:
<div id="tabs-1ua">
#RenderPage("~/Views/Admin/Create.cshtml")
</div>
The Create.cshtml page does correctly appear within my tab, however when I create the user (this view is a basic user creation page) and click the button, nothing happens. No user is created and no error is presented. The "this" html with the tabs is in a different controller which does not have any model associations. The user creation is inside the AdminController, pertinent methods shown below:
public ActionResult Create()
{
return View();
}
[HttpPost]
public async Task<ActionResult> Create(CreateModel model)
{
if (ModelState.IsValid)
{
AppUser user = new AppUser { UserName = model.Name, Email = model.Email};
IdentityResult result = await UserManager.CreateAsync(user,
model.Password);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
else
{
AddErrorsFromResult(result);
}
}
return View(model);
}
I put a breakpoint at the beginning of the Post method, but it was never hit when I accessed the create page from within my other page.
When I access this page directly and create a user, I get the expected behavior for new creation and validation. The model is as follows:
public class CreateModel
{
[Required]
public string Name { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
}
And the Create.cshtml view is as follows:
#model IdentityDevelopment.Models.CreateModel
#{ ViewBag.Title = "Create User";}
<h2>Create User</h2>
#Html.ValidationSummary(false)
#using (Html.BeginForm())
{
<div class="form-group">
<label>Name</label>
#Html.TextBoxFor(x => x.Name, new { #class = "form-control" })
</div>
<div class="form-group">
<label>Email</label>
#Html.TextBoxFor(x => x.Email, new { #class = "form-control" })
</div>
<div class="form-group">
<label>Password</label>
#Html.PasswordFor(x => x.Password, new { #class = "form-control" })
</div>
<button type="submit" class="btn btn-primary">Create</button>
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn btn-default" })
}
My questions are, is it possible to do what I am trying to do? If so what changes do I need to make in order to reuse the existing available code?
Thank you.
You may explcitly specify which action method the form should post to when submit button is clicked.
You can use this overload of Html.BeginForm method to do so.
public static MvcForm BeginForm(
this HtmlHelper htmlHelper,
string actionName,
string controllerName
)
So update your Create view.
#model IdentityDevelopment.Models.CreateModel
#using (Html.BeginForm("Create","Admin"))
{
#Html.TextBoxFor(x => x.Name, new { #class = "form-control" })
<button type="submit" class="btn btn-primary">Create</button>
}
Now nomatter where you include this view, it will always post to Admin/Create
You should move your create form into a partial view which you can then render with RenderPartial. Then in your parent html page form do an ajax post to the partial views controller that defines the create method. Then you can use your partial anywhere you like with the logic centralized into the partial views controller.

Resources