MVC: Client Validation Fails, but data is still posted - asp.net-mvc-2

As above, I'm implemented the client side validation no problem, and it pops up the relevant messages as required. However, the submit button still appears to submit the form even though the form is not in a valid state.
The controller method throws it out immediately, because ModelState is not valid, but is there a flag/property I can check client side to prevent the post from happening at all?
UPDATE:
The problem appears to be because the form is submitted asynchronously using a jquery post, hence my javascript method is posting the data regardless of the validation state. So what I'm looking for is, before I do that post, to do something along the lines of if( [Property/Method which indicates MVC Model State] == false ) return false;, however, I'm struggling to find such a method or property.
I've considered implementing a check function which identifies whether the 'input-validation-error' class is applied to any of my form fields. With JQuery, it's pretty simple, but it doesn't sit to well with me. Does anyone have any opinions on doing this?
On the one hand, it seems a bit of a hack because I'm effectively iterating through the form after it's been validated to see if it's actually valid. On the other hand, I'm not sure how the MVC JS would identify the modelstate if there were multiple forms on the same page, whereas if I was to do it myself, I could identify 'for the post of this form, I'm interested in these fields'.

Related

Play Framework: Don't change URL after form validation failed

In a plain Play application I have the following scenario.
A route file which looks like this:
GET /accounts/add controllers.Accounts.add()
POST /accounts controllers.Accounts.create()
The first route results in a view where I can add a new account. The form to submit the new account looks something like this:
#helper.form(action = routes.Accounts.create()) {...}
Now the controller binds the input to the form and checks for any validation errors:
public static Result create() {
Form<Account> form = Form.form(Account.class).bindFromRequest();
if (form.hasErrors()) {
return badRequest(views.html.account.add.render(form));
}
...
}
Now the thing is, the client will see the same view with some additional error messages. However, meanwhile the URL has changed from http://example.com/accounts/add to http://example.com/accounts.
If the client now reloads the browser this calls GET http://example.com/accounts (which isn't even mapped in this scenario - thus getting a 404 - Not Found).
Maybe it's just me but I find this kind of annoying and browsing some GitHub projects I couldn't find a good solution for this case.
Of cause things would be much simpler if the second route is rewritten to:
POST /accounts/add controllers.Accounts.create()
... in which case everything works fine. But from a REST point of view this doesn't feel good either. The same applies to update scenarios (having GET /accounts/:id/update vs. PUT /accounts/:id).
Is there a guide on how to handle this? Am I getting something wrong or is this no problem at all (from a pragmatic point of view)?
It's not possible to leave the previous URL because a request for a new address has already been made. A controller only provides response for a requested resource. To go to the previous URL you could only make a redirect in case of validation failure but you would lost errors that way so this is not a solution.
I suggest mapping both actions with the same URL. This way you would solve problem with the browser reload.
If you create a REST service for http clients that aren't browsers you will probably want to serve different response than a simple http page. The separation of actions for particular clients could be a good solution for keeping REST API clean and a browser user happy.

Grails: calling an action that uses withForm

I have a situation in which I need to reuse an action that has its functionality wrapped in a withForm closure.
Everything works well when submitting the form but when I try to reuse that action in another way I get redirect errors from my browser. Specifically, I need to redirect another action to it, possibly call it with chain, and I also want to call it from a hyperlink.
I'd really like to avoid creating a redundant action or having the invalidToken closure execute the same code. I've tried to find some more details about how withForm works and find out what happens if no token is passed to the closure but the Googles have let me down.
Is this possible? Am I trying to make it do something it can't?
More info:
I have a user edit controller action. It is wrapped with the withForm closure. There are three different cases in which I need to call this controller to render the user edit page:
An admin enters the user's id into an input and clicks the form
submit button (this form uses useToken). This needs to be secured
and protected from duplicate form submission.
An admin selects a user to edit from a list of employees by clicking
on the user's name (a hyperlink). Its possible I could turn this into a form submission with useToken and do some CSS styling to make it look like a link.
An admin creates a new user. When the user is successfully created
the create controller redirects (or uses chain) to the edit
controller. I can't find a work around for this, except to create a redundant controller.
If your code is used in more than one place a controller action isn't the best place to put it. I suggest you to move that piece of code to a service and call it from both actions.
Here is my solution. If anyone has some insight into other methods of solving this please contribute. I'm sure I'm not the only one that has had this problem.
The answer is due, in large part to #Sergio's response. It was far more simple than what I was thinking it would be. I created my edit action without withFormthen call it from another action that wraps the edit action in the withForm.
def editWT(Long uid, Long pid){
withForm{
edit(uid, pid)
}
}
def edit(Long uid, Long pid){
// Do lots of stuff to prep the data for rendering the view
}
This answer isn't innovative or ground-breaking but it works. I hope this helps someone else.

Google Chrome Inspect Element Issue With Hidden ID's

I am not 100% sure if this is as big an issue has I seem to think it is right now but I think I may of found an issue or at else an hole within the Inspect Element viewer within Chrome.
I was using (I have now changed my settings) hidden ID's to set a number of defaults, one was users levels, another was to make the user active by default.
However when I view these ID's within the inspect Element view and then changed the values, submitting the form would submit the NEW value to the server and not the value I had given it.
For Example:
I had something like the following within my code,
<input type="hidden" name="data[user][level][id]" value="1" id="MyID">
I then changed it within the Inspect view to,
<input type="hidden" name="data[user][level][id]" value="2" id="MyID">
Then I submitted the form and was surprised that the NEW value was submitted, I was always under the inpresion that hidden ID's where not changeable and the browser should only submit the default values held within.
I have now changed this to letting the database default to a basic user and then I can change the users setting has I want to. But in some cases this may not be an option, so I was hoping for an answer or some feedback about how to make this more safe.
Am I just a bit slow, are there better methods (different ones) to passing 'hidden' data from forms to the server?
I was thinking about maybe using JQuery to add the needed hidden fields to the forms once the user had selected / submitted the form, but i am not sure if this is 100% safe or even if its a good idea.
Any ideas / feedback are very welcome.....
Many Thanks,
Glenn.
I had the same problem passing the database data into a modal,the solution i know is to use jquery ajax to get the informations from the database requesting a file,adding them into variables and compare the variables
$.ajax({
url: "test.html",
context: document.body
}).done(function() {
$(this).addClass("done");
});
I used this code sample to do it.
Of course there are a few modifications to be done depending on your script
I found a better way of doing this, at lest in CakePHP. The CakePHP framework has inbuilt security calls. These in-built functions when added give you all sorts of stuff but the main reason I used them was to stop this sort of form tampering.
I am not 100% sure how it does this, but it adds a token to all forms and it checks to see if the form being submitted is right? Again not sure how the token works.
But here is the code I used ::
public function beforeFilter() {
$this->Auth->allow('index', 'SystemAccess');
$this->Security->blackHoleCallback = 'blackhole';
}
public function blackhole($type) {
$this->Auth->logout();
$this->Session->setFlash('Sorry a security issue has been detected, please try again or contact us for support.', 'default', array(), 'bad');
$this->redirect($this->Auth->redirect('/'));
}
Now I will add that the call the Auth logout I added to this for extra added security, as the user maybe have logged in on a system and it just not be them that is trying to do things that they should not.
Hope that helps others out!
But this is only a fix for when CakePHP is in use. I would take it that other frameworks would have their options but if your only using basic HTML? or a CMS like Drupal again there might be in built security.
Many Thanks
Glenn.
The only safe and best solution that I found for this issue is to check on the server side whether the user_id sent with the form is the same user_id logged in with or not.
Although using jquery is good idea, but, did not work with my case as am using data: $(this).serialize(),
However here's my code on the server side (Note, am using Laravel 5.4, but am sure it won't matter with your case)
if ($request->user_id != Auth::user()->id)
return json_encode("F**K YOU ! Don't Play Smart -_- !");
else
raw_material_category::create($request->all());
Hope this helped ;)

Classic ASP form doesn't post on page refresh

I have an ASP page that takes two arguments on the querystring. On the page is a form that posts back to itself.
If I do the form post once, and then try to refresh the page, it doesn't repost the form. It loads the page as though it were loading for the first time, missing the querystring values.
Is there a way to ALWAYS force a repost when I refresh a page that is the result of a FORM post?
It sounds like the problem you're having is loss of some essential parameters to your page when posting. In ASP there are two primary methods of passing parameters, in the url string via GET or from a form POST. The former passes you values in the QueryString dictionary while the latter gives them to you in the Form dictionary. Fortunately for you it is possible to accept a parameter that exists in EITHER dictionary by looking to Request object:
Request["a"] will find a regardless of being in Request.QueryString["a"] or Request.Form["a"].
This will help you in your current dilemma because you can simply write your querystring parameters to your Form on initial load of the page as <input type="hidden" fields. On subsequent posts your Request["a"] search for your parameters will find them regardless of being passed in the URL (on initial load) or via post on subsequent calls.
The problem was that I was going into the Firefox address bar and pressing Enter. This caused the URL to reload (and of course it didn't have the querystring after it reposted). So -- lesson is to do a check of the incoming vars and form vars to see if the page has been manually refreshed I suppose...
You could still maintain the submitted values in this situation.
What you would need to do is log the most recent request in either a Cookie, Session or data/file store, and on each request, check to see if the request was handled before you remove the data.
Since what you were after was the querystring it could just be something like this:
Response.Cookies("tempdata")("querystring") = Request.ServerVariables("QUERY_STRING")
Response.Cookies("tempdata")("querystring_handled") = false
then when you are done with that request you can clear the cookie value or set the querystring_handled = true.
There are probably situations where this could cause some conflicts, but just so you know, it is still going to be possible for you to remember the request once it is received by the server.
Which action does the form use: GET or POST? Normally, a form would use the POST action, but in this case, if you refresh the page with the posted form, you will not get anything in query string, because query string only gets passed via the GET action. Assuming that this issue is not caused by page caching, it seems to me like it works as designed (if the form POSTs data). Just make sure that you process the form variables if the query string is missing.

MVC 2.0 Post Form to action instead of redirect to action

I am using T4MVC to redirect to another action return RedirectToAction(MVC.MyController.MyAction());.
In result it is doing get request.
Is there any way to make post request from controller. I want to keep all the same but only make post instead get. I cant find any methods for that. I found one post helper here http://geekswithblogs.net/rakker/archive/2006/04/21/76044.aspx but i cant pass any values i need using this post helper. I was trying to pass values through TempData but they are not coming when i using this helper. May be some one have any ideas?
The reason i want to do this because when user come from one controller to another and then if user click update or just click enter in browser address bar, page will break.
Should i use session for that reason?
A RedirectToAction will always perform a GET, never a POST (it returns a HTTP 302 to the browser, which will then issue a GET request).
To persist data across the redirect, if it is data that can be easily represented as a string and stored in the query string, then you can just add it to the route values of the redirect.
e.g.
return RedirectToAction("Search", new { searchString = "whatever" });
If it is a complex type, then you will need to store it in TempData. A number of other questions on StackOverflow (such as this one) give details on how.
If repeatedly storing to and reading from TempData across your application offends your code-sense, then you can encapsulate this by using the PassParametersDuringRedirect attribute and generic RedirectToAction available in the MvcContrib project. Some details on this technique are available here.
only way of doing post is by having a form and doing submit on that form, either with a submit button or with javascript, any info you want passed to that action must be in that form and you will find everything posted in FormCollection(hope I spelled it right).