Megosztás a következőn keresztül:


Érvényesítés Domain-Specific nyelven

Tartományspecifikus nyelv (DSL) szerzőjeként érvényesítési korlátozásokat határozhat meg annak ellenőrzéséhez, hogy a felhasználó által létrehozott modell értelmezhető-e. Ha például a DSL lehetővé teszi a felhasználók számára, hogy megrajzolhassák az emberek és őseik családfáját, írhat egy kényszert, amely biztosítja, hogy a gyermekeknek a szüleik után születési dátumuk legyen.

Az érvényesítési korlátozások végrehajthatók a modell mentésekor, megnyitásakor és amikor a felhasználó explicit módon futtatja az Ellenőrzés menü parancsot. Az ellenőrzést programvezérléssel is végrehajthatja. Végrehajthat például érvényesítést egy tulajdonságérték vagy kapcsolat változására válaszul.

Az ellenőrzés különösen fontos, ha szöveges sablonokat vagy a felhasználói modelleket feldolgozó egyéb eszközöket ír. Az ellenőrzés biztosítja, hogy a modellek megfelelnek az eszközök által feltételezett előfeltételeknek.

Figyelmeztetés

Azt is engedélyezheti, hogy az érvényesítési korlátozások a DSL külön bővítményeiben, a bővítménymenü parancsaival és a kézmozdulatkezelőkkel együtt definiálhatók legyenek. A felhasználók a DSL mellett is telepíthetik ezeket a bővítményeket. További információ: DSL kiterjesztése MEF használatával.

Érvényesítés futtatása

Ha egy felhasználó egy modellt szerkeszt, vagyis a tartományspecifikus nyelv egy példányát, a következő műveletek futtathatnak érvényesítést:

  • Kattintson a jobb gombbal a diagramra, és válassza az Összes ellenőrzése lehetőséget.

  • Kattintson a jobb gombbal a felső csomópontra a DSL Explorerben, és válassza az Összes érvényesítése lehetőséget

  • Mentse a modellt.

  • Nyissa meg a modellt.

  • Emellett olyan programkódot is írhat, amely érvényesítést futtat, például egy menüparancs részeként vagy egy változásra válaszul.

    Az érvényesítési hibák megjelennek a Hibalista ablakban. A felhasználó duplán kattinthat egy hibaüzenetre a hiba okaként szolgáló modellelemek kiválasztásához.

Érvényesítési korlátozások meghatározása

Érvényesítési korlátozásokat úgy határozhat meg, hogy érvényesítési módszereket ad hozzá a DSL tartományosztályaihoz vagy kapcsolataihoz. Ha az érvényesítést a felhasználó vagy a program ellenőrzése alatt futtatja, a rendszer végrehajtja az érvényesítési módszerek egy részét vagy egészét. A rendszer minden metódust az osztály minden példányára alkalmaz, és az egyes osztályokban több érvényesítési módszer is lehet.

Minden ellenőrzési módszer jelentést készít a talált hibákról.

Megjegyzés:

Az érvényesítési módszerek hibákat jelentenek, de nem módosítják a modellt. Ha módosítani vagy megakadályozni szeretne bizonyos módosításokat, tekintse meg az Érvényesítés alternatívái című témakört.

Érvényesítési kényszer definiálása

  1. Érvényesítés engedélyezése a Szerkesztő\Érvényesítési csomópontban:

    1. Nyissa meg a Dsl\DslDefinition.dsl fájlt.

    2. A DSL Explorerben bontsa ki a Szerkesztő csomópontot, és válassza az Érvényesítés lehetőséget.

    3. A Tulajdonságok ablakban állítsa a Felhasználás tulajdonságokat a következőre true: A legkényelmesebb beállítani ezeket a tulajdonságokat.

    4. Kattintson az Összes sablon átalakítása gombra a Megoldáskezelő eszköztárán.

  2. Írjon részleges osztálydefiníciókat egy vagy több tartományosztályhoz vagy tartománykapcsolathoz. Ezeket a definíciókat írja be egy új kódfájlba a Dsl-projektben .

  3. Minden osztály előtagja ezzel az attribútummal:

    [ValidationState(ValidationState.Enabled)]
    
    • Alapértelmezés szerint ez az attribútum engedélyezi a származtatott osztályok érvényesítését is. Ha le szeretné tiltani egy adott származtatott osztály érvényesítését, használhatja ValidationState.Disableda következőt:
  4. Érvényesítési módszerek hozzáadása az osztályokhoz. Minden érvényesítési módszernek lehet bármilyen neve, de egy típusú ValidationContextparamétere lehet.

    Az előtagnak egy vagy több ValidationMethod attribútummal kell rendelkeznie:

    [ValidationMethod (ValidationCategories.Open | ValidationCategories.Save | ValidationCategories.Menu ) ]
    

    Az ValidationCategories határozza meg a metódus végrehajtásának módját.

    Például:

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);
    }
  }

Figyelje meg a következő pontokat a kóddal kapcsolatban:

  • Érvényesítési módszereket adhat hozzá tartományosztályokhoz vagy tartománykapcsolatokhoz. Az ilyen típusok kódja a Dsl\Generated Code\Domain*.cs.

  • A rendszer minden érvényesítési módszert alkalmaz az osztály és annak alosztályainak minden egyes példányára. Egy tartománykapcsolat esetén minden példány egy link két modellelem között.

  • Az érvényesítési módszerek nincsenek alkalmazva semmilyen meghatározott sorrendben, és a rendszer nem alkalmazza az egyes metódusokat az osztály példányaira semmilyen előrejelezhető sorrendben.

  • Általában helytelen gyakorlat, ha egy érvényesítési módszer frissíti az áruház tartalmát, mert ez inkonzisztens eredményekhez vezetne. Ehelyett a metódusnak minden hibát jelenteni kell a context.LogError, LogWarning vagy LogInfo hívásával.

  • A LogError hívásban megadhatja azon modellelemek vagy kapcsolati hivatkozások listáját, amelyek akkor lesznek kiválasztva, amikor a felhasználó duplán kattint a hibaüzenetre.

  • A modell programkódban való olvasásáról további információt a Modell navigálása és frissítése a programkódban című témakörben talál.

    A példa a következő tartománymodellre vonatkozik. A ParentsHaveChildren kapcsolat gyermek és szülő nevű szerepkörökkel rendelkezik.

    DSL-definíciós diagram – családfamodell

Érvényesítési kategóriák

Az attribútumban ValidationMethodAttribute megadhatja, hogy mikor kell végrehajtani az érvényesítési módszert.

Kategória Execution
ValidationCategories Amikor a felhasználó meghívja az Ellenőrzés menü parancsot.
ValidationCategories A modellfájl megnyitásakor.
ValidationCategories A fájl mentésekor. Ha ellenőrzési hibák lépnek fel, a felhasználónak lehetősége lesz megszakítani a mentési műveletet.
ValidationCategories A fájl mentésekor. Ha ebben a kategóriában vannak hibák a metódusok között, a rendszer figyelmezteti a felhasználót, hogy előfordulhat, hogy nem lehet újra megnyitni a fájlt.

Ez a kategória olyan érvényesítési módszerekhez használható, amelyek ismétlődő neveket vagy azonosítókat tesztelnek, vagy egyéb olyan feltételeket, amelyek betöltési hibákat okozhatnak.
ValidationCategories A ValidateCustom metódus meghívásakor. Az ebben a kategóriában szereplő érvényesítések csak programkódból hívhatók meg.

További információ: Egyéni érvényesítési kategóriák.

Az érvényesítési módszerek helye

Ezt a hatást gyakran úgy érheti el, hogy egy érvényesítési módszert egy másik típusra helyez. Hozzáadhat például egy metódust a Person osztályhoz a ParentsHaveChildren kapcsolat helyett, és iterálhat a kapcsolatokon:

[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)
        { ...

Érvényesítési korlátozások összesítése. Ha kiszámítható sorrendben szeretné alkalmazni az ellenőrzést, definiáljon egyetlen érvényesítési módszert egy tulajdonososztályon, például a modell gyökérelemét. Ezzel a technikával több hibajelentést is összesíthet egyetlen üzenetben.

Hátránya, hogy a kombinált módszer kevésbé könnyen kezelhető, és hogy a korlátozásoknak azonosnak ValidationCategorieskell lenniük . Ezért azt javasoljuk, hogy ha lehetséges, minden kényszert külön metódusban tartson.

Értékek átadása a kontextus gyorsítótárban. A környezeti paraméter rendelkezik egy szótárval, amelybe tetszőleges értékeket helyezhet el. A szótár az érvényesítési futtatás élettartama során is megmarad. Egy adott érvényesítési módszer például megtarthatja a hibaszámot a környezetben, és használatával elkerülheti, hogy ismétlődő üzenetekkel elárasztsa a hibaablakot. Például:

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( ... ); }

A szorzások érvényesítése

A minimális szorzás ellenőrzésére szolgáló érvényesítési módszerek automatikusan létrejönnek a DSL-hez. A kód a Dsl\Generated Code\MultiplicityValidation.cs fájlba van írva. Ezek a módszerek akkor lépnek érvénybe, ha engedélyezi az érvényesítést a Szerkesztő\Ellenőrzés csomópontban a DSL Explorerben.

Ha a tartománykapcsolatok szerepköreinek szorzását 1..* vagy 1..1 értékre állítja, de a felhasználó nem hoz létre kapcsolatot, érvényesítési hibaüzenet jelenik meg.

Ha például a DSL személy és város osztályokkal rendelkezik, és a PersonLivesInTown kapcsolat 1..\* kapcsolattal rendelkezik a Város szerepkörben, akkor minden olyan személynél, akinek nincs városa, hibaüzenet jelenik meg.

Érvényesítés futtatása a programkódból

Az ellenőrzést egy ValidationController elérésével vagy létrehozásával futtathatja. Ha azt szeretné, hogy a hibák megjelenjenek a felhasználó számára a hibaablakban, használja a diagram DocData-fájljához csatolt ValidationControllert. Ha például egy menüparancsot ír, CurrentDocData.ValidationController a parancskészlet osztályban érhető el:

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;
...

További információért lásd a következőt: Parancs hozzáadása a helyi menühöz.

Létrehozhat egy külön érvényesítési vezérlőt is, és saját maga kezelheti a hibákat. Például:

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) { ... }
}

Ellenőrzés futtatása módosítás esetén

Ha meg szeretné győződni arról, hogy a rendszer azonnal figyelmezteti a felhasználót, ha a modell érvénytelenné válik, megadhat egy érvényesítést futtató tárolóeseményt. További információ az áruházi eseményekről a következőben található: Event Handlers Propagate Changes Outside the Model.

Az érvényesítési kód mellett adjon hozzá egy egyéni kódfájlt a DslPackage-projekthez az alábbi példához hasonló tartalommal. Ez a kód a ValidationController dokumentumhoz csatolt kódot használja. Ez a vezérlő megjeleníti az érvényesítési hibákat a Visual Studio hibalistájában.

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);
    }
  }
}

A kezelőket a csatolásokat vagy elemeket érintő visszavonási vagy újraműveletek után is meghívja a rendszer.

Egyéni érvényesítési kategóriák

A szokásos érvényesítési kategóriákon (például a Menün és a Megnyitáson) kívül saját kategóriákat is meghatározhat. Ezeket a kategóriákat a programkódból hívhatja meg. A felhasználó közvetlenül nem tudja meghívni őket.

Az egyéni kategóriák jellemző használata egy olyan kategória definiálása, amely ellenőrzi, hogy a modell megfelel-e egy adott eszköz előfeltételeinek.

Ha egy érvényesítési metódust szeretne hozzáadni egy adott kategóriához, az előtagot az alábbi attribútummal kell ellátnia:

[ValidationMethod(CustomCategory = "PreconditionsForGeneratePartsList")]
[ValidationMethod(ValidationCategory.Menu)]
private void TestForCircularLinks(ValidationContext context)
{...}

Megjegyzés:

A metódusokat tetszőleges számú [ValidationMethod()] attribútummal előtaggal lehet előtagolni. Testreszabott és standard kategóriákhoz is hozzáadhat metódust.

Egyéni ellenőrzés meghívása:


// Invoke all validation methods in a custom category:
validationController.ValidateCustom
  (store, // or a list of model elements
   "PreconditionsForGeneratePartsList");

Az érvényesítés alternatívái

Az érvényességi korlátozások hibát jeleznek, de nem módosítják a modellt. Ha ehelyett meg szeretné akadályozni a modell érvénytelenné válását, más technikákat is használhat.

Ezek a technikák azonban nem ajánlottak. Általában jobb, ha hagyja, hogy a felhasználó döntse el, hogyan javítsa ki az érvénytelen modellt.

Módosítsa a módosítást a modell érvényességének visszaállításához. Ha például a felhasználó egy tulajdonságot állít be az engedélyezett maximális érték fölé, visszaállíthatja a tulajdonságot a maximális értékre. Ehhez definiáljon egy szabályt. További információ: Szabályok A változások propagálása a modellen belül.

Ha érvénytelen módosítást kísérel meg, állítsa vissza a tranzakciót. Erre a célra is definiálhat egy szabályt, de bizonyos esetekben felül lehet bírálni egy OnValueChanging() tulajdonságkezelőt, vagy felül lehet bírálni egy olyan módszert, mint például OnDeleted().. A tranzakció visszaállításához használja this.Store.TransactionManager.CurrentTransaction.Rollback().. További információért lásd: Tartománytulajdonság értékváltozás-kezelői.

Figyelmeztetés

Győződjön meg arról, hogy a felhasználó tudja, hogy a módosítást módosították vagy visszaállították. Például: System.Windows.Forms.MessageBox.Show("message").