Практическое руководство. Определение ограничений проверки для моделей UML

В Visual Studio Ultimate можно определять ограничения проверок, которые проводятся с целью убедиться, что модель соответствует заданным условиям.Например, можно задать ограничение, которое позволяет запретить пользователю создавать цикл отношений наследования.Ограничение вызывается, когда пользователь пытается открыть модель, кроме того, его можно вызвать вручную.Если происходит сбой ограничения, определенное пользователем сообщение об ошибке добавляется в окно ошибок.Эти ограничения можно упаковать в Visual Studio Integration Extension (VSIX) и распространять другим пользователям Visual Studio Ultimate.

Кроме того, можно определить ограничения, проверяющие модель на соответствие внешним ресурсам, например базам данных.

ПримечаниеПримечание

Если требуется проверить код программы по схеме слоев, см. раздел Добавление пользовательской проверки архитектуры в схемы слоев.

Требования

Применение ограничений проверки

Ограничения проверки применяются в трех случаях: при сохранении или открытии модели и при выборе пункта Проверить модель UML в меню Архитектура.В каждом случае применяются только ограничения, определенные для соответствующего случая, хотя, как правило, каждое ограничение определяется для использования в нескольких случаях.

Сведения о ошибках проверки отображаются в окне ошибок Visual Studio. Чтобы выбрать элементы модели, содержащие ошибки, нужно дважды щелкнуть ошибку.

Дополнительные сведения о проведении проверок см. в разделе Проверка модели UML.

Определение расширения проверки

Чтобы создать расширение проверки для конструктора UML, необходимо создать класс, определяющий ограничения проверки, и внедрить этот класс в расширение Visual Studio Integration Extension (VSIX).Расширение VSIX выполняет роль контейнера, позволяющего установить ограничение.Предусмотрено два альтернативных способа определения расширения проверки.

  • Создайте расширение проверки в его собственном расширении VSIX с помощью шаблона проекта. Этот метод является более быстрым.Используйте его, если не требуется объединять ограничения проверки с другими типами расширений, такими как команды меню, пользовательские элементы панели элементов или обработчики жестов.В одном классе можно определить несколько ограничений.

  • Создайте отдельный класс проверки и проекты VSIX. Этот метод следует использовать, если требуется объединить несколько типов расширений в одном VSIX-файле.Например, если для команды меню требуется, чтобы в модели соблюдались определенные ограничения, команду меню можно внедрить в то же расширение VSIX, что и метод проверки.

Создание расширения проверки в его собственном расширении VSIX

  1. В диалоговом окне Создать проект в разделе Проекты моделирования выберите Расширение проверки.

  2. Откройте файл .cs в новом проекте и внесите в класс изменения, реализующие ограничение проверки.

    Дополнительные сведения см. в разделе Реализация ограничения проверки.

    Важное примечаниеВажно

    Убедитесь, что ваши файлы .cs содержат следующую инструкцию using.

    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;

  3. В этот проект можно добавлять дополнительные ограничения, определяя новые методы.Чтобы идентифицировать метод как метод проверки, он должен быть помечен атрибутами таким же образом, как и исходный метод проверки.

  4. Проверьте ограничения, нажав клавишу F5.Дополнительные сведения см. в разделе Выполнение проверки.

  5. Установите команду меню на другой компьютер, скопировав файл bin\*\*.vsix, построенный вашим проектом.Дополнительные сведения см. в разделе Установка ограничений проверки.

При добавлении других файлов .cs обычно требуется следующая инструкция using.

using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.Modeling.Validation;
using Microsoft.VisualStudio.Uml.Classes;

Альтернативная процедура:

Создание отдельного ограничения проверки в проекте библиотеки классов

  1. Создайте проект библиотеки классов либо добавив его в существующее решение VSIX, либо создав новое решение.

    1. В меню Файл выберите Создать, Проект.

    2. В разделе Установленные шаблоны разверните узел Visual C# или Visual Basic, а затем в центральном столбце выберите Библиотека классов.

  2. Создайте проект VSIX, если ваше решение еще его не содержит:

    1. В Обозреватель решений, в контекстном меню решения выберите Добавить, Создать проект.

    2. В разделе Установленные шаблоны разверните узел Visual C# или Visual Basic, а затем выберите пункт Расширение среды.В среднем столбце щелкните Проект VSIX.

  3. Сделайте проект VSIX автоматически загружаемым проектом решения.

    • В окне обозревателя решений в контекстном меню проекта VSIX выберите команду Назначить запускаемым проектом.
  4. Последовательно выберите source.extension.vsixmanifest, Содержимое, затем добавьте проект библиотеки классов в качестве компонента MEF:

    1. На вкладке Метаданные задайте имя VSIX.

    2. На вкладке Цели установки задайте Visual Studio Ultimate и Premium в качестве целевых объектов.

    3. На вкладке Активы выберите Создать и в диалоговом окне установите:

      Тип = Компонент MEF

      Источник = Проект в текущем решении

      Проект = Проект библиотеки классов

Определение класса проверки

  1. Эта операция не требуется, если класс проверки создан со своим собственным расширением VSIX из шаблона проекта проверки.

  2. В проекте класса проверки добавьте ссылки на следующие сборки .NET:

    Microsoft.VisualStudio.Modeling.Sdk.11.0

    Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml

    Microsoft.VisualStudio.Uml.Interfaces

    System.ComponentModel.Composition

  3. Добавьте файл в проект библиотеки классов, содержащий код, аналогичный показанному в следующем примере.

    • Каждое ограничение проверки содержится в методе, помеченном специальным атрибутом.Метод принимает параметр типа элемента модели.При проверке рабочая среда проверки применяет каждый метод проверки к каждому элементу модели, соответствующему типу параметра метода.

    • Эти методы можно помещать в любые классы и пространства имен.Измените их в соответствии со своими предпочтениями.

    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.Linq;
    using Microsoft.VisualStudio.Modeling.Validation;
    using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
    using Microsoft.VisualStudio.Uml.Classes;
    // You might also need the other Microsoft.VisualStudio.Uml namespaces.
    
    namespace Validation
    {
      public class MyValidationExtensions
      {
        // SAMPLE VALIDATION METHOD.
        // All validation methods have the following attributes.
        [Export(typeof(System.Action<ValidationContext, object>))]
        [ValidationMethod(
           ValidationCategories.Save
         | ValidationCategories.Open
         | ValidationCategories.Menu)]
        public void ValidateClassNames
          (ValidationContext context, 
           // This type determines what elements 
           // will be validated by this method:
           IClass elementToValidate)
        {
          // A validation method should not change the model.
    
          List<string> attributeNames = new List<string>();
          foreach (IProperty attribute in elementToValidate.OwnedAttributes)
          {
            string name = attribute.Name;
            if (!string.IsNullOrEmpty(name) && attributeNames.Contains(name))
            {
              context.LogError(
                string.Format("Duplicate attribute name '{0}' in class {1}", name, elementToValidate.Name),
                "001", elementToValidate);
            }
            attributeNames.Add(name);
          }
    
        }
        // Add more validation methods for different element types.
      }
    }
    

Выполнение ограничения проверки

В целях проверки следует выполнять методы проверки в режиме отладки.

Тестирование ограничений проверки

  1. Нажмите F5, или в меню Отладка, выберите пункт Начать отладку.

    Запустится экспериментальный экземпляр Visual Studio.

    Устранение неполадок. Если новый экземпляр Visual Studio не запускается.

    • Если имеется более одного проекта, убедитесь, что проект VSIX назначен запускаемым проектом решения.

    • В обозревателе решений в контекстном меню запускамого или единственного проекта выберите команду Свойства.В редакторе свойств проекта перейдите на вкладку Отладка.Проверьте, что строка в поле Запуск внешней программы является полным путем к Visual Studio; обычно она имеет следующий вид:

      C:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe

  2. В экспериментальном экземпляре Visual Studio откройте или создайте проект моделирования и откройте или создайте схему моделирования.

  3. Для настройки проверки на простые ограничения, указанные в предыдущем разделе, выполните следующие действия.

    1. Откройте схему классов.

    2. Создайте класс и добавьте два атрибута с одинаковыми именами.

  4. В контекстном меню в любом месте схемы выберите Проверить.

  5. Любые ошибки модели будут отражены в окне ошибок.

  6. Щелкните дважды отчет об ошибках.Если элементы, упомянутые в отчете, видны на экране, они будут выделены.

    Устранение неполадок. Если команда Проверить не появилась в меню, убедитесь в следующем:

    • Проект проверки указан в качестве компонента MEF на вкладке Активы в source.extensions.manifest в проекте VSIX;

    • к методам проверки присоединены верные атрибуты Export и ValidationMethod;

    • метод ValidationCategories.Menu присутствует среди аргументов атрибута ValidationMethod и соединен с другими аргументами с помощью логического ИЛИ (|);

    • параметры всех атрибутов Import и Export являются допустимыми;

Оценка ограничения

Метод проверки должен определять, какое значение имеет ограничение проверки, которое хочет использовать пользователь — true или false.Если значение true, ограничение не должно ничего делать.Если значение false, ограничение должно создать отчет об ошибке с использованием методов, предоставленных параметром ValidationContext.

ПримечаниеПримечание

Методы проверки не должны изменять модель.Невозможно задать время или последовательность выполнения ограничений.Если необходимо передать сведения между последовательными выполнениями метода проверки в ходе проверки, можно использовать контекстный кэш, описанный в разделе Согласование нескольких проверок.

Например, если необходимо убедиться, что каждый тип (класс, интерфейс или перечислитель) имеет имя не короче трех символов, можно воспользоваться следующим методом.

public void ValidateTypeName(ValidationContext context, IType type)
{
  if (!string.IsNullOrEmpty(type.Name) && type.Name.Length < 3)
  {
    context.LogError(
      string.Format("Type name {0} is too short", type.Name),
               "001", type);
   }
 }

Сведения о методах и типах, которые можно использовать для перехода по модели и чтения модели, см. в разделе Программирование с UML API.

Ee329482.collapse_all(ru-ru,VS.110).gifО методах ограничения проверки

Каждое ограничение проверки определяется методом следующей формы.

[Export(typeof(System.Action<ValidationContext, object>))]
 [ValidationMethod(ValidationCategories.Save 
  | ValidationCategories.Menu 
  | ValidationCategories.Open)]
public void ValidateSomething
  (ValidationContext context, IClassifier elementToValidate)
{...}

Каждый метод проверки имеет следующие атрибуты и параметры.

[Export(typeof(System.Action <ValidationContext, object>))]

Определяет метод как ограничение проверки с использованием Managed Extensibility Framework (MEF).

[ValidationMethod (ValidationCategories.Menu)]

Задает время выполнения проверки.Используйте побитовое ИЛИ (|), если нужно объединить несколько параметров.

Menu = вызывается из меню "Проверка".

Save = вызывается при сохранении модели.

Open = вызывается при открытии модели.Load = вызывается при сохранении модели, но в случае какого-либо нарушения предупреждает пользователя о потенциальной невозможности повторного открытия модели.Также выполняется при загрузке, до того, как модель будет проанализирована.

public void ValidateSomething

(ValidationContext context,

IElement element)

Замените второй параметр IElement типом элемента, к которому должно применяться ограничение.Метод ограничения будет вызываться для всех элементов заданного типа.

Имя метода не имеет значения.

Можно определить сколько угодно методов проверки с разными типами в качестве второго параметра.При проверке каждый метод проверки вызывается для каждого элемента модели, соответствующего типу параметра.

Ee329482.collapse_all(ru-ru,VS.110).gifСоздание отчетов об ошибках проверки

Чтобы создать отчет об ошибке, используйте методы, предоставленные ValidationContext.

context.LogError("error string", errorCode, elementsWithError);

  • "error string" отображается в списке ошибок Visual Studio.

  • errorCode — это строка, которая должна быть уникальным идентификатором ошибки.

  • elementsWithError обозначает элементы в модели.При двойном нажатии на отчет об ошибке выделяется фигура, представляющая этот элемент.

LogError(),LogWarning() и LogMessage() размещают сообщения в разных разделах списка ошибок.

Применение методов проверки

Проверяется каждый элемент в модели, включая отношения и части более крупных элементов, таких как атрибуты класса и параметры операции.

Каждый метод проверки применяется к каждому элементу, соответствующему указанному типу элемента по второму параметру.Это значит, что если, например, определить один метод проверки с помощью второго параметра IUseCase, а другой метод — с помощью его супертипа IElement, оба метода будут применяться к каждому варианту использования в модели.

Иерархию типов см. в разделе Типы элементов модели.

Кроме того, для доступа к элементам можно использовать следующие отношения.Например, при необходимости определить метод проверки для IClass, нужно выполнить цикл с использованием принадлежащих ему свойств.

public void ValidateTypeName(ValidationContext context, IClass c)
{
   foreach (IProperty property in c.OwnedAttributes)
   {
       if (property.Name.Length < 3)
       {
            context.LogError(
                 string.Format(
                        "Property name {0} is too short", 
                        property.Name), 
                 "001", property);
        }
   }
}

Ee329482.collapse_all(ru-ru,VS.110).gifСоздание метода проверки для модели

Если нужно обеспечить однократный вызов метода проверки при каждом запуске, можно проверить объект IModel.

using Microsoft.VisualStudio.Uml.AuxiliaryConstructs; ...
[Export(typeof(System.Action<ValidationContext, object>))]
[ValidationMethod(ValidationCategories.Menu)]
public void ValidateModel(ValidationContext context, IModel model)
{  foreach (IElement element in model.OwnedElements)
   { ...

Ee329482.collapse_all(ru-ru,VS.110).gifПроверка фигур и схем

Методы проверки не вызываются для отображаемых элементов (схем и фигур), так как основной задачей методов проверки является проверка модели.Доступ к текущей схеме, однако, можно получить через контекст схемы.

В классе проверки объявите DiagramContext импортированным свойством.

using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation; 
...
[Import]
public IDiagramContext DiagramContext { get; set; }

В методе проверки для доступа к текущей фокусной схеме (при наличии) можно воспользоваться DiagramContext.

[Export(typeof(System.Action<ValidationContext, object>))]
[ValidationMethod(ValidationCategories.Menu)]
public void ValidateModel(ValidationContext context, IModel model)
{
  IDiagram focusDiagram = DiagramContext.CurrentDiagram;
  if (focusDiagram != null)
  {
    foreach (IShape<IUseCase> useCaseShape in
              focusDiagram.GetChildShapes<IUseCase>())
    { ...

Чтобы записать ошибку в журнал, нужно получить элемент модели, представляемый фигурой, так как передать фигуру LogError невозможно.

       IUseCase useCase = useCaseShape.Element;
       context.LogError(... , usecase);

Ee329482.collapse_all(ru-ru,VS.110).gifСогласование нескольких проверок

При вызове проверки (например, пользователем из меню схемы) каждый метод проверки применяется к каждому элементу модели.Это означает, что в ходе одного вызова рабочей среды проверки один метод может несколько раз применяться к разным элементам.

Это препятствует правильному проведению проверок, обрабатывающих отношения между элементами.Например, можно создать проверку, которая начинается с варианта использования и перебирает отношения include, чтобы убедиться, что циклы отсутствуют.Но если этот метод применяется к каждому варианту использования в модели, имеющей много ссылок include, существует вероятность, что метод будет многократно обрабатывать одни и те же области модели.

Избежать этого позволяет использование контекстного кэша, в котором сохраняются сведения во время выполнения проверки.Его можно использовать для передачи сведений между различными выполнениями методов проверки.Например, можно сохранять список элементов, которые уже были обработаны в ходе этой проверки.Кэш создается в начале каждого выполнения проверки, его невозможно использовать для передачи сведений между разными выполнениями проверки.

context.SetCacheValue<T> (name, value)

Сохранение значения

context.TryGetCacheValue<T> (name, out value)

Получение значения.Возвращает значение true, если операция завершилась удачно.

context.GetValue<T>(name)

Получение значения.

Context.GetValue<T>()

Получение значения заданного типа.

Установка и удаление расширения

Расширение Visual Studio можно установить как на своем компьютере, так и на других.

Установка расширения

  1. Найдите на компьютере файл .vsix, который был создан проектом VSIX.

    1. В Обозреватель решений, в контекстном меню проекта VSIX выберите Открыть папку в проводнике Windows.

    2. Найдите файл bin\*\Ваш_проект.vsix

  2. Скопируйте файл .vsix на конечный компьютер, на котором необходимо установить расширение.Это может быть ваш компьютер или любой другой.

    • На конечном компьютере должен быть установлен один из выпусков Visual Studio, заданный в source.extension.vsixmanifest.
  3. Откройте файл .vsix на конечном компьютере.

    Visual Studio Extension Installer откроет и установит расширение.

  4. Запустите или перезапустите Visual Studio.

Удаление расширения

  1. В меню Инструменты выберите пункт Диспетчер расширений.

  2. Разверните Установленные расширения.

  3. Выберите расширение и щелкните Удалить.

Иногда не удается загрузить ошибочное расширение. В этом случае создается отчет в окне ошибок, но расширение не отображается в диспетчере расширений.В этом случае расширение можно удалить, удалив файл из следующего расположения, где %LocalAppData% — это обычно ИмяДиска:\Users\ИмяПользователя\AppData\Local:

%LocalAppData%\Microsoft\VisualStudio\11.0\Extensions

Пример

В этом примере демонстрируется поиск циклов в отношении зависимости между элементами.

Проверка проводится при сохранении файла и выполнении команды проверки в меню.

/// <summary>
/// Verify that there are no loops in the dependency relationsips.
/// In our project, no element should be a dependent of itself.
/// </summary>
/// <param name="context">Validation context for logs.</param>
/// <param name="element">Element to start validation from.</param>
[Export(typeof(System.Action<ValidationContext, object>))]
[ValidationMethod(ValidationCategories.Menu 
     | ValidationCategories.Save | ValidationCategories.Open)]
public void NoDependencyLoops(ValidationContext context, INamedElement element)
{
    // The validation framework will call this method
    // for every element in the model. But when we follow
    // the dependencies from one element, we will validate others.
    // So we keep a list of the elements that we don't need to validate again. 
    // The list is kept in the context cache so that it is passed
    // from one execution of this method to another.
    List<INamedElement> alreadySeen = null;
    if (!context.TryGetCacheValue("No dependency loops", out alreadySeen))
    {
       alreadySeen = new List<INamedElement>();
       context.SetCacheValue("No dependency loops", alreadySeen);
    }

    NoDependencyLoops(context, element, 
                new INamedElement[0], alreadySeen);    
}

/// <summary>
/// Log an error if there is any loop in the dependency relationship.
/// </summary>
/// <param name="context">Validation context for logs.</param>
/// <param name="element">The element to be validated.</param>
/// <param name="dependants">Elements we've followed in this recursion.</param>
/// <param name="alreadySeen">Elements that have already been validated.</param>
/// <returns>true if no error was detected</returns>
private bool NoDependencyLoops(ValidationContext context, 
    INamedElement element, INamedElement[] dependants, 
    List<INamedElement> alreadySeen)
{
    if (dependants.Contains(element))
    {
        context.LogError(string.Format("{0} should not depend on itself", element.Name), 
        "Fabrikam.UML.NoGenLoops", // unique code for this error
        dependants.SkipWhile(e => e != element).ToArray()); 
            // highlight elements that are in the loop
        return false;
    }
    INamedElement[] dependantsPlusElement = 
        new INamedElement[dependants.Length + 1];
    dependants.CopyTo(dependantsPlusElement, 0);
    dependantsPlusElement[dependantsPlusElement.Length - 1] = element;

    if (alreadySeen.Contains(element))
    {
        // We have already validated this when we started 
        // from another element during this validation run.
        return true;
    }
    alreadySeen.Add(element);

    foreach (INamedElement supplier in element.GetDependencySuppliers())
    {
        if (!NoDependencyLoops(context, supplier,
             dependantsPlusElement, alreadySeen))
        return false;
    }
    return true;
}

См. также

Основные понятия

Практическое руководство. Определение и установка расширения моделирования

Программирование с UML API