Evjen c04.tex V2 - 01/28/2008 12:45pm Page 214 Chapter 4: Validation Server Controls Figure 4-7 If you create your own server-side validations, you can make them as complex as your applications require. For instance, using the CustomValidator for server-side validations is something you do if you want to check the user’s input against dynamic values coming from XML files, databases, or elsewhere. For an example of using the CustomValidator control for some custom server-side validation, you can work with the same example as you did when creating the client-side validation. Now, create a server-side check that makes sure a user-input number is divisible by 5. This is illustrated in Listing 4-15. Listing 4-15: Using the CustomValidator control to perform server-side v alidations VB < %@ Page Language="VB" % > < script runat="server" > Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) If Page.IsValid Then Label1.Text = "VALID ENTRY!" End If End Sub Sub ValidateNumber(sender As Object, args As ServerValidateEventArgs) Try Dim num As Integer = Integer.Parse(args.Value) args.IsValid = ((num mod 5) = 0) Catch ex As Exception args.IsValid = False End Try End Sub < /script > < html xmlns="http://www.w3.org/1999/xhtml" > < head runat="server" > < title > CustomValidator < /title > < /head > < body > < form id="form1" runat="server" > 214 Evjen c04.tex V2 - 01/28/2008 12:45pm Page 215 Chapter 4: Validation Server Controls < div > < p > Number: < asp:TextBox ID="TextBox1" Runat="server" >< /asp:TextBox > < asp:CustomValidator ID="CustomValidator1" Runat="server" ControlToValidate="TextBox1" Text="Number must be divisible by 5" OnServerValidate="ValidateNumber" >< /asp:CustomValidator > < /p > < p > < asp:Button ID="Button1" OnClick="Button1_Click" Runat="server" Text="Button" >< /asp:Button > < /p > < p > < asp:Label ID="Label1" Runat="server" >< /asp:Label > < /p > < /div > < /form > < /body > < /html > C# < %@ Page Language="C#" % > < script runat="server" > protected void Button1_Click(Object sender, EventArgs e) { if (Page.IsValid) { Label1.Text = "VALID ENTRY!"; } } void ValidateNumber(object source, ServerValidateEventArgs args) { try { int num = int.Parse(args.Value); args.IsValid = ((num%5) == 0); } catch(Exception ex) { args.IsValid = false; } } < /script > Instead of a client-side JavaScript function in the code, this example includes a server-side function — ValidateNumber. The ValidateNumber function,aswellasallfunctionsthatarebeingconstructedto work with the CustomValidator control, must use the ServerValidateEventArgs object as one of the parameters in order to get the data passed to the function for the validation check. The ValidateNumber function itself is nothing fancy. It simply checks to see if the provided number is divisible by 5. 215 Evjen c04.tex V2 - 01/28/2008 12:45pm Page 216 Chapter 4: Validation Server Controls From within your custom function, which is designed to work with the CustomValidator control, you actually get at the value coming from the form element through the args.Value object. Then you set the args.IsValid property to either True or False depending on your validation checks. From the preceding example, you can see that the args.IsValid is set to False if the number is not divisible by 5 and also that an exception is thrown (which would occur if a string value was input into the form element). After the custom function is established, the next step is to apply it to the CustomValidator control, as shown in the following example: < asp:CustomValidator ID="CustomValidator1" Runat="server" ControlToValidate="TextBox1" Text="Number must be divisible by 5" OnServerValidate="ValidateNumber" >< /asp:CustomValidator > To make the association between a CustomValidator control and a function that you have in your server-side code, you simply use the OnServerValidate attribute. The value assigned to this property is the name of the function — in this case, ValidateNumber . Running this example causes the postback to come back to the server and the validation check (based on the ValidateNumber function) to be performed. From here, the page reloads and the Page_Load event is called. In the example from Listing 4-15, you can see that a check is done to see whether the page is valid. This is done using the Page.IsValid property: If Page.IsValid Then Label1.Text = "VALID ENTRY!" End If Using Client-Side and Server-Side Validation Together As stated earlier in this chapter, you have to think about the security of your forms and to ensure that the data you are collecting from the forms is valid data. For this reason, when you decide to employ client-side validations (as you did in Listing 4-14), you should take steps to also reconstruct the client-side function as a server-side function. When you have done this, you should associate the CustomValidator control to both the client-side and server-side functions. In the case of the number check validation from Listings 4-14 and 4-15, you can use both validation functions in your page and then change the CustomValidator control to point to both of these functions, as shown in Listing 4-16. Listing 4-16: The CustomValidator control with client- and server-side validations < asp:CustomValidator ID="CustomValidator1" Runat="server" ControlToValidate="TextBox1" Text="Number must be divisible by 5" ClientValidationFunction="validateNumber" OnServerValidate="ValidateNumber" >< /asp:CustomValidator > From this example, you can see it is simply a matter of using both the ClientValidationFunction and the OnServerValidate attributes at the same time. The ValidationSummary Server Control The ValidationSummary control is not a control that performs validations on the content input into your Web forms. Instead, this control is the reporting control, which is used by the other validation controls 216 Evjen c04.tex V2 - 01/28/2008 12:45pm Page 217 Chapter 4: Validation Server Controls on a page. You can use this validation control to consolidate error reporting for all the validation errors that occur on a page instead of leaving this up to each and every individual validation control. You might want this capability for larger forms, which have a comprehensive form validation process. If this is the case, you may find it rather user-friendly to have all the possible validation errors reported to the end user in a single and easily identifiable manner. These error messages can be displayed in a list, bulleted list, or paragraph. By default, the ValidationSummary control shows the list of validation errors as a bulleted list. This is illustrated in Listing 4-17. Listing 4-17: A partial page example of the ValidationSummary control < p > First name < asp:TextBox ID="TextBox1" Runat="server" >< /asp:TextBox > < asp:RequiredFieldValidator ID="RequiredFieldValidator1" Runat="server" ErrorMessage="You must enter your first name" ControlToValidate="TextBox1" >< /asp:RequiredFieldValidator > < /p > < p > Last name < asp:TextBox ID="TextBox2" Runat="server" >< /asp:TextBox > < asp:RequiredFieldValidator ID="RequiredFieldValidator2" Runat="server" ErrorMessage="You must enter your last name" ControlToValidate="TextBox2" >< /asp:RequiredFieldValidator > < /p > < p > < asp:Button ID="Button1" OnClick="Button1_Click" Runat="server" Text="Submit" >< /asp:Button > < /p > < p > < asp:ValidationSummary ID="ValidationSummary1" Runat="server" HeaderText="You received the following errors:" > < /asp:ValidationSummary > < /p > < p > < asp:Label ID="Label1" Runat="server" >< /asp:Label > < /p > This example asks the end user for her first and last name. Each text box in the form has an associated RequiredFieldValidator control assigned to it. When the page is built and run, if the user clicks the Submit button with no values placed in either of the text boxes, it causes both validation errors to fire. This result is shown in Figure 4-8. As in earlier examples of validation controls on the form, these validation errors appear next to each of the text boxes. You can see, however, that the ValidationSummary control also displays the validation errors as a bulleted list in red at the location of the control on the Web form. In most cases, you do not want these errors to appear twice on a page for the end user. You can change this behavior by using the Text property of the validation controls, in addition to the ErrorMessage property, as you have typically done throughout this chapter. This approach is shown in Listing 4-18. 217 Evjen c04.tex V2 - 01/28/2008 12:45pm Page 218 Chapter 4: Validation Server Controls Figure 4-8 Listing 4-18: Using the Text property of a validation control < asp:RequiredFieldValidator ID="RequiredFieldValidator1" Runat="server" ErrorMessage="You must enter your first name" Text="*" ControlToValidate="TextBox1" >< /asp:RequiredFieldValidator > or < asp:RequiredFieldValidator ID="RequiredFieldValidator1" Runat="server" ErrorMessage="You must enter your first name" ControlToValidate="TextBox1" > * < /asp:RequiredFieldValidator > Listing 4-18 shows two ways to accomplish the same task. The first is to use the Text property and the second option is to place the provided output between the tags of the < asp:RequiredFieldValidator > elements. Making this type of change to the validation controls produces the results shown in Figure 4-9. To get this result, just remember that the ValidationSummary control uses the validation control’s ErrorMessage property for displaying the validation errors if they occur. The Text property is used by the validation control and is not utilized at all by the ValidationSummary control. In addition to bulleted lists, you can use the DisplayMode property of the ValidationSummary control to change the display of the results to other types of formats. This control has the following possible values: ❑ BulletList ❑ List ❑ SingleParagraph 218 Evjen c04.tex V2 - 01/28/2008 12:45pm Page 219 Chapter 4: Validation Server Controls Figure 4-9 Figure 4-10 219 Evjen c04.tex V2 - 01/28/2008 12:45pm Page 220 Chapter 4: Validation Server Controls You can also utilize a dialog box instead of displaying the results to the Web page. Listing 4-19 shows an example of this behavior. Listing 4-19: Using a dialog box to report validation errors < asp:ValidationSummary ID="ValidationSummary1" Runat="server" ShowMessageBox="True" ShowSummary="False" >< /asp:ValidationSummary > From this code example, you can see that the ShowSummary property is set to False — meaning that the bulleted list of validation errors are not shown on the actual Web page. However, because the ShowMes- sageBox property is set to True , you now get these errors reported in a message box, as illustrated in Figure 4-10. Turning Off Client-Side Validation Because validation server controls provide clients with client-side validations automatically (if the requesting container can properly handle the JavaScript produced), you might, at times, want a way to control this behavior. It is quite possible to turn off the client-side capabilities of these controls so that they don’t independently send client-side capabilities to the requestors. For instance, you might want all validations done on the server, no matter what capabilities the requesting containers offer. You can take a couple of approaches to turning off this functionality. The first is at the control level. Each of the validation server controls has a property called Enable- ClientScript . This property is set to True by default, but setting it to False prevents the control from sending out a JavaScript function for validation on the client. Instead, the validation check is done on the server. The use of this property is shown in Listing 4-20. Listing 4-20: Disabling client-side validations in a validation control < asp:RequiredFieldValidator ID="RequiredFieldValidator1" Runat="server" Text="*" ControlToValidate="TextBox1" EnableClientScript="false" / > You can also remove a validation control’s client-side capability programmatically (shown in Listing 4-21). Listing 4-21: Removing the client-side capabilities programmatically VB Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) RequiredFieldValidator1.EnableClientScript = False End Sub C# protected void Page_Load(Object sender, EventArgs e) { RequiredFieldValidator1.EnableClientScript = false; } 220 Evjen c04.tex V2 - 01/28/2008 12:45pm Page 221 Chapter 4: Validation Server Controls Another option is to turn off the client-side script capabilities for all the validation controls on a page from within the Page_Load event. This can be rather helpful if you want to dynamically decide not to allow client-side validation. This is illustrated in Listing 4-22. Listing 4-22: Disabling all client-side validations from the Page_Load event VB Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) For Each bv As BaseValidator In Page.Validators bv.EnableClientScript = False Next End Sub C# protected void Page_Load(Object sender, EventArgs e) { foreach(BaseValidator bv in Page.Validators) { bv.EnableClientScript = false; } } Looking for each instance of a BaseValidator object in the validators contained on an ASP.NET page, this For Each loop turns off client-side validation capabilities for each and every validation control the page contains. Using Images and Sounds for Error Notifications So far, we have been displaying simple textual messages for the error notifications that come from the validation server controls. In most instances, you are going to do just that — display some simple textual messages to inform end users that they input something into the form that doesn’t pass your validation rules. An interesting tip regarding the validation controls is that you are not limited to just text — you can also use images and sounds for error notifications. To do this, you use the Text property of any of the validation controls. To use an image for the error, you can simply place some appropriate HTML as the value of this property. This is illustrated in Listing 4-23. Listing 4-23: Using images for error notifications < asp:RequiredFieldValidator ID="RequiredFieldValidator1" Runat="server" Text=’ < img src="error.gif" > ’ ControlToValidate="TextBox1" >< /asp:RequiredFieldValidator > As you can see from this example, instead of some text being output to the Web page, the value of the Text property is an HTML string. This bit of HTML is used to display an image. Be sure to notice the use of the single and double quotation marks so you won’t get any errors when the page is generated in the browser. This example produces something similar to what is shown in Figure 4-11. 221 Evjen c04.tex V2 - 01/28/2008 12:45pm Page 222 Chapter 4: Validation Server Controls Figure 4-11 The other interesting twist you can create is to add a sound notification when the end user errs. You can do this the same way you display an image for error notifications. Listing 4-24 shows an example of this. Listing 4-24: Using sound for error notifications < asp:RequiredFieldValidator ID="RequiredFieldValidator1" Runat="server" Text=’ < bgsound src="C: \ Windows \ Media \ tada.wav" > ’ ControlToValidate="TextBox1" EnableClientScript="False" > < /asp:RequiredFieldValidator > You can find a lot of the Windows system sounds in the C: \ Windows \ Media directory. In this example, the Text uses the < bgsound > element to place a sound on the Web form (works only with Internet Explorer). The sound is played only when the end user triggers the validation control. When working with sounds for error notifications, you have to disable the client-side script capability for that particular control because if you do not, the sound plays when the page is loaded in the browser, whether or not a validation error has been triggered. Working with Validation Groups In many instances, developers want to place more than one form on a single page. This was always possible in ASP.NET 1.0/1.1 because different button clicks could be used to perform different server-side events. Some issues related to this type of construction were problematic, however. 222 Evjen c04.tex V2 - 01/28/2008 12:45pm Page 223 Chapter 4: Validation Server Controls One of these issues was the difficulty of having validation controls for each of the forms on the page. Different validation controls were often assigned to two distinct forms on the page. When the end user submitted one form, the validation controls in the other form were fired (because the user was not work- ing with that form), thereby stopping the first form from being submitted. Figure 4-12, for example, shows a basic page for the St. Louis .NET User Group that includes two forms. Figure 4-12 One of the forms is for members of the site to supply their usernames and passwords to log into the Members Only section of the site. The second form on the page is for anyone who wishes to sign up for the user group’s newsletter. Each form has its own button and some validation controls associated with it. The problem arises when someone submits information for one of the forms. For instance, if you were a member of the group, you would supply your username and password, and click the Login button. The validation controls for the newsletter form would fire because no e-mail address was placed in that particular form. If someone interested in getting the newsletter places an e-mail address in the last text box and clicks the Sign-up button, the validation controls in the first form fire because no username and password were input in that form. ASP.NET 3.5 provides you with a ValidationGroup property that enables you to separate the validation controls into separate groups. It enables you to activate only the required validation controls when an 223 . when creating the client-side validation. Now, create a server-side check that makes sure a user-input number is divisible by 5. This is illustrated in Listing 4- 15. Listing 4- 15: Using the CustomValidator. are going to do just that — display some simple textual messages to inform end users that they input something into the form that doesn’t pass your validation rules. An interesting tip regarding. was placed in that particular form. If someone interested in getting the newsletter places an e-mail address in the last text box and clicks the Sign-up button, the validation controls in the first