Event hooks for MVC unobtrusive remote validation - asp.net-mvc

Is there a way to hook into MVC3 unobtrusive remote validation on the client, before data is submitted to the remote method, and after a result is returned from the remote method?
I am trying to tell a remote validator to only perform validation if the submit button is clicked. The normal behavior is to validate several times, such as during keypress, blur etc. This is no good, as the validation method in question needs to call a non-idempotent operation. I need to make sure that method is only invoked if the user has clicked the submit button.
If I could hook into a before event, I could set a field in the form that flags the submit button as being clicked or not. However I would need to reset this flag after the remote method returns a validation result.
Any other suggestions? This is for validating a password using the ASP.NET Membership Provider's Membership.ValidateUser(string username, string password) method. This method will increment the FailedPasswordAttemtCount each time an invalid password is sent, so I don't want it to execute during blur, keypress, etc.

You could override the default validation options for the current page:
$.validator.setDefaults({
onkeyup: false,
onfocusout: false,
onsubmit: true
});

The solution above didn't resolve this for me. Somehow, the validator setting was not being set. So, I implemented the following and it worked:
$(function () {
var settings = $.data($('form')[0], 'validator').settings;
settings.onkeyup = false;
});

Related

Force a user to re-enter credentials before submit

Using MVC5, i have an application which a user must be logged into, and then can perform standard actions on some data (create, edit, delete).
I would like to add a credentials prompt, whenever a certain task if performed. So say for example a user is editing a row of data. I want them to be prompted to enter their login credentials again when they hit the Save button, before the row is updated. To be clear, they are ALREADY logged in, i just want to force them to re-confirm their credentials before being allowed to save.
How can i do this in the controller? I want a seperate screen/popup to show, asking for username and password (which will then be checked to ensure correct user credentials) before allowing update of the data.
I looked at creating a new method in the controller, which is passed a username and password, which looks after checking the users credentials again. But how do I go about calling this from the Edit screen, when I also need a popup to appear? Do i go down the route of adding a hidden div on the Edit view, which shows when the user clicks the Save button, and it then calls the method?
Generally, you're expected to attempt a solution, first. Then, if you run into specific issues, you can ask a question about those specific issues. I will tell you that this should be relatively straight-forward. All you need is for the user to re-enter their password. Just add a password input to your edit form and bind it to something on your view model, or you can simply bind it directly to an action parameter, in addition to your view model:
[HttpPost]
public ActionResult MyAction(MyViewModel model, string password)
If you want it to be done in a popup, simply include the popup HTML within the form (so the that the input in the popup will be part of the form) or you'll need to use JavaScript to set another input within the form, which would be bound to either a view model property or action param. Either way, the point is that the password should be posted along with the rest of the form data.
Once inside your post action, you can verify the password by manually:
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
var verifyPassword = UserManager.PasswordHasher.VerifyHashedPassword(user.PasswordHash, password);
if (verifyPassword == PasswordVerificationResult.Failed)
{
ModelState.AddModelError("", "Password incorrect.");
// If password is incorrect, ModelState will be invalid now
}
if (ModelState.IsValid)
{
// save posted data
}
It sounds like you'd ideally want an action which you can call asynchronously from the client. While this can take the form of a standard MVC controller action, you may want to consider building this into a Web API controller (Generally we would use Web API controllers to serve up non-HTML responses). You can read more about Web API in many places on the web so I won't go into that now, but let's say you have a HttpResponseMessage result method which looks like this:
[HttpPost]
public HttpResponseMessage CheckCredentials(string username, string password)
{
// Check user credentials and return either one of the following results:
// If credentials valid
return Request.CreateResponse(HttpStatusCode.OK);
// If not valid
return Request.CreateErrorResponse(HttpStatusCode.BadRequest);
}
Using this pattern you could return a '200 OK' response for valid credentials and a '400 Bad Request' for invalid credentials.
As you already stated, you could have the HTML content required for authentication prompt hidden on the page. When the user performs an action which requires authentication, you could render the popup. When the user submits the popup you could fire off an asynchronous request to the Web API endpoint which you created earlier. Depending on the response you get back, you either proceed with the task or prompt for credentials again with an error message.
Obviously as you'd be sending user credentials over a we request, make sure you're making use of HTTPS.
EDIT:
As Chris mentioned below, this solution leaves your 'quick check' in the hands of the client. While this is fine when you simply want to provide a way to stop the user from easily carrying out an action without re-entering their credentials, you should not rely entirely on it.
You could store the username and password as hidden fields and include them with your main synchronous POST. This would allow you to check that the user entered valid credentials from the server.

unobtrusive validation with custom validator that requires ajax post

I'm using ASP.NET MVC with unobtrusive validation. I need to add a new custom validation attribute with client-side validation, which is fine (I've already got some of those defined). The problem is that in the client side validation, I need to make an ajax call to check if the input is valid.
In MVC, you add client-side validators with addMethod:
jQuery.validator.addMethod("customValidation", function(){...})
But the function you define needs to return a boolean, and doing an ajax post is aysnc, which breaks that.
According to jQuery validator and a custom rule that uses AJAX there are 2 options - either use async:false in the ajax call or add a remote to the validate method. BUT, async:false is depcrated and I can't use remote because I'm using unobtrusive validation.
Has anyone got any better solutions to this?
Data annotations contain a Remote attribute that plugs into jquery remote validation automatically.
https://msdn.microsoft.com/en-us/library/system.web.mvc.remoteattribute(v=vs.98).aspx

Unobtrusive Validation messages don't work on inputs without name attribute

Our credit card processor (Braintree Payments) requires that we not use the "name" attribute on credit card fields (card number, expiration date, and CCV) to obviously make sure they don't get POSTed to the server unencrypted. I found a custom Extension to generate a name-less text box (How to extend html.textboxfor to remove the name attribute?). This works great, since it allows us to generate a text box without the name attribute, but it still adds all the other validation attributes and such automatically. But I have run into a problem.
When I use #Html.NameLessTextBoxFor(model => model.CardNumber) in my view, it correctly generates the text box without a name attribute. We also use Data Annotations in the View Model to generate unobtrusive validation. The visible problem on the actual website is that when there is a validation error with one of these name-less fields, the ValidationMessage span doesn't display any error messages. The name-less field correctly turns red, but the error messages don't display.
I believe I have deduced why this isn't working, but I can't figure out how to fix it. I looked at the generated HTML for the ValidationMessage span, and I see this attribute:
data-valmsg-for="MyViewModel.CardNumber"
That would be correct if my name-less field had the name attribute set like normal. But since I can't set the name attribute, how do I get the ValidationMessage to still work?
Scrub the name attrributes on submit would be something like:
$("form").submit(function () {
$(this.find(":input").removeAttr("name");
});
It's possible that this may be too late in the chain of events though, so you may have to preventDefault and repost the form, something like this:
$("form").submit(function (e) {
if($(this.find(":input[name]").length > 0) {
e.preventDefault();
$(this.find(":input").removeAttr("name");
$(this).trigger("submit");
}
});
Or indeed do as I did and code a callBack into unobtrusive validation to check if validation has passed and at that point remove the name attributes. Here are my notes on adding that callBack:
//Added the following to the onErrors function:
if ($.isFunction(callBackOnError)) {
setTimeout(function () {
callBackOnError();
}, 100);
}
//Then in the exposing declarative section of the plugin
onError: function (callBack) {
callBackOnError = callBack;
}
Have a play with it and see what you find. Keen to know your eventual conclusion, so please do update. Hope this has somewhat helped you.

jquery post submit prevent validation [duplicate]

I have a form that allows the user to edit my model. They can save the data, as well as publish it. When the user hits save I want to go ahead and save the form even if its doesnt pass validation so that can come back and finish filling it out later. But if they blur out of a field and its required I still want it to turn red and show the error message. So basically I want normal client side validation without it preventing the form from posting.
Is there a way to do that?
simply override the form submit and that should disable the validation.
$(function () {
$("form").submit(function () {
if (!$(this).valid()) {
//form is not valid
return true;
}
});
});
You dont need the check there obviously and can just return true, thats just to show you how to check if its valid.

clearing ajax.beginform but what if server side doesn't want the form to be cleared?

I have something like this:
I am using Ajax.BeginForm and its updatetargetid is a div which basically informs user whether it was successfully submitted or not and the problem, if any.
My controller function that is handling the form submission checks if there were any errors like duplicate entries and such and does re-checking of client-side rules and returns Content(....) accordingly.
This is what I'm using to clear form afterwards, but as you can see that the form would still get cleared even when my controller function has detected some problem that client-side didn't. I set AjaxOptions OnComplete = "onComplete".
function onComplete() {
if ($("#myForm").validate().form()) {
$("#myForm").clearForm();
}
}
Use function onComplete(ajaxContext){ } instead of function onComplete() {}
From the server end, if there are model validation errors, it usually means the validation summary (if supported) contains some error messages. Using ajaxContext, you can read the the response that is returned as part of ajax call and check the values of validation summary element.
Other option is to design a strategy between your controller and view - e.g. specify an error indicator as part of your response header and use this to decide whether to clear your form or not in OnComplete handler.
so then whats the problem? You simply dont call the onComplete function when there is a server side error. But instead display an error message to let the user know that nothing will happen as there was a server side error. And this way the form will not get cleared.
If everything does work on the server side, then only then will you call the onComplete function.
PK

Resources