CHAPTER 7

image

Validating Data

An age-old problem with computer systems is this: garbage in, garbage out. When users enter incomplete or inaccurate data into a computer system, the result of any processing will be of equally poor quality. Luckily, LightSwitch provides a host of features to help keep your data clean. In this chapter, I’ll show you how to do the following:

  • create data-valuation rules by using the table designer
  • define more sophisticated rules by writing code that runs on the server
  • define screen-specific rules by writing code that runs only on the client

In this chapter, I’ll show you how to create conditional rules; for example, if the user enters a close date for an issue, the Closed-by Engineer field becomes mandatory. Also, I’ll show you how to create comparison rules; for example, closed date can’t be earlier than create date. Additional examples in this chapter will include how to refer to related data in your validation procedures, and how to use regular expressions to validate string patterns, such as Social Security numbers.

LightSwitch includes a rich validation framework that enforces validation rules on both the client and server. I’ll explain how this works and show you a technique for use on desktop applications to generate validation warnings. You can use these warnings to encourage users to optionally supply or correct a piece of data when they attempt to save a record. To round off this chapter, I’ll demonstrate a couple of useful techniques you can apply to your applicationhow to enforce unique values for a field in a table and how to apply validation rules prior to the deletion of a record.

Understanding Validation in LightSwitch

You can apply validation and business rules in several places throughout your application. Therefore, it’s useful to understand exactly where these places are.

First, you can specify predefined validation rules through the table designer. As an example, you can use predefined rules to specify the minimum or maximum acceptable values for a numeric field. LightSwitch automatically enforces these rules on all screens in your application and also applies data-type validation. By defining validation rules at the table level, all logic is defined in a single place. If you change the data length of a table field afterward, LightSwitch enforces your new rule without your needing to make changes to every screen in your application, or to any other part of your application.

For more-complex scenarios, you can build validation rules with .NET code. You can attach these custom property validation rules to table rows and fields (i.e., entities and properties).

You can also write validation code at the screen level. This allows you to perform validation that’s specific to a particular screen. Finally, LightSwitch enforces any validation that exists at the storage layer (for example, SQL Server check constraints).

LightSwitch performs the validation on both the client and server tiers. Figure 7-1 illustrates the workflow and shows the types of validation that occur at each tier.

9781484207673_Fig07-01.jpg

Figure 7-1. The types of validation that run on each tier

For HTML client applications, LightSwitch enforces the predefined validation rules on the client. This includes mandatory fields, range (minimum and maximum values), and maximum string-length validation.

The client-side validation that LightSwitch carries out on desktop applications is more sophisticated. On desktop clients, LightSwitch enforces any .NET custom property validation on the client. This enables the screen to show validation errors to the user immediately. For instance, a desktop application can show validation errors as soon as the cursor leaves the text box. In comparison, the built-in custom property validation in HTML client applications requires a round trip to the server.

Users must correct all validation errors before the client calls the server-side save operation. When the server receives the change-set data, it repeats the validation that the client carried out. This behavior improves the security of your application because it prevents users from bypassing your validation logic by communicating with the data service endpoint directly, or by tampering with your client application. An important point you should be aware of is that LightSwitch won’t repeat any custom screen validation if the screen object does not exist on the server. Therefore, LightSwitch won’t revalidate any rules you define on local screen properties. During server-side execution, LightSwitch also applies data service validation. These are custom .NET validation rules that run only on the server.

When LightSwitch completes the server validation, it submits the change to the data-storage layer (i.e., SQL Server for Intrinsic data). If the data doesn’t adhere to the validation rules of the data store, the data store returns an exception to the server. The server then rolls back any data changes that have been applied, and executes the code in the SaveChanges_ExecuteFailed method. This is a method for which you can write .NET code that runs when an error occurs.

In terms of best practices, it’s best to write validation that runs on the server whenever possible. The advantage of server-side validation is that LightSwitch executes the same validation logic for both the desktop and the HTML client applications in your solution. With client-side screen validation, you need to write the same validation procedures on each screen on which you want to apply your validation. Server-side validation is also more secure, because it’s more resistant to tampering by end users. You can never strictly enforce client-side validation, because a user could circumvent your rules by calling the server methods from outside the client application (i.e., through the OData endpoint).

How Client Validation Works in Desktop Clients

For desktop clients, LightSwitch uses an efficient client-side validation engine that caches the results after they are first derived. When the validation runs again, the client is saved from having to rerun all validation rules if just one single rule fails validation. Behind the scenes, LightSwitch uses a system of dependency tracking.

Let’s suppose that you attach a validation rule to a property called EndDate. This rule specifies that the EndDate value must be greater than the StartDate value. When the validation engine first processes this rule, it registers StartDate as a dependency of the validation rule. If the value of either the StartDate or EndDate properties changes, LightSwitch will schedule the validation rule for reevaluation.

The validation engine tracks entities, properties, and most of the properties that the LightSwitch API exposes. Specifically, this includes the members that are exposed via the Details class. The most notable feature of this class is that it enables you to access the change-set object.

Regular .NET properties and your own .NET objects are not tracked by the dependency engine. If you include these in your own custom validation code, the client will only reevaluate your rule when validation takes place.

To prevent validation errors from showing up everywhere when a user creates a new entity, the validation engine does not compute results for unmodified properties. For example, let’s suppose that the surname property for the engineer entity is mandatory. If a user opens a new data screen based on this entity, the screen won’t immediately report the surname value as missing, even though it is. LightSwitch evaluates the rule only when the user modifies the surname value. When the user attempts to save the record, LightSwitch will evaluate all validation rules, irrespective of whether the underlying property has been changed.

How MVVM Applies to Validation

A feature of desktop applications is that if a user enters data that fails validation, LightSwitch summarizes the errors in a validation summary control. It surrounds any offending controls with a red border to highlight the errors to the user (Figure 7-2).

9781484207673_Fig07-02.jpg

Figure 7-2. Validation summary control

These red borders are generated by the Silverlight control. Silverlight controls are bound to content items that are auto-generated by LightSwitch at runtime. These content items expose validation errors to the controls by implementing the INotifyDataErrorInfo interface. So, in keeping with the MVVM principles, the view (Silverlight control) performs only the red highlighting, and the view model (the content item) carries out the actual validation logic.

HTML client applications work in a similar way and also alert users to validation errors through the use of red highlighting. The built-in validation on HTML client screens is not as powerful as the desktop client equivalent. Later in this chapter, I’ll discuss this topic in greater detail and show you ways to improve validation in HTML client applications.

Defining Simple (Predefined) Validation Rules

You can define simple validation rules declaratively through the table designer. Figure 7-3 highlights the validation rules that you can define for a table field through the properties sheet. These simple rules include data range and required field validation.

9781484207673_Fig07-03.jpg

Figure 7-3. Setting validation properties at a field level

This screenshot refers to a field of data type Double. At runtime, LightSwitch automatically prevents users from entering non-numeric data. LightSwitch enforces similar rules for all other data types.

Image Note  LightSwitch creates storage constraints for many of these settings. This allows the database engine to enforce the same validation rules. For example, if you check the “Include in Unique Index” checkbox, LightSwitch creates a unique index in your SQL Server database.

Other property-validation rules you can specify through the property sheet include:

  • Data-Length Validation: You can specify the maximum amount of text that a user can enter for the String data type, and for string-based business types that include Person, Phone Number, Email Address, and Web Address.
  • Range Validation: You can specify minimum and maximum values for numeric and date fields. Specifically, this type of range validation applies to the data types Date, DateTime, DateTimeOffset, Decimal, Double, Money, and Percent, as well as all Integer types.
  • Required Field Validation: You can make a field mandatory by checking the “Is Required” checkbox. When you do this for fields in the Intrinsic database, LightSwitch also creates a NOT NULL constraint on the database column.

Writing Custom Property Validation

Predefined validation works well for simple scenarios. If you need to enforce more-complex rules, you can do so by defining rules with .NET code. You can apply this validation at a property or entity level (as part of the Save pipeline).

Identifying Where Validation Runs

When you attempt to write validation code in Visual Studio, it might not be obvious exactly where that code runs. To help clarify this, Figure 7-4 shows the table and screen designers for a desktop application and highlights where LightSwitch carries out the validation.

9781484207673_Fig07-04.jpg

Figure 7-4. Where validation is performed in relation to the designer

You won’t find any items that are labelled “validate” in the “Write Code” menu in the HTML client screen designer. However, this doesn’t prohibit you from writing client-side JavaScript validation in HTML client applications. You can accomplish this by adding change listeners to the properties you wish to validate, which I’ll show you how to do later in this chapter.

Creating Validation Rules and Warnings

Typically, you use custom validation to enforce rules that a user must correct before saving a record. With desktop applications, LightSwitch provides a second option. You can write code to provide an optional warning rather than to force the user to correct the data. The method for creating both types of validation is similar, so I’ll begin by showing you how to create a validation warning.

Using the Help Desk example, the engineer table includes an optional Email Address field. To encourage users to provide email addresses for engineers, you can create a validation rule to prompt users to supply an email address if it’s been left blank.

To create this rule, open the engineer table and select the EmailAddress property. Next, open the properties sheet and click on the Custom Validation link that appears in the Validation Group (as shown in the lower part of Figure 7-3). This opens the code window and reveals a method stub that contains the commented-out line results.AddPropertyError("<Error-Message>"). Un-commenting this line produces a validation error when LightSwitch validates the email address. So, the key to building custom validation is to build conditional logic around this line of code. To complete this rule, replace your code with the code that’s shown in Listing 7-1.

Now, run your desktop application and try to add an engineer record without an email address. When you attempt to save the record, LightSwitch displays a validation warning that prevents you from saving the record (Figure 7-5). Since this is just a warning, LightSwitch permits you to save the record by clicking on the Save button again.

9781484207673_Fig07-05.jpg

Figure 7-5. Validation warning

An important point to be aware of is that validation warnings work best with the LightSwitch Standard shell. LightSwitch doesn’t show validation warnings on New Data Entry screens in applications that use the Cosmopolitan shell. With the Cosmopolitan shell, LightSwitch opens the newly created record in the Details screen without displaying the validation warning (validation errors, however, work as they should).

Let’s examine the code in Listing 7-1. The first line image tests for an empty or null email address. If the test succeeds, the code raises a validation warning by calling the results object’s AddPropertyResult method image. The first parameter specifies the error that LightSwitch shows to the user.

The results object is of type EntityValidationResultsBuilder, and the methods that you can call are shown in Table 7-1.

Table 7-1. EntityValidationResultsBuilder Methods

Method

Description

AddPropertyError

Generates a validation error against a property

AddPropertyResult

Produces a validation warning against a property

AddEntityError

Generates a validation error against an entity

AddEntityResult

Produces a validation warning against an entity

By using the results object, you can attach errors or results (e.g., warnings) to properties or methods. When you attach an error or a result to a property (with the AddPropertyError or AddPropertyResult methods), LightSwitch prefixes with the error message that it shows to the user with the property name. If you call the AddEntityError or AddEntityResult methods instead, LightSwitch prefixes the error message it shows to the user with the entity name.

When you create validation warnings by calling the AddPropertyResult or AddEntityResult methods, you can specify a severity level. This can either be ValidationSeverity.Error, ValidationSeverity.Informational, or ValidationSeverity.Warning. If you choose the ValidationSeverity.Informational, LightSwitch displays a blue information icon in the validation summary, whereas choosing the warning level produces a red exclamation point icon (these icons may not appear if you choose a non-standard shell). To provide a validation warning, you must provide the severity level as Informational or Warning. If you choose the severity level Error, LightSwitch produces a validation error that the user must correct, rather than a warning.

Image Tip  For desktop clients, screen validation occurs immediately, as soon as a user leaves a text box or control. If you want to perform a task that runs as soon as a user leaves a control, you could add the logic to the property’s validate method. For example, you could write code in the Surname_Validate method that changes the surname characters to uppercase, and this code will run as soon the user leaves the surname text box. But before you apply this technique, please read the section on using INotifyPropertyChanged, which you’ll find in Chapter 9.

Custom Validation Examples

Now that you understand how to raise validation errors in .NET code, here are some actual examples of how to validate input data. This section will show you how to use related data in your validation procedures, how to make a field mandatory based upon some condition, and how to validate string values with regular expressions.

Comparing against Other Properties

You can use custom validation to apply validation rules that depend on the values of other fields in the record. This example prevents users from entering an issue close date that’s earlier than the create date.

To create this rule, open the Issue table in the table designer and select the CloseDateTime property. Open the properties sheet, click the Custom Validation link, and enter the code that’s shown in Listing 7-2.

Figure 7-6 illustrates how this validation rule appears in an HTML client application. This validation error appears when the user triggers the code on the server by clicking the Save button. Desktop applications behave better because the validation warning appears immediately as soon the focus leaves the Closed Date textbox. Because custom property validation runs on both the client and the server in desktop applications, LightSwitch can display the validation error without requiring a round trip to the server.

9781484207673_Fig07-06.jpg

Figure 7-6. Custom server validation

Image Caution  If you want to create a validation rule by using the Write Code button, rather than the Custom Validation link, you must select the property (for example, ClosedDateTime) before clicking the Write Code button. If you don’t, the property’s validation method (ClosedDateTime_Validate) will not appear in the drop-down of available options.

Mandating Data with Conditions

You can very easily make fields mandatory: just select the “Is Required” checkbox for your property in the table designer. However, you might want to make a field mandatory based on some other condition, and to do this, you’ll need to write custom validation code.

Here’s an example that demonstrates this scenario. The Issue table contains a Close Date Time field and a Closed-by Engineer field. If the user enters a close date, the Closed-by Engineer field becomes mandatory. Otherwise, the Closed-by Engineer field can remain optional.

You can see in the previous example that the properties sheet for the CloseDateTime property includes a Custom Validation link that opens the code window and creates a method stub. The properties sheet for the Closed-by Engineer field doesn’t include a Custom Validation link. This is because Closed-by Engineer refers to a related item. It belongs on the many side of a (zero-or-1)-to-many relationship with the Engineer table.

So, to access the code window, you need to select the ClosedByEngineer navigation property in the table designer and click on the Write Code button. When the drop-down appears, you’ll be able to validate the ClosedByEngineer by selecting the ClosedByEngineer_Validate method that appears (Figure 7-7). Now, enter the code that’s shown in Listing 7-3.

9781484207673_Fig07-07.jpg

Figure 7-7. Creating validation on navigation properties

When you now run your application, you’ll find that you can’t enter a closed date without choosing a “closed-by” engineer.

Validating Patterns with Regular Expressions

Regular expressions (regexes) allow you to carry out validation that involves matching string patterns. You can use regexes to validate the formats of Social Security numbers, bank sort codes, postal codes, domain names, and many other pieces of data.

This technique uses the Regex class in the System.Text.RegularExpressions namespace. Listing 7-4 shows the code that validates the format of the Social Security Number field in the Engineers table.

This code illustrates the use of the IsMatch method. This method allows you to pass in an expression, and have a Boolean result returned that indicates whether a match exists.

Image Tip  Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems. (Jamie Zawinski)

As this quote implies, regular expressions can be complex and difficult to understand. To simplify the task of writing expressions, you can visit websites such as http://regexlib.com or http://www.regular-expressions.info to find libraries of pre-built expressions.

Checking against Child Collections

There may be circumstances where you need to refer to child records in a validation routine. To demonstrate such a scenario, this example adds a feature to the Help Desk application. This feature will allow users to store multiple documents against each issue record. From a validation perspective, this example shows you how to enforce a maximum number of child records that are associated with a parent record. Specifically, this example shows you how to prevent users from assigning more than ten documents per issue. In practice, you might want to apply such a technique to help conserve storage space on the server. In addition to referring to child records, this section also illustrates the use of data service validation, as opposed to the custom property navigation that you’ve seen so far.

To create this example, the first step is to create the IssueDocument table, as shown in Figure 7-8. This figure also illustrates the relationship that exists between the Issue and IssueDocument tables.

9781484207673_Fig07-08.jpg

Figure 7-8. Issue Document table

In this example, the Issue table belongs on the (zero-or-1) end of a (zero-or-1)-to-many relationship. For these types of navigation properties, LightSwitch doesn’t allow you to write property-level navigation that runs on both the client and server. The only type of validation you can create in this instance is server-side entity validation.

To build the validation rule, open the Issue table and click on the Write Code button. Select the Issues_Validate method from the General Methods group (Figure 7-9). Now, enter the code shown in Listing 7-5.

9781484207673_Fig07-09.jpg

Figure 7-9. Creating entity validation that runs on the server

The code in Listing 7-5 demonstrates how to call an aggregate function on a child collection. By building data service code that runs only on the server, you can more efficiently perform this type of validation.

If you were to implement this rule through screen or custom property validation, the client would need to retrieve all the issue-document data onto the client to produce the count. And because each document record can be large, performing this type of validation on the server can be very slow.

Validating Data on the Client

The best way to implement validation is to write code that runs on the server. However, there are certain scenarios where client-side validation can produce a better experience for end users. In this section, I’ll show you how to define JavaScript validation rules for HTML client applications and .NET screen validation rules for desktop applications.

HTML Client Validation

The HTML client performs a good job of validating the data that users enter. It automatically carries out data type, data length, and mandatory field validation. When the user clicks the Save button, the screen highlights the fields that have failed validation by both showing a dialog and surrounding the fields in red (Figure 7-10). However, there are two areas where the built-in validation falls short.

9781484207673_Fig07-10.jpg

Figure 7-10. Validation warningfailure to enter required data

First, the need for users to click the Save button to see the validation errors can be irritating. A friendlier approach is to give quicker feedback when a field fails validation by highlighting the field as soon as the focus leaves the control.

Second, a more frustrating issue is that LightSwitch doesn’t provide sufficient error detail when the user fails to select mandatory fields. The first screenshot in Figure 7-11 illustrates the error dialog that LightSwitch shows when a user attempts to create an issue record without selecting the mandatory fields “Assigned Engineer” and “Issue Status.” This dialog shows “Data in the Issue record is invalid.” The message fails to convey exactly why this issue record is invalid. Without any further description, an uninitiated user wouldn’t have a clue as to why this record is invalid. When a user modifies a record and accidently clears the Assigned Engineer field, the default error message that LightSwitch shows is equally cryptic, as illustrated in the second screenshot in Figure 7-11.

9781484207673_Fig07-11.jpg

Figure 7-11. Default error messages are not very friendly

Fortunately, you can address these two problems by building client-side validation. Here’s how to modify the Add Edit Issue screen to provide friendlier information when a user fails to select a mandatory related field. To implement this validation, open the Add Edit Issue screen in the designer. Next, click the Add Code button, select the created method, and add the code that’s shown in Listing 7-6.

The code begins by constructing the rule that the create date must be earlier than the closed date. This code utilizes a method in the HTML client’s API called addChangeListener. This method defines code that executes each time a property value changes. In this case, we want to validate the data whenever a user changes either the create date or closed date values. Therefore, it’s necessary to add change listeners to both the ClosedDate image and CreateDate image properties.

The code that performs the validation follows a common pattern. Let’s look at the rule that mandates the entry of an assigned engineer. The first part of this routine obtains a reference to the screen’s issue property image. Next, it obtains a reference to the content item that you want to validatein this case, the AssignedEngineer property image. The next piece of code checks whether the assigned engineer is undefined. If so, it attaches a validation result to the assigned engineer content item image. If the user selects an assigned engineer, the code clears the validation result image. If the code to clear the result didn’t exist, the Assigned Engineer field would remain in an error condition, even after the user corrected the data. The remaining part of the code carries out similar logic for the Issue Status and Closed Date fields.

When you now run your application and enter invalid data, LightSwitch shows the validation warning as soon as the focus leaves the control, as shown in Figure 7-12. As you can see, this behavior is an improvement, because it provides the user with instantaneous feedback and also indicates the selection fields that are missing.

9781484207673_Fig07-12.jpg

Figure 7-12. Custom client validation warning

Image Tip  Unlike desktop applications, HTML client applications do not indicate the screen fields that are mandatory. You can help your users by setting a different label color for required fields, which I’ll show you how to do in Chapter 8.

Desktop Client Validation

For desktop client applications, one reason to implement client-side validation is to apply validation rules that apply only to a single screen. To give an example, the code in this section shows you how to make the Issue Status field mandatory on the issue detail screen. By validating at a screen level, you could extend the system at a future date to allow end users to raise their own issues, but not allow the users to prioritize their own issues.

To create this example, open the Issue Detail screen and make sure you select the issue property in the screen member list. Click the Write Code button and select the validate method from the Screen Property Methods group, as shown in Figure 7-13. Next, enter the code that’s shown in Listing 7-7.

9781484207673_Fig07-13.jpg

Figure 7-13. Creating screen validation

This code looks very similar to the custom property validation examples, but one difference is that the results object is of type ScreenValidationResultsBuilder image.

As this code demonstrates, you can call the AddPropertyError or AddPropertyMessage methods to attach validation results to the property that you’re validating. In addition to these two methods, you can also call either of the two methods AddScreenError or AddScreenMessage. The purpose of these two methods is to attach validation results to the screen rather than to the property.

Accessing Validation Results in Code

In desktop applications, you can access validation results in code by using the details API. Listing 7-8 illustrates some example syntax you can use in your application.

You can use the Details.Properties object to return only those errors for a specific field (for example, Details.Properties.Firstname).

LightSwitch validates properties only when they are modified, and the IsValidated property indicates whether a property is validated. The HasErrors property indicates whether any validation errors have been found.

The ValidationResults collection contains details about each validation error. When you access ValidationResults, LightSwitch validates all objects that have not already been validated.

Validating Data at the Database

You can create validation rules at the database for external SQL Server data sources. For instance, you can add a SQL Server check constraint to validate your data against a T-SQL expression. If a user attempts to enter data that conflicts with your rule, LightSwitch will return the error to the user.

A practical application of database validation is to enforce unique values for a specified field. This technique can help resolve a limitation in the LightSwitch table designer. You can use the table designer to define a unique field by selecting the “Is Unique” checkbox for any given field. But if you select the “Is Unique” checkbox for more than one field in a table, LightSwitch creates a combination index for the set of fields that you selected. There’s no simple way to enforce uniqueness on two or more fields independently within a table through the graphical designer.

If you were using an attached SQL Server database, you could apply this validation by defining a SQL Server unique constraint. To create a unique constraint, open your table in SQL Server Management Studio. Open the Indexes/Keys dialog box by clicking on the toolbar’s Index button (Figure 7-14).

9781484207673_Fig07-14.jpg

Figure 7-14. Creating a unique index

In the General section of this dialog, choose the column that you want to apply the index on, set the “Is Unique” option to Yes, and select the type Unique Key.

Figure 7-15 illustrates a unique constraint on the SSN column in the engineer table. If you attempt to enter a duplicate SSN, LightSwitch displays the database constraint error in the summary panel, as shown in Figure 7-17. Notice that the error message includes a heading that indicates that the error comes from the server. If the server returns any other errors, those errors would also be grouped into the same block.

9781484207673_Fig07-15.jpg

Figure 7-15. Unique constraint violation error

Because the Intrinsic database is also a SQL Server database, you can define database validation on your Intrinsic data source once you deploy your application.

Walkthrough 7-1. Enforcing Data Rules

To end this chapter, this section will cover some practical techniques you can use in your applications. In the first walkthrough, I’ll show you how to enforce unique property values, and in the second walkthrough, I’ll show you how to apply validation rules prior to a user deleting a record.

Enforcing Uniqueness and Preventing Duplicates

The previous section on database validation showed you how to enforce uniqueness by applying database constraints. Although this approach is simple to implement, it isn’t always feasible, particularly if your data source isn’t a database, or if you don’t have permission to make schema changes to the data source.

In this walkthrough, I’ll show you how to apply validation rule to the Security Clearance Reference Number field in the Engineer table. This rule ensures that for each row in this table, the security clearance reference value must be unique.

To create this validation rule, open the Engineer table in the table designer and select the ClearanceReference property. From the properties sheet, click on the Custom Validation link and enter the code that’s shown in Listing 7-9.

This code may seem more complex than you would first expect. This is because you need to check for duplicates on the client (for desktop clients, the user might enter several new engineers in a data grid) in addition to duplicates on the server.

First, the code checks that no server records match the clearance reference number that’s been entered by the user image. It uses a where clause that excludes the ID of the current record. Without this, the query would return a match for the identical record on the server.

Next, it checks for duplicate clearance reference numbers that have been entered by the user on the client image. It then performs a query that returns any deleted records image.

If duplicate records are found on the server or client but are also marked as deleted, the clearance number passes validation. If not, the code raises a property error to prevent the user from saving the record image. Figure 7-16 shows the error that a user would see in an HTML client application.

9781484207673_Fig07-16.jpg

Figure 7-16. Duplicate error

Validating Deletions on the Server

There may be situations in which you need to apply validation rules prior to a user deleting a record. However, applying validation rules during the deletion process can be very complex. This complexity arises because LightSwitch doesn’t apply validation rules on deleted entities during the Save pipeline process. If it did, your users would be forced to fill in all mandatory fields, just to delete a record.

In this walkthrough, we’ll add a feature to the Help Desk application to demonstrate a technique you can use to run validation code whenever a user deletes a record. This feature will enable engineers to maintain a history of the responses to each issue. These responses will be stored in table called IssuesReponse, and Figure 7-17 shows the schema of this table. This table includes a field called AwaitingClient. An engineer would set this field to true if the response required some feedback from the user who raised the issue.

9781484207673_Fig07-17.jpg

Figure 7-17. IssueResponse table schema

This walkthrough shows you how to prohibit issues from being deleted if there are responses that are awaiting the client. This process consists of at least two parts:

  1. Carry out the validation check in the entity set’s Validate method.
  2. If errors are found, raise an exception in the entity set’s Deleting method.
  3. On the client, undelete the records that have failed validation (optional step).

Listing 7-10 shows the server code that you would write against the Issue entity to carry out this validation.

Here’s how the code in this listing works. The server-side Validate method checks whether the issue record is deleted image. If this condition is true, the code queries the IssueResponses navigation property to find any related issue-response records that are marked as AwaitingClient image. If one or more records exist, the code calls the AddEntityError method to record the fact that the entity has failed validation image.

Because LightSwitch ignores validation errors on deleted entities, code execution continues into the pre-process entities phase of the Save pipeline. Here, the Save pipeline executes the code in the Deleting method and raises an exception if the AddEntityError method was called in the Validate method image. By raising an exception here, the Save pipeline aborts the transaction and executes the SaveChanges_ExecuteFailed method. This prevents the record from being deleted.

An important point is that if you want to perform validation against child records during a delete operation, you need to turn off the Cascade Delete option on the relationship (that is, set it to Restricted). If not, the Save pipeline deletes any related child records prior to calling the validate method, and you won’t be able to access any issue-response records in the validate method of your issue entity.

Because of this, the code manually carries out the cascade delete behavior by deleting the child records in the deleting method image.

You can now run your application. Figure 7-18 shows the error that appears in an Editable Grid screen when you attempt to delete a record that doesn’t adhere to the validation rule.

9781484207673_Fig07-18.jpg

Figure 7-18. Error when deleting a record

Although the server correctly enforces the rule, one piece of untidiness remains. Following the validation error, the record remains deleted on the client. Because the client thinks the record is deleted, the record remains greyed out, and this prevents the user from correcting the validation error. The way to resolve this problem is to undelete the record on the client when a deletion error occurs.

Listing 7-11 shows the .NET code you would add to an Editable Grid screen to undelete a record if an error occurred. You would add this code to the SaveError method of a screen.

Unlike desktop client applications, the screens you create through the screen templates in HTML client applications do not include the ability for users to delete records. Therefore, this listing includes the code you would add to a custom delete button on an Add Edit Issue screen. This listing includes the code that deletes the current record, as well as the code to undelete the record in the event of a failure.

In desktop applications, users can delete multiple records, particularly on screens that contain data grids. The code in this listing takes account of this. In the SaveError method of a screen, you can access the records that have failed validation. The code loops through the error records and discards the changes on any deleted records.

In the HTML client example, the code behind the button calls the deleteEntity method on the local issue property to delete the issue. Immediately afterward, the code calls the data service’s saveChanges method to commit the change (note that this also saves all other data changes that the user may have made). If the save operation succeeds, the code navigates the user back to the calling page. Otherwise, the code displays the error message and discards the change to the local screen property.

Summary

LightSwitch provides several ways to validate data. The options that are available to you include predefined, custom property, data service, screen, and data store (database validation).

The simplest way to validate data is to specify predefined rules through the table designer. By using predefined rules, you can define mandatory fields, set maximum field lengths, and set minimum and maximum values for numeric data fields. LightSwitch applies predefined validation on all screens in your application. If you later modify a predefined rule on a table (for example, if you increase the length of a text field), your application applies the new rule without your needing to modify individual screens, or any other part of your application. LightSwitch carries out predefined validation on the client and revalidates the data on the server when a user initiates a save operation.

For more-complex scenarios, you can apply custom property validation by writing .NET code. You can use this type of validation to apply rules on properties (i.e., table fields). On desktop applications, LightSwitch executes this type of validation on the client and revalidates the data on the server during the save operation. HTML client applications are unable to perform custom property validation on the client because the language of the HTML client is JavaScript, not .NET. For HTML client applications, LightSwitch can only perform custom property validation on the server when the user saves the record. The downside to this is that users only see validation errors when they click the Save button. Unlike desktop applications, error notifications can appear as soon as the focus leaves a control.

LightSwitch executes data service validation on the server. This type of validation enables you to apply rules on tables and is useful if you need to create rules that refer to navigation properties. In this chapter, I showed you how to use data service validation to limit the number of child records that are associated with a parent record.

To define custom property or data service validation, you select the property or table in the designer and use the Write Code button to select the validate method. This opens the code window, and you can write conditional code to raise an error by calling the AddPropertyError or AddEntityError methods. Both methods require you to supply the error message that LightSwitch displays to the user. If you call the AddPropertyMessage or AddEntityMessage methods instead, LightSwitch shows a validation warning and allows the user to save their changes (without making corrections) once they acknowledge the warning.

LightSwitch applies custom property and data service validation rules globally throughout your application. If you want to define non-global rules to support a specific scenario, you can accomplish this by writing screen code that runs on the client. In the case of HTML client applications, you can use screen validation to display an alert if a user fails to select a mandatory field from a picker control. In this scenario, the predefined validation error doesn’t include the field name, which makes it difficult for the user to identify the exact cause of the validation failure.

In HTML client applications, writing code to raise a validation error involves two parts. The first part is to call the addChangeListener method on the local screen property to define code that LightSwitch executes whenever the value of a property changes. The second is to write the conditional logic that determines a validation failure, and to raise an error by attaching a new ValidationResult object to the content item.

LightSwitch also applies any rules that you define on the underlying database. For example, you can use SQL Server constraints to define the unique fields on table.

This chapter includes various code samples that you can reuse in your application. This includes code that prevents duplicate records, code to compare values against other properties, and code that uses regular expressions to ensure that input data matches a specific format.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset