La validación en los lenguajes específicos de dominio
Como autor de un lenguaje específico (DSL), puede definir restricciones de validación para comprobar que el modelo creado por el usuario es significativo.Por ejemplo, si un DSL permite a los usuarios dibujan un árbol de familia de personas y sus antecesores, puede escribir una restricción que garantiza que los elementos secundarios tienen fechas de nacimiento después de sus elementos primarios.
Puede hacer que las restricciones de validación se ejecutan cuando se guarda el modelo, cuando se abre, y cuando el usuario explícitamente ejecuta el comando de menú de Validar .También puede ejecutar la validación bajo el control de programa.Por ejemplo, podría ejecutar la validación en respuesta a un cambio en un valor de propiedad o una relación.
La validación es particularmente importante si escribe las plantillas de texto u otras herramientas que procesan los modelos de los usuarios.La validación garantiza que los modelos satisfacen las condiciones previas de por las herramientas.
Precaución |
---|
También puede permitir que las restricciones de validación se define en extensiones independientes a DSL, junto con comandos de menú de extensión y controladores de gestos.Los usuarios pueden decidir instalar estas extensiones además de ADSL.Para obtener más información, vea Ampliar DSL mediante MEF. |
Validación actual
Cuando un usuario edita un modelo, es decir, una instancia de lenguaje específico de dominio, las siguientes acciones pueden ejecutar la validación:
Haga clic con el botón secundario en el diagrama y valide todosseleccione.
Haga clic con el botón secundario en el nodo superior en el Explorador de ADSL y de valide todosseleccione
Guarde el modelo.
Abra el modelo.
Además, puede escribir código de programa que ejecute la validación, por ejemplo, como parte de un comando de menú o en respuesta a un cambio.
cualquier error de validación aparecerá en la ventana de Lista de errores .El usuario puede hacer doble clic en un mensaje de error para seleccionar los elementos de que son la causa del error.
Definición de restricciones de validación
Define restricciones de validación agregando métodos de validación a las clases de dominio o relaciones ADSL.Cuando la validación se ejecuta, por el usuario o bajo el control de programa, ejecutan algunos o todos los métodos de validación.Cada método se aplica a cada instancia de la clase, y puede haber varios métodos de validación de cada clase.
Informes de cada método de validación los errores que encuentre.
[!NOTA]
Los métodos de validación indican errores, pero no cambian el modelo.Si desea ajustar o para evitar ciertos cambios, vea alternativas a la validación.
Para definir una restricción de validación
Validación de permiso en el nodo de Editor\Validation :
Abra Dsl\DslDefinition.dsl.
En el Explorador ADSL, expanda el nodo de Editor y seleccione Validación.
en la ventana Propiedades, establezca las propiedades de utiliza a true.Es más conveniente establecer todas estas propiedades.
Haga clic en Transformar todas las plantillas en la barra de herramientas del explorador de soluciones.
Escriba las definiciones de clase parcial para uno o más de las clases de dominio o de las relaciones de dominio.escriba estas definiciones en un nuevo archivo de código en el proyecto de Dsl .
prefijo cada clase con este atributo:
[ValidationState(ValidationState.Enabled)]
- de forma predeterminada, este atributo también habilitará la validación para las clases derivadas.Si desea deshabilitar la validación en una clase derivada concreta, puede utilizar ValidationState.Disabled.
Agregue los métodos de validación a las clases.Cada método de validación puede tener cualquier nombre, pero tiene un parámetro de ValidationContextescrito.
Debe estar precedido por uno o más atributos de ValidationMethod :
[ValidationMethod (ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu ) ]
el ValidationCategories especifica cuando se ejecuta el método.
Por ejemplo:
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
// Allow validation methods in this class:
[ValidationState(ValidationState.Enabled)]
// In this DSL, ParentsHaveChildren is a domain relationship
// from Person to Person:
public partial class ParentsHaveChildren
{
// Identify the method as a validation method:
[ValidationMethod
( // Specify which events cause the method to be invoked:
ValidationCategories.Open // On file load.
| ValidationCategories.Save // On save to file.
| ValidationCategories.Menu // On user menu command.
)]
// This method is applied to each instance of the
// type (and its subtypes) in a model:
private void ValidateParentBirth(ValidationContext context)
{
// In this DSL, the role names of this relationship
// are "Child" and "Parent":
if (this.Child.BirthYear < this.Parent.BirthYear
// Allow user to leave the year unset:
&& this.Child.BirthYear != 0)
{
context.LogError(
// Description:
"Child must be born after Parent",
// Unique code for this error:
"FAB001ParentBirthError",
// Objects to select when user double-clicks error:
this.Child,
this.Parent);
}
}
Observe los siguientes sobre este código:
Puede agregar métodos de validación a las clases de dominio o relaciones de dominio.el código para estos tipos está en Dsl\Generated Code\Domain*.cs.
Cada método de validación se aplica a cada instancia de la clase y sus subclases.En el caso de una relación de dominio, cada instancia es un vínculo entre dos elementos del modelo.
Los métodos de validación no se aplican en orden especificado, y cada método no se aplica a las instancias de la clase en orden confiable.
Normalmente es práctica incorrecto para que un método de validación actualice el contenido del almacén, porque esto llevaría a los resultados incoherentes.En su lugar, el método debe notificar cualquier error llamando a context.LogError, LogWarning o LogInfo.
En la llamada a LogError, puede proporcionar una lista de elementos del modelo o vínculos de la relación que son seleccionado cuando el usuario hace doble clic en el mensaje de error.
Para obtener información sobre cómo leer el modelo en código de programa, vea Navegar y actualizar un modelo en el código del programa.
El ejemplo se aplica al modelo de dominio siguiente.La relación de ParentsHaveChildren tiene roles que se llama Child y elemento primario.
Categorías de validación
En el atributo de ValidationMethod , especifique si el método de validación debe ejecutarse.
Categoría |
Execution |
---|---|
Cuando el usuario invoca el comando de menú validar. |
|
Cuando se abre el archivo del modelo. |
|
Cuando guarde el archivo.Si hay errores de validación, dará el usuario la opción de cancelar la operación. |
|
Cuando guarde el archivo.Si hay errores de métodos en esta categoría, advierten el usuario que puede no ser posible abrir el archivo. Utilice esta categoría para los métodos de validación que comprueban los nombres o los id. duplicados, u otras condiciones que pueden producir errores de carga. |
|
Cuando se llama al método de ValidateCustom.Las validaciones en esta categoría se pueden invocar desde de código de programa. Para obtener más información, vea Categorías personalizadas de validación. |
Dónde colocar métodos de validación
Puede tener acceso a menudo el mismo efecto colocando un método de validación en un tipo diferente.Por ejemplo, podría agregar un método a la clase person en lugar de la relación de ParentsHaveChildren, y hace que recorra en iteración los vínculos:
[ValidationState(ValidationState.Enabled)]
public partial class Person
{[ValidationMethod
( ValidationCategories.Open
| ValidationCategories.Save
| ValidationCategories.Menu
)
]
private void ValidateParentBirth(ValidationContext context)
{
// Iterate through ParentHasChildren links:
foreach (Person parent in this.Parents)
{
if (this.BirthYear <= parent.BirthYear)
{ ...
Agregar restricciones de validación. Para aplicar una validación en un orden confiable, defina un método de validación en una clase de propietario, por el elemento raíz del modelo.Esta técnica también permite agregar informes de error multithreading en un único mensaje.
Las desventajas son que el método combinado es menos fácil de administrar, y que las restricciones deben tener mismo ValidationCategories.Por consiguiente se recomienda mantener cada restricción en un método independiente si es posible.
Pasar valores en la memoria caché del contexto. El parámetro de contexto tiene un diccionario en el que puede colocar valores arbitrarios.El diccionario conserva durante la vida de la validación.Un método set de validación podría, por ejemplo, conservar un número de error en el contexto, y utilizarlo para evitar inundar la ventana de error con mensajes repetidos.Por ejemplo:
List<ParentsHaveChildren> erroneousLinks;
if (!context.TryGetCacheValue("erroneousLinks", out erroneousLinks))
erroneousLinks = new List<ParentsHaveChildren>();
erroneousLinks.Add(this);
context.SetCacheValue("erroneousLinks", erroneousLinks);
if (erroneousLinks.Count < 5) { context.LogError( ... ); }
Validación de Multiplicidades
Los métodos de validación para comprobar multiplicidad mínima se generan automáticamente ADSL.El código se escribe en Dsl\Generated Code\MultiplicityValidation.cs.Estos métodos surten efecto cuando se habilita la validación en el nodo de editor \Validation en el Explorador de ADSL.
Si establece la multiplicidad de un rol de relación de dominio sea 1. * o 1..1, pero el usuario no establece relaciones de esta relación, un mensaje de error de validación.
Por ejemplo, si un ADSL tiene person y Town de las clases, y una relación PersonLivesInTown con una relación 1.* en el rol de Town, después de cada persona que no tenga Town, un mensaje de error aparecerá.
Validación en el código de programa
Puede ejecutar la validación obtener acceso o creando un ValidationController.Si desea que los errores que se van a mostrar al usuario en la ventana de error, utilice el ValidationController adjunto a DocData del diagrama.Por ejemplo, si escribe un comando de menú, CurrentDocData.ValidationController está disponible en la clase determinada de comando:
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Modeling.Shell;
...
partial class MyLanguageCommandSet
{
private void OnMenuMyContextMenuCommand(object sender, EventArgs e)
{
ValidationController controller = this.CurrentDocData.ValidationController;
...
Para obtener más información, vea Cómo: Agregar un comando a un menú contextual.
También puede crear un controlador independiente de validación, y administra los errores personalmente.Por ejemplo:
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Modeling.Shell;
...
Store store = ...;
VsValidationController validator = new VsValidationController(s);
// Validate all elements in the Store:
if (!validator.Validate(store, ValidationCategories.Save))
{
// Deal with errors:
foreach (ValidationMessage message in validator.ValidationMessages) { ... }
}
Validación actual cuando un cambio aparece
Si desea asegurarse de que adviertan el usuario inmediatamente si el modelo deja de ser válido, puede definir un evento de almacén que ejecute la validación.Para obtener más información sobre eventos almacenados, vea Los controladores de eventos propagan cambios fuera del modelo.
Además del código de validación, agregue un archivo de código personalizado al proyecto de DslPackage , con contenido similar al ejemplo siguiente.Este código utiliza ValidationController que se asocia al documento.Este controlador muestra los errores de validación en la lista de errores de Visual Studio .
using System;
using System.Linq;
using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Validation;
namespace Company.FamilyTree
{
partial class FamilyTreeDocData // Change name to your DocData.
{
// Register the store event handler:
protected override void OnDocumentLoaded()
{
base.OnDocumentLoaded();
DomainClassInfo observedLinkInfo = this.Store.DomainDataDirectory
.FindDomainClass(typeof(ParentsHaveChildren));
DomainClassInfo observedClassInfo = this.Store.DomainDataDirectory
.FindDomainClass(typeof(Person));
EventManagerDirectory events = this.Store.EventManagerDirectory;
events.ElementAdded
.Add(observedLinkInfo, new EventHandler<ElementAddedEventArgs>(ParentLinkAddedHandler));
events.ElementDeleted.Add(observedLinkInfo, new EventHandler<ElementDeletedEventArgs>(ParentLinkDeletedHandler));
events.ElementPropertyChanged.Add(observedClassInfo, new EventHandler<ElementPropertyChangedEventArgs>(BirthDateChangedHandler));
}
// Handler will be called after transaction that creates a link:
private void ParentLinkAddedHandler(object sender,
ElementAddedEventArgs e)
{
this.ValidationController.Validate(e.ModelElement,
ValidationCategories.Save);
}
// Called when a link is deleted:
private void ParentLinkDeletedHandler(object sender,
ElementDeletedEventArgs e)
{
// Don't apply validation to a deleted item!
// - Validate store to refresh the error list.
this.ValidationController.Validate(this.Store,
ValidationCategories.Save);
}
// Called when any property of a Person element changes:
private void BirthDateChangedHandler(object sender,
ElementPropertyChangedEventArgs e)
{
Person person = e.ModelElement as Person;
// Not interested in changes in other properties:
if (e.DomainProperty.Id != Person.BirthYearDomainPropertyId)
return;
// Validate all parent links to and from the person:
this.ValidationController.Validate(
ParentsHaveChildren.GetLinksToParents(person)
.Concat(ParentsHaveChildren.GetLinksToChildren(person))
, ValidationCategories.Save);
}
}
}
Se llama a los controladores también después de operaciones de deshacer o de rehacer que afectan a los vínculos o elementos.
Categorías personalizadas de validación
Además de las categorías estándar de validación, como menú y Abrir, puede definir dispone de categorías.Puede invocar estas categorías de código de programa.el usuario no puede invocarlos directamente.
Un uso típico de categorías personalizadas es definir una categoría que comprueba si el modelo cumple las condiciones previas de una herramienta específica.
Para agregar un método de validación a una categoría determinada, prefijo con un atributo como de esto:
[ValidationMethod(CustomCategory = "PreconditionsForGeneratePartsList")]
[ValidationMethod(ValidationCategory.Menu)]
private void TestForCircularLinks(ValidationContext context)
{...}
[!NOTA]
Puede prefijo un método con todos los atributos de [ValidationMethod()] como desee.Puede agregar un método a las categorías personalizadas y estándar.
para invocar una validación personalizada:
// Invoke all validation methods in a custom category:
validationController.ValidateCustom
(store, // or a list of model elements
"PreconditionsForGeneratePartsList");
alternativas a la validación
Restricciones de validación indican errores, pero no cambian el modelo.Si, en su lugar, desea evitar el modelo el llegar a ser válido, puede utilizar otras técnicas.
Sin embargo, estas técnicas no es recomendable.Normalmente es mejor que el usuario decidir cómo corregir un modelo no válido.
Ajuste el cambio para restaurar el modelo a la validez. Por ejemplo, si el usuario establece una propiedad sobre el máximo permitido, se pueden restaurar la propiedad el valor máximo.Para ello, defina una regla.Para obtener más información, vea Las reglas propagan los cambios dentro del modelo.
Revertir la transacción si se intenta un cambio no válido. También puede definir una regla con este propósito, pero es en algunos casos es posible reemplazar un controlador **OnValueChanging()**de la propiedad, o reemplazar un método como OnDeleted(). para revertir una transacción, el uso this.Store.TransactionManager.CurrentTransaction.Rollback(). para obtener más información, vea Controladores de los cambios de valor de propiedad de dominio.
Precaución |
---|
Asegúrese de que el usuario sepa que el cambio se ha ajustado o revertir.por ejemplo, utilice System.Windows.Forms.MessageBox.Show("message"). |
Vea también
Conceptos
Navegar y actualizar un modelo en el código del programa
Los controladores de eventos propagan cambios fuera del modelo