an ASP.NET, C# technical blog, by Gianni Tropiano

The power of CustomValidator - Validate with WebServices

by CodeGolem 2. May 2009 14:52

Article of the day at ASP.NET (july 8th, 2009)

Many times we need to validate user input with some custom logic that is so hard to implement on the client side with javascript.
There are even times when this is not possible (for example validating username uniqueness against a database).

Still we would like to avoid postbacks and give an interactive feedback to the user.

Now, we will try to use a CustomValidator leveraging WebServices.

Since the ASP.NET validation framework is synchronous, many people tried to implement WebService-based validation using synchronous calls to the server.
But we all know (or should know) synchronous IS BAD, and this is why the whole AJAX framework is implemented asynchronously.

So, how can we stop the postback if we can't have an immediate response from the webservice?

Here is my try.

Let's start from our sample page:


<asp:ScriptManager runat="server">
    <Services>
        <asp:ServiceReference Path="~/CustomValidator/Webservices/WebService.asmx" />
    </Services>
</asp:ScriptManager>
<div>
    <asp:TextBox runat="server" ID="MyTextBox" />
    <asp:CustomValidator
        runat="server"
        ID="MyCustomValidator"
        ControlToValidate="MyTextBox"
        OnServerValidate="MyCustomValidator_ServerValidate"
        ClientValidationFunction="myAjaxValidator"
        ErrorMessage="Invalid entry!" />
    <br />
    <asp:Button runat="server" Text="Submit" />
</div>

Here we have our ScriptManager with a ServiceReference pointing to our validation WebService, a TextBox to be validated, the CustomValidator and a submit button.

Here is our sample validation WebService:


[WebService(Namespace = "//tempuri.org/">http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService {

    [WebMethod]
    public bool Validate(string value) {
        return WebService.StaticValidate(value);
    }

    public static bool StaticValidate(string value)
    {
        return value.ToLower() != "foo";
    }
}

I've moved the validation logic in a static method, so it can be invoked from the server-side validation event too, enabling us to share the same code for client-side and server-side validation.

So, any value will be accepted, but "foo".

Finally, the javascript client validation code:


<script type="text/javascript">
    var originalTarget;
    var originalErrorMessage;
   
    function myAjaxValidator(sender, args) {
        /* invoke validation webservice with a success callback */
        /* no failure callback, and the sender passed in as UserState */
        WebService.Validate($get('<%= MyTextBox.ClientID %>').value, callBack, null, sender);
        /* store the original target of the event */
        originalTarget = $get('__EVENTTARGET').value;
        /* validation is always set to false */
        args.IsValid = false;
        /* store the original errormessage from the CustomValidator */
        if (sender.errormessage != "")
            originalErrorMessage = sender.errormessage;
        /* remove the errormessage, so it is not shown to the user */
        /* until asynchronous WebService call is complete */
        sender.errormessage = sender.innerText = "";
    }
    function callBack(result, sender) {
        var isValid = result;
        // validate all other validators on the page
        for (i = 0; i < Page_Validators.length; i++)
            if (Page_Validators[i] != sender) {
                ValidatorValidate(Page_Validators[i]);
                isValid = isValid && Page_Validators[i].isvalid;
        }
       
        if (result) {
            if (isValid)
                // force postback if all validators report valid data
                __doPostBack(originalTarget, '');
        }
        else {
            // display the original errormessage if the WebService result is false
            sender.errormessage = sender.innerText = originalErrorMessage;
        }
    }
</script>

So, this is what is going to happen:

As the validation event is fired, our custom validation function invokes our WebService, passing in a reference to an asynchronous callback.
The validation is always set to false: postback will be blocked.
Before leaving the function, we store the original target of the event and the original errorMessage of our validator.
Then we clear the errorMessage of the validator, so it will not show to the user.

Finally, the asynchronous callback is invoked by the AJAX framework.
We loop through all the validators on the page and verify they are valid.
If all validators report valid values, and the WebService result is valid too, we force a postback invoking the __doPostBack() function, passing in the originalTarget we stored before.

Eventually, we restore the errorMessage for the CustomValidator if the WebService reports invalid state.

Give it a try. I've tested it with other standard validators on the page, and it seems working fine.Cool

There is only one drawback:
I was not able to get it working when there is a ValidationSummary on the page. Cry

UPDATE: Seems user Nick Cipollina found a solution to have a ValidationSummary on the page!
Read his comment for further details.

Any comments and feedbacks are welcome.

Have fun coding!

Tags: , ,

ASP.NET

Comments


United States sulumits retsambew 
May 16. 2009 06:19
great info, thanks.


United States Nick Cipollina 
June 10. 2009 19:40
I've got the answer to validation summary.  Add the following to the myAjaxValidator function:

if (source.innerText != "")
originalInnerText = source.innerText;

Capture your original innerText, because that is what the validator will actually display.

Then in your callback function if the result is invalid do the following:

sender.errormessage = originalErrorMessage;
sender.innerText = originalInnerText;
ValidatorUpdateIsValid();
ValidatorSummaryOnSubmit(null);

This will update the validation summary on the page (if it exists).  Great post!


India Gokul 
June 13. 2009 16:10
Great post!!

I was not able to get it working when there is a ValidatorCalloutExtender attached with the textbox.

Any Idea ?


United Kingdom dnoxs 
June 25. 2009 20:00
Hi,

I see you use __doPostBack function to force a postback if all the validators are valid.

I have a situation where I need to perfom a callback because my validators are inside an updatepanel.

Any suggestions?


June 25. 2009 20:32
Hello there!
As far as I know, invoking __doPostBack function using a target control that is inside an updatepanel, automatically performs a partial update instead of a full postback.
Is this what you were looking for? Or did I misunderstand your needing?
Bye!


United States naruto wallpaper 
June 28. 2009 16:34
thanks for this useful info


Spain wisata ciamis 
June 28. 2009 21:29
nice article.... i get more information in this site.. thank's friends!!


Indonesia rusli zainal sang visioner 
June 28. 2009 23:48
thanks for sharing, it's really useful information


Indonesia Stop Dreaming Start Action 
June 28. 2009 23:49
many thanks, great post, have a nice day friend


Indonesia confession 
June 30. 2009 16:16
hi nice to meet you. iam a newbie thank's for info regard


Indonesia stop dreaming start action 
July 1. 2009 13:27
nice post. thanks for sharing


United States aces high 
July 2. 2009 07:44
thanks for this useful info


Indonesia cantik 
July 3. 2009 12:21
nice to be here ,thanks for sharing, friend..have a nice day


Denmark Joe 
July 6. 2009 18:11
Nice blog.. really like it..


Australia Satheesh  
July 8. 2009 06:14
Cool Stuff!! Thanks for sharing!!


India shakti 
July 8. 2009 10:03
Web service used in this way leaks information to outside world.When called from AJAX a javascript proxy referencing webservice is downloaded to client and is referred by AJAX client framework. The best approach is to make use of UPdate Panels in Ajax and let custom validators fire server side code asynchronously.


July 8. 2009 10:40
Hi shakti! Thank you for your feedback!
What kind of information could the outside world get from a webservice proxy? :S

UpdatePanel still performs a postback to the server... this is what client-side validation, if enabled, should avoid. In this scenario we have a semi-client-side validation, could be bizarre, but I think invoking a validation webservice could perform better than a postback.

Of course, the client's data should also be validated on the server-side as well!


India shailesh 
July 8. 2009 12:16
Thanks for share such good information about the AJAX and web service. We can save time for use and also our server request.


United States jim 
July 8. 2009 18:44
It is definately possible to validate usernames against a database clientside. I have done it in two production apps. All you need is a little AJAX and javascript. I use a page service and fire it on the blur method of the control. I use a span tag to show the results - and refocus on the control if duped.


Saudi Arabia Agha Usman 
July 8. 2009 22:55
If somebody don't want to use web services. here is the other solution
www.aghausman.net/.../...stom-validation-ajax.html

Here I am validating user name with simple ajax.


India Saransh 
July 9. 2009 11:06
Nice Post.

Small update on Nick's solution for ValidationSummary.

the method to call is

ValidationSummaryOnSubmit(null);  

in place of

ValidatorSummaryOnSubmit(null);


India Thanigainathan 
July 9. 2009 14:13
Hi,

Fantastic article. Cool approach to solve the ajax problems.

Thanks,
Thani


United States PHProxy 
July 12. 2009 19:32
Thanks for this great post - I will be sure to check out your blog more often


United States Raju 
July 14. 2009 22:07
I disagree with the statement that synchronous validation is bad. If you do asynchronous you are setting your self up for failure. The original conditions that you are validating might not exist anymore.
Imagine that I want to validate whether or not a number is greater than 0. If I type in 5 and click submit. You will call the webservice and return control to me. I can then change the number to -1 and then your webservice returns and validates successfully,l calls tha callback function and submits to the server. The value will be -1? What was the point of your validation? Why jump through so many loops to expose another flaw? Synchronous guarantees that the user will not change anything making it easier and more robust than your asynchronous solution.

Raju


July 15. 2009 11:06
Hello Raju.
When I say "synchronous is bad", I mean: waiting for a response from the server may freeze or hang the browser. In addition to this, validating fields asynchronously you may let the user fill other fields in the meantime, or even add functionality to cancel the in-progress validation request.
To avoid user changing values while validation is in progress you may simply disable the submit button (or the validated field) until you received a valid response from the webservice.

Thank you for your feedback!


India web designer 
July 16. 2009 12:18
Thanks u r  information  


U.A.E. download free roulette software 
July 16. 2009 14:25
A simpler approach these days might be to use the ServerSideValidationExtender that's part of the Validation Guidance Bundle... See here: www.pnpguidance.net/.../...artialPagePostBack.aspx


Netherlands Ferdinand 
July 20. 2009 16:19
Hi all,

I was using this code as a test to see if I could use it in an application I'm working on but during debug I discovered that the 'originalTarget' variable allways stays empty. Therefor the line "__doPostback(originalTarget, '');" will perform a postback, but not on the button (so any server site code behind that button won't be executed).

Anyone has an idea of what I'm missing or where my code goes wrong?

TIA!
Ferdinand.


United States SEO 
July 21. 2009 11:35
Where can I get AJAX offline reading sources?


United States sulumits retsambew 
July 22. 2009 12:03
Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon.

Add comment



  Country flag

biuquote
  • Comment
  • Preview
Loading



Recent Posts

Sponsored By

iziCommerce

e-commerce has

never been so izi!

Try our online store!