Exercise 2: Data Validation

In this exercise, you will learn about the new data validation features in ASP.NET 4.5. You will check out the new unobtrusive validation features in Web Forms. You will use data annotations in the application model classes for user input validation, and finally, you will learn how to turn on or off request validation to individual controls in a page.

Task 1 – Unobtrusive Validation

Forms with complex data including validators tend to generate too much JavaScript code in the page, which can represent about 60% of the code. With unobtrusive validation enabled, your HTML code will look cleaner and tidier.

In this section, you will enable unobtrusive validation in ASP.NET to compare the HTML code generated by both configurations.

  1. Open Visual Studio 11 and open the WebFormsLab-Ex2-Begin.sln solution located in the Source\Ex2-Validation\Begin folder of this lab. Alternatively, you can continue working on your existing solution from the previous exercise.
  2. Press F5 to start the web application. Go to the Customers page and click the Add a New Customer link.
  3. Right-click on the browser page, and select View Source option to open the HTML code generated by the application.

    Figure 9

    Showing the page HTML code

  4. Scroll through the page source code and notice that ASP.NET has injected JavaScript code in the page to perform the validations and show the error list.

    Figure 10

    Validation JavaScript code in CustomerDetails page

  5. Press F12 to open the developer tools.
  6. Select the Script tab and expand the “CustomerDetails.aspx” combo to see all the referenced scripts.

    Notice that there are no references to the jQuery library. The validations are performed using the Microsoft Ajax Libraries together with JavaScript code injected within the page.

    Figure 11

    No jQuery used for validations

  7. Close the browser and go back to Visual Studio.
  8. Now you will enable unobtrusive validation. Open Web.Config and locate ValidationSettings:UnobtrusiveValidationMode key in the AppSettings section. Set the key value to WebForms.

    Web.Config

    <configuration>
    FakePre-aa368d8d52d64b3ab81350e448e89b47-30f5849cf0dc4467b6c650c50317c292FakePre-9bcb8cac591b495e8e3dbd0e5d1b470b-3dc3d427d9d74dc88165519dd3108450FakePre-b765cd9185814502957ee495aebe4264-f793a1f89bff4737a5dabf484b271e6c <add key="ValidationSettings:UnobtrusiveValidationMode" value="WebForms"/>

    Note:
    You can also set this property in the “Page_Load” event in case you want to enable Unobtrusive Validation only for some pages.

  9. Open the Global.asax.cs file and add the following using statement (shown in bold)

    (Code Snippet – Web Forms Lab - Ex02 – Using statements)

    C#

    using System.Web.SessionState; using WebFormsLab.Model; using System.Web.ModelBinding;

  10. Within the Application_Start method of the Global.asax.cs file, add the following code

    (Code Snippet – Web Forms Lab - Ex02 – ScriptREsourceDefinition)

    C#

    ScriptResourceDefinition myScriptResDef = new ScriptResourceDefinition(); myScriptResDef.Path = "~/Assets/Scripts/jquery-1.7.1.min.js"; myScriptResDef.DebugPath = "~/Assets/Scripts/jquery-1.7.1.js"; myScriptResDef.CdnPath = "https://code.jquery.com/jquery-1.7.1.min.js"; myScriptResDef.CdnDebugPath = "https://code.jquery.com/jquery-1.7.1.js"; ScriptManager.ScriptResourceMapping.AddDefinition("jquery", null, myScriptResDef);

  11. Open Site.Master. Add the code below to include a ScriptManager on the page to include a script reference to the jQuery client library.

    (Code Snippet – Web Forms Lab - Ex01 – Script Manager)

    HTML

    <form runat="server">
    FakePre-3a89de0f58684ec39f8a909696bb2e12-da98117150d44130a553fb74be018d67<asp:ScriptManager ID="uxScriptManagerMasterPage" runat="server" EnableCdn="False"> <Scripts> <asp:ScriptReference Name="jquery" /> </Scripts> </asp:ScriptManager>FakePre-98307289f9a443bf9f4764b642303610-e211c3ff58d74e5ba584b7c782dab70aFakePre-4f352de343e544ac8be6cb28b377b580-ec2e6c4d74e24003a3a0b7ac080c4335

  12. Open CustomerDetails.aspx and press F5 to start the Web application.
  13. Press the F12 key to open the IE developer tools. Once the developer tools is open, select the script tab. Select CustomerDetails.aspx from the menu and take note that the scripts required to run jQuery on the page have been loaded into the browser from the local site.

    Figure 12

    Loading the jQuery JavaScript files directly from the local IIS server

  14. Close the browser to return to Visual Studio. Open the Site.Master file again and locate the ScriptManager that you just added to the page. Change the value of the EnableCdn property to be True. This will force jQuery to be loaded from the online URL, not from the local site’s URL.
  15. Open CustomerDetails.aspx in Visual Studio. Press the F5 key to run the site. Once Internet Explorer opens, press the F12 key to open the developer tools. Select the Script tab, and then take a look at the drop-down list. Note the jQuery JavaScript files are no longer being loaded from the local site, but rather from the online jQuery CDN.

    Figure 13

    Loading the jQuery JavaScript files from the jQuery CDN

  16. Open the HTML page source code again using the View source option in the browser. Notice that by enabling the unobtrusive validation ASP.NET has replaced the injected JavaScript code with data- *attributes.

    Figure 14

    Unobtrusive validation code

    Note:
    In this example, you saw how a validation summary with Data annotations was simplified to only a few HTML and JavaScript lines. Previously, without unobtrusive validation, the more validation controls you add, the bigger your JavaScript validation code will grow.

Task 2 – Validating the Model with Data Annotations

ASP.NET 4.5 introduces data annotations validation for Web Forms. Instead of having a validation control on each input, you can now define constraints in your model classes and use them across all your web application. In this section, you will learn how to use data annotations for validating a new/edit customer form.

  1. Open CustomerDetail.aspx page. Notice that the customer first name and second name in the EditItemTemplate and InsertItemTemplate sections are validated using a RequiredFieldValidator controls. Each validator is associated to a particular condition, so you need to include as many validators as conditions to check.
  2. Add data annotations to validate the Customer model class. Open Customer.cs class in the Model folder and decorate each property using data annotation attributes.

    (Code Snippet –Web Forms Lab - Ex02 – Data Annotations)

    C#

    namespace WebFormsLab.Model
    FakePre-d4daeb0a62c64cd3993c57288dde1eca-015d713c3a5e491e84797c98786f98deFakePre-e0d1ecf59fa8451d9aea036a04d772c9-13cbc39574d5496690bb3e5456d8f065FakePre-57a9ba57ca574dcc80a23e9906fc0806-4ba9899f58784235a42bed4177a4951eFakePre-49e05d3c4f334a5492d9c7b98c4f9047-1de57aa865d24dc882156955097f41aeFakePre-d9be6fe042db490da00e75d6c1cfdcef-f793431976604baeb002fa2e58ac729bFakePre-1f50bcd305114cf6b191009e4b753ede-d061054b217d470cb86c6c9f6a8db51a [Key] public int Id { get; set; } [Required] public string FirstName { get; set; } [Required] public string LastName { get; set; } [Range(0, 130)] public int Age { get; set; } public Address Address { get; set; } [Phone] public string DaytimePhone { get; set; } [EmailAddress, StringLength(256)] public string EmailAddress { get; set; }FakePre-fc15f26406534b3c9449fc065baf4042-7c7996aa9eca4b95b62f83dee7834821FakePre-ff9e67bf2ff847409903698bdb8c1e7b-f6213028e0be4154be2b8993f991bfa1FakePre-26bb414202724207895aa6282dc48579-d9e1a69095ee476cadf7beb00a50fda3FakePre-7e185ad9d09e4691abfe8c0bcd86e079-3cb5ef665efc4fd58ef1b3e70fd0d98aFakePre-72e9c742c2a446a4a100353562d0649b-3b56e075fb3c4a9893dc24f0d844797aFakePre-3a58fa201b7544d2bb3653c89de26621-9ad4a49ee4a84284b6f93df975711b77FakePre-ef278f6de6184cecb2b7b010147ee003-0bb9f7c2a9ba4e37a5f091445c9af3b7FakePre-a408e2a21a654d299e6348867606a08a-834c40f8995c4e3ba00b4863b3cec56a

    Note:
    .NET Framework 4.5 has extended the existing data annotation collection. These are some of the data annotations you can use: [CreditCard], [Phone], [EmailAddress], [Range], [Compare], [Url], [FileExtensions], [Required], [Key], [RegularExpression].

    Some usage examples:

    [Key]: Specifies that an attribute is the unique identifier

    [Range(0.4, 0.5, ErrorMessage="{Write an error message}"]: Double range

    [EmailAddress(ErrorMessage="Invalid Email"), MaxLength(56)]: Two annotations in the same line.

    You can also define your own error messages within each attribute.

  3. Open CustomerDetails.aspx and remove all the RequiredFieldvalidators for the first and last name fields in the in EditItemTemplate and InsertItemTemplate sections of the FormView control.

    HTML

    <EditItemTemplate> <fieldset> <ul> <li><asp:Label runat="server" AssociatedControlID="firstName">First Name: </asp:Label></li> <li><asp:TextBox runat="server" ID="firstName" Text='<%#: BindItem.FirstName %>' /> <!-- Remove the following line--> &nbsp;<asp:RequiredFieldValidator runat="server" ControlToValidate="firstName" ErrorMessage="Please enter a value for First Name" ForeColor="Red" /> </li> </ul> <ul> <li><asp:Label runat="server" AssociatedControlID="lastName">Last Name: </asp:Label></li> <li><asp:TextBox runat="server" ID="lastName" Text='<%#: BindItem.LastName %>' /> <!-- Remove the following line--> &nbsp;<asp:RequiredFieldValidator runat="server" ControlToValidate="lastName" ErrorMessage="Please enter a value for Last Name" ForeColor="Red" /> </li> </ul> <ul> ... <InsertItemTemplate> <fieldset> <ul> <li><asp:Label runat="server" AssociatedControlID="firstName">First Name: </asp:Label></li> <li><asp:TextBox runat="server" ID="firstName" Text='<%# BindItem.FirstName %>' /> <!-- Remove the following line--> &nbsp;<asp:RequiredFieldValidator runat="server" ControlToValidate="firstName" ErrorMessage="Please enter a value for First Name" ForeColor="Red" /> </li> </ul> <ul> <li><asp:Label runat="server" AssociatedControlID="lastName">Last Name: </asp:Label></li> <li><asp:TextBox runat="server" ID="lastName" Text='<%#: BindItem.LastName %>' /> <!-- Remove the following line--> &nbsp;<asp:RequiredFieldValidator runat="server" ControlToValidate="lastName" ErrorMessage="Please enter a value for Last Name" ForeColor="Red" /> </li> </ul> <ul>

    Note:
    One advantage of using data annotations is that validation logic is not duplicated in your application pages. You define it once in the model, and use it across all the application pages that manipulate data.

  4. Open CustomerDetails.aspx code-behind and locate the SaveCustomer method. This method is called when inserting a new customer and receives the Customer parameter from the FormView control values. When the mapping between the page controls and the parameter object occurrs, ASP.NET will execute the model validation against all the data annotation attributes and fill the ModelState dictionary with the errors encountered, if any.

    The ModelState.IsValid will only return true if all the fields on your model are valid after performing the validation.

    C#

    public void SaveCustomer(Customer customer) 
    FakePre-f317af3ee2e048658bd336606ef8a6fd-542b92ec35dc478f90dc7a4bf6c31736 if (ModelState.IsValid)FakePre-e224fc2bb0c14eaab8c4079bc4f1b2ed-da9fc9cee33e4470870346338691af3eFakePre-8cefc68e034b4b30a86a3c0d7db8a31d-618f05c11862446abbf2b942b71e8cceFakePre-801ba8c1f5334d94b92d55a2ee77b4fa-616d515fe06841a1b27f415b8a92ceb9FakePre-c1b0da346ab5470e923f85fae4dd86c3-b5254ddae1764d559af19d660653a5a8

  5. Add a ValidationSummary control at the end of the CustomerDetails page to show the list of model errors.

    (Code Snippet – Web Forms Lab - Ex02 – ValidationSummary)

    HTML

          </fieldset>
    FakePre-70fbadf6271d4967b287e8a421dfc140-9aa530f12ae34b83bb7895d2f13500aeFakePre-db27d61fff80450a8d2e45242b873d85-1111b43a25424d8d9de54cc749becac8FakePre-4d07e5bc9b0f4d59a629c800efa22440-9c907f06083d401798c912634de01a54 <asp:ValidationSummary runat="server" ShowModelStateErrors="true" ForeColor="Red" HeaderText="Please check the following errors:"/>FakePre-3c7f2bc4f51f400184afdfd5005ef444-5d905e37ec2141fe90c8f050e09ca542

    The ShowModelStateErrors is a new property on the ValidationSummary control that when set to true, the control will show the errors from the ModelState dictionary. These errors come from the data annotations validation.

  6. Press F5 to run the Web application. Complete the form with some erroneous values and click Save to execute validation. Notice the error summary at the bottom.

    Figure 15

    Validation with Data Annotations

Task 3 – Handling Custom Database Errors with ModelState

In previous version of Web Forms, handling database errors such as a too long string or a unique key violation could involve throwing exceptions in your repository code and then handling the exceptions on your code-behind to display an error. A great amount of code is required to do something relatively simple.

In Web Forms 4.5, the ModelState object can be used to display the errors on the page, either from your model or from the database, in a consistent manner.

In this task, you will add code to properly handle database exceptions and show the appropriate message to the user using the ModelState object.

  1. While the application is still running, try to update the name of a category using a duplicated value.

    Figure 16

    Updating a category with a duplicated name

    Notice that an exception is thrown due to the “unique” constraint of the CategoryName column.

    Figure 17

    Exception for duplicated category names

  2. Stop debugging. In the Products.aspx.cs code-behind file, update the UpdateCategory method to handle the exceptions thrown by the db.SaveChanges() method call and add an error to the ModelState object.

    The new TryUpdateModel method updates the category object retrieved from the database using the form data provided by the user.

    (Code Snippet – Web Forms Lab - Ex01 – UpdateCategory Handle Errors)

    C#

    public void UpdateCategory(int categoryId)
    FakePre-050e7536793e40b7ae795652eee5d67a-7ccda163738045c8a15a416948247896FakePre-736d2418941243bda802d2ac8b388ab1-a9f57801f7624e758163350911dbba6bFakePre-e4bb0c44279540aebe98196e55ac1f3a-9ced704e1fb540c084b77617440d4dcaFakePre-faaa0f0757ac47a183d2833f07b1a21d-5749b0a7f9aa4a68b373e3ff5570c1baFakePre-3b9f6412d1b44827a07a3139b5897c15-b1815d2baacd443cbe31b159fcea95ebFakePre-a8494ba3cff74a7aa4257920519953c1-67c648dcc576426ca5675cb2e5770882FakePre-bfba7d50e69b4a2384a8ce369e209ca2-61ab1d5712f04fd6ab0e3250207d3dea try { this.db.SaveChanges(); } catch (DbUpdateException) { ModelState.AddModelError("CategoryName", string.Format("A category with the name {0} already exists.", category.CategoryName)); }FakePre-96d8a04009794c2c9e8691895b6ab46f-2cf0c1ed2bc74fcb9be47459fcc64904FakePre-3afd0a6542054726941fb451c751304f-0ab14c40f93b43fa9fc99be31d499722

    Note:
    Ideally, you would have to identify the cause of the DbUpdateException and check if the root cause is the violation of a unique key constraint.

  3. Open Products.aspx and add a ValidationSummary control below the categories GridView to show the list of model errors.

    (Code Snippet – Web Forms Lab - Ex02 – Categories ValidationSummary)

    HTML

    <asp:GridView ID="categoriesGrid" runat="server"
    FakePre-d9bc0d3f16fa4ccaabee3a54be4fb97e-cd84c89b77c54db8a989a6574db32bc1FakePre-dd863014966d46aabc6850fff2782e5d-4678fce5e9fe4360bfe8ddd44447d24dFakePre-dd4f3486d88e456382ec3eaf7a03d117-f1a29f3a89494658851c1a397bc300c8<asp:ValidationSummary ID="ValidationSummary1" runat="server" ShowModelStateErrors="true" />FakePre-ff5c0a8c4e1a4fa8bde2b0685d3305db-9fb7a7f42edb43d2a9cac2f6b5892bf3FakePre-ff848f62d5a84be2920e2659e14e52c4-425173a8ecab49ccb3df6c40214c1a35

  4. Run the site and go to the Products page. Try to update the name of a category using an duplicated value.

    Notice that the exception was handled and the error message appears in the ValidationSummary control.

    Figure 18

    Duplicated category error

Task 4 – Request Validation in ASP.NET Web Forms 4.5

The request validation feature in ASP.NET provides a certain level of default protection against cross-site scripting (XSS) attacks. In previous versions of ASP.NET, request validation was enabled by default and could only be disabled for an entire page. With the new version of ASP.NET Web Forms you can now disable the request validation for a single control, perform lazy request validation or access un-validated request data (be careful if you do so!).

  1. Press Ctrl+F5 to start the site without debugging and go to the Products page. Select a category and then click the Edit link on any of the products.
  2. Type a description containing potentially dangerous content, for instance including HTML tags. Take notice of the exception thrown due to the request validation.

    Figure 19

    Editing a product with potentially dangerous content

    Figure 20

    Exception thrown due to request validation

  3. Close the page and, in Visual Studio, press SHIFT+F5 to stop debugging.
  4. Open the ProductDetails.aspx page and locate the Description TextBox.
  5. Add the new ValidateRequestMode property to the TextBox and set its value to Disabled.

    The new ValidateRequestMode attribute allows you to disable the request validation granularly on each control. This is useful when you want to use an input that may receive HTML code, but want to keep the validation working for the rest of the page.

    HTML

    <li>
    FakePre-16bf329b5d5840e78d0aaf577788663f-f6f37224372949fd8465e4c1a73eb699 ValidateRequestMode="Disabled" />FakePre-a79e45c85c264372b1728eb2c5b59f82-4bea3305537c4fdc9fe657544c7774cb

  6. Press F5 to run the web application. Open the edit product page again and complete a product description including HTML tags. Notice that you can now add HTML content to the description.

    Figure 21

    Request validation disabled for the product description

    Note:
    In a production application, you should sanitize the HTML code entered by the user to make sure only safe HTML tags are entered (for example, there are no <script> tags). To do this, you can use Microsoft Web Protection Library.

  7. Edit the product again. Type HTML code in the Name field and click Save. Notice that Request Validation is only disabled for the Description field and the rest of the fields re still validated against the potentially dangerous content.

    Figure 22

    Request validation enabled in the rest of the fields

  8. Now open Web.config and check the HttpRuntime element, notice the new 4.5 validation mode.

    XML

    <system.web>
    FakePre-8564e4b9e2fe4cce97f479d43d251f55-4b847a9cb5244c648b1651b2ae2b2956 <httpRuntime requestValidationMode="4.5" encoderType="System.Web.Security.AntiXss.AntiXssEncoder, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />FakePre-62e9778d5957451e9f9cdbfb2bef1b69-9c8f83f74e0a4d30a140fbb33f97f7a3FakePre-714b28c4ce7f460582b3f1b563d81e50-cf36caab46464aef950f78bd4908f4ae

    ASP.NET Web Forms 4.5 includes a new request validation mode to perform request validation lazily. With the request validation mode set to 4.5, if a piece of code accesses Request.Form["key"], ASP.NET 4.5's request validation will only trigger request validation for that specific element in the form collection.

    Additionally, ASP.NET 4.5 now includes core encoding routines from the Microsoft Anti-XSS Library v4.0. The Anti-XSS encoding routines are implemented by the new AntiXssEncodertype found in the new System.Web.Security.AntiXssnamespace. With the encoderType parameter configured to use AntiXssEncoder, all output encoding within ASP.NET automatically uses the new encoding routines.

  9. ASP.NET 4.5 request validation also supports un-validated access to request data. ASP.NET 4.5 adds a new collection property to the HttpRequest object called Unvalidated. When you navigate into HttpRequest.Unvalidated you have access to all of the common pieces of request data, including Forms, QueryStrings, Cookies, URLs, and so on.

    Figure 23

    Request.Unvalidated object

    Note:
    Please use the HttpRequest.Unvalidated property with caution! Make sure you carefully perform custom validation on the raw request data to ensure that dangerous text is not round-tripped and rendered back to unsuspecting customers!