Walkthrough: Adding Validation to a Domain Model

As the author of a domain-specific language, you can add constraints to your domain models. This enables you to check for semantic correctness beyond what you can express in the syntax of that language. Users of your domain-specific languages can validate the models they create from those languages. Also, they can display their results. For more information, see Validation Overview for Domain-Specific Languages.

注意

When you install Domain-Specific Language Tools, you also install samples such as the FamilyTree sample on which this walkthrough is based. For more information, see Family Tree Sample.

In this walkthrough, you continue from the steps conducted in Walkthrough: Customizing the Domain-Specific Language Definition by adding validation constraints to the FamilyTree solution.

Prerequisites

To complete this walkthrough, you must:

Enabling the Validation Framework

Before you add validation, you must set global switches within the language definition to specify when validation occurs. For this example, you enable validation when a user opens a file, saves a file, or uses the Validate menu command.

To enable the validation framework

  1. Open the solution that you customized in Walkthrough: Customizing the Domain-Specific Language Definition

  2. In Solution Explorer, open DslDefinition.dsl.

  3. In DSL Explorer, expand the Editor node, and then click Validation.

    If DSL Explorer does not appear, open the View menu, point to Other Windows, and click DSL Explorer.

  4. In the Properties window, set the Uses Menu, Uses Open, and Uses Save properties to True.

    If the Properties window is not showing, press F4.

  5. Save DslDefinition.dsl.

  6. Regenerate the code for the solution by clicking Transform All Templates on the Solution Explorer toolbar.

    注意

    You might see a message warning you not to run text templates from untrusted sources. If you do not want this message to appear again, select the Do not show this message again check box, and click OK. Otherwise, click OK.

Adding Validation Code

When you transform all templates, the system generates in the Dsl project the source code that defines your domain-specific language. Also, it generates a class for each class and relationship that is defined in the DslDefinition.dsl file. To add validation constraints, you add methods to these classes. However, to avoid interfering with the generated text, you should write your validation methods in a separate file or in files that define partial classes.

To add a partial class

  1. In Solution Explorer, right-click the Dsl project, point to Add, and then click New Folder. Click the resulting folder, and rename it Validation.

  2. Right-click the Validation folder, point to Add, and then click New Item.

  3. Under Templates, click Code File.

  4. In Name, type BirthDates.cs, and click Add.

    注意

    When you write a large set of validations, you should create more than one file. You might want to write a separate file for each class. Another option is to write a separate file for each group of related constraints, each of which might contain more than one partial class.

  5. In BirthDates.cs, add the following code:

    namespace Fabrikam.FamilyTree
    {
        using System;
        using System.Collections.Generic;
        using System.Text;
        using System.Collections.Specialized;
       using Microsoft.VisualStudio.Modeling.Validation;
        [ValidationState(ValidationState.Enabled)]
        public partial class Person
    {
        //   Validation methods for Person go here.
    }
    }
    

    注意

    To verify the name and the namespace of the generated class, open Dsl\GeneratedCode\DomainClasses.cs.

  6. In Solution Explorer, expand the Dsl project, and expand the GeneratedCode folder.

  7. Click the plus sign (+) beside DomainClasses.tt, and then double-click DomainClasses.cs.

  8. Verify that the partial class in the code sample has the same name and namespace as the generated class.

The ValidationState attribute guarantees that validation methods in the class are called when validation occurs. By default, constraints apply to instances of subclasses, but you can set ValidationState.Disabled in specific subclasses if your domain requires it.

Writing a Validation Method

To define constraints, you must add a validation method to your partial class.

To add the validation method

  • In BirthDates.cs, add the following code as a method in the partial class Person:

    注意

    Replace "//… validation methods for Person go here"from the previous procedure.

    // This attribute identifies the method ValidateParentBirth 
    // to the validation framework.
    [ValidationMethod
     ( // These values select which events cause the method to be invoked.
          ValidationCategories.Open |
          ValidationCategories.Save |
          ValidationCategories.Menu
     )
    ]
      // This method is applied to each instance of the 
      // type in a model. 
      private void ValidateParentBirth(ValidationContext context)   
      {
        foreach (Person parent in this.Parents)
          {
            if (this.Birth <= parent.Birth)
            {
              context.LogError(
                 // Description
                           "Birth must be after Parent's birth",
                 // Unique code for this error
                           "FAB001FamilyParentBirthError", 
                  // Objects to select when user double-clicks error
                           this, 
                           parent);
            }
          }
      }
    

    注意

    You should declare validation methods private or protected if they might be overridden in a subclass. This strategy avoids cluttering the public API of the domain model with validation methods.

Testing the Constraint

Rebuild your project to test the validation code. If you have not made further changes to the language definition files, you do not need to transform all templates again.

To test the method

  1. On the Build menu, click Rebuild Solution.

  2. On the Debug menu, click Start Debugging, or press F5.

  3. Open Test.ftree.

    The validation error appears in the Error List window (because you specified that the file should be validated whenever it is opened).

  4. Add further classes and relationships with errors between the birth dates of the parents and the children.

  5. Right-click anywhere in the model designer, and click Validate All.

    The new validation errors appear in the Error List window.

  6. Save the file.

    You might see a message that indicates that there were validation errors. It will prompt you to either continue to save or not.

Debugging Constraints

You can make a constraint work only in debug builds by wrapping the validation method with #if DEBUG and #endif.

See Also

Concepts

Validation Overview for Domain-Specific Languages

How to: Add Validation to a Domain Model

Family Tree Sample

User Interface Process Sample

Class Diagram Sample

Domain-Specific Language Tools Glossary