目录

介绍

为什么要使用它?

分布式系统的端到端跟踪

调试器

背景

使用代码

示例

如何使用控件

怎么运行的

Tick()方法

元素渲染

API引用

顺序

参加者

消息

激活

方框

SequenceDiagramControl + AOP库=调试器

兴趣点

顺序图特征未实现

PlantUML

NConcern和CNeptune


本文介绍了一个Windows .NET控件,用于以UML顺序图的形式动态可视化对象及其交互。该控件具有类似于调试器的中断功能。另外,它提供了一个实际使用的示例,其中实时拦截和可视化了应用程序的执行。

  • 下载源1.2 MB

介绍

顺序图是UML图的基本类型之一。他们的重点是对系统进行动态建模。它们允许描述系统与环境参与者之间或系统参与者之间随着时间的推移的交互作用。它们清晰的图形布局有助于快速直观地了解系统的行为。

本文介绍了一个Windows .NET控件,用于动态对象可视化及其相互作用(作为顺序图)。该控件具有类似于调试器的中断功能。另外,它提供了一个实际使用的示例,其中实时拦截和可视化了应用程序的执行。

为什么要使用它?

这是使用控件的两种情况:

分布式系统的端到端跟踪

您有一个分布在不同计算机上的,由独立组件(例如微服务)组成的分布式应用程序,很难跟踪整个执行过程。您将每个微服务的日志事件转发到收集器,以便可以在单个顺序图中可视化整个流程,以便于分析和调试:

该控件最初是为这种情况创建的,并构成其一部分。将其重新打包以用于通用用途。

调试器

您已经开发了一种软件工具,可以使用AOP(面向切面​​的编程)技术来拦截任何.NET应用程序的方法调用,现在您希望将捕获的调用跟踪可视化为流程图:

在本文结尾处,我提供了这种用法的概念证明。

背景

顺序图显示了对象的行为。因此,时间的概念以及对象之间的依赖关系出现在顺序图中。反过来,这使顺序图可以显示系统中的“情况”。

顺序图的大多数现有用法仅限于静态模型:顺序图基于模型或静态代码的定义。它们充当流程的蓝图,并用于在系统内进行交互。

但是,顺序图也可以用于可视化系统的实时活动。此活动可能是计算机程序中的实时方法调用,分布式应用程序组件内的通信等等。动态分析与静态分析的不同之处在于,它需要一个活动的系统进行建模。即,在运行的系统上执行动态分析,而在系统工件(例如源代码)上执行静态分析。

使用代码

示例

SequenceDiagram解决方案包含两个项目:SequenceDiagramLib具有实际控件,而SequenceDiagramTestApp项目具有演示控件功能的各种示例。

除了一个示例外,所有示例都完全在主线程中运行。底部包含“基本示例(线程)”示例,用于在不同线程中修改序列的情况。

下面是一个简单的顺序图定义,涉及两个参与者以及他们之间的一些消息传递:

Sequence sequence = this.sequenceControl.Sequence;Participant alice = sequence.Participants.Create("Alice");
Participant bob = sequence.Participants.Create("Bob");
sequence.Messages.Add("AuthenticationRequest", alice, bob);
sequence.Tick();sequence.Messages.Add("AuthenticationResponse", bob, alice, dashStyle: DashStyle.Dash);
sequence.Tick();sequence.Messages.Add("Another authentication request", alice, bob);
sequence.Tick();sequence.Messages.Add("Another authentication Response", bob, alice);
sequence.Tick();

该序列由SequenceDiagramControl呈现:

控件用水平线表示时间的流逝。每条水平线表示一个时间刻度,而当前时间标记则表示为红线。

第二个更复杂的顺序图定义了我们的SequenceDiagramControl:

Sequence sequence = this.sequenceControl.Sequence;Participant user = sequence.Participants.Create("User");
Participant a = sequence.Participants.Create("A");
Participant b = sequence.Participants.Create("B");
Participant c = sequence.Participants.Create("C");
sequence.Messages.Add("DoWork", user, a);
a.Activate();
sequence.Tick();sequence.Messages.Add("<< createRequest >>", a, b);
b.Activate();
sequence.Tick();sequence.Messages.Add("DoWork", b, c);
c.Activate();
sequence.Tick();sequence.Messages.Add("WorkDone", c, b, dashStyle: DashStyle.Dot);
c.Deactivate();
c.Destroy();
sequence.Tick();sequence.Messages.Add("RequestCreated", b, a, dashStyle: DashStyle.Dot);
b.Deactivate();
sequence.Tick();sequence.Messages.Add("Done", a, user);
a.Deactivate();
sequence.Tick();

...以及SequenceDiagramControl的演绎:

如何使用控件

1、创建一个名为Form1的Windows窗体。

2、在表单中添加一个SequenceDiagramControl名称为sequenceDiagram。

3、将两个按钮添加到您的窗体。他们的名字为runButton和continueButton。

4、设置两个按钮的处理程序。

runButton的事件处理程序会创建一个包含两个参与者和两个时间步长的序列:

private void runButton_Click(object sender, EventArgs e)
{Sequence sequence = this.sequenceDiagram.Sequence;Participant a = sequence.Participants.CreateOrGet("A");Participant b = sequence.Participants.CreateOrGet("B");sequence.Messages.Add("Create request", a, b);sequence.Tick();sequence.Messages.Add("Return", b, a);sequence.Tick();
}

当序列处于等待状态时,continueButton的事件处理程序可用。它的功能是恢复应用程序的执行。

private void continueButton_Click(object sender, EventArgs e)
{Sequence sequence = this.sequenceDiagram.Sequence;sequence.Continue();
}

5、定义序列的OnEnter()和OnExit()事件处理程序。

该序列在中断开始时调用OnEnterBreak()事件处理程序,并在执行恢复时调用OnExitBreak()事件处理程序。

private void Sequence_OnEnterBreak()
{this.runButton.Enabled = false;this.continueButton.Enabled = true;
}private void Sequence_OnExitBreak()
{this.runButton.Enabled = true;this.continueButton.Enabled = false;
}

6、窗体的构造函数初始化两个按钮的启用/禁用状态,并设置序列事件处理程序。

public Form1()
{InitializeComponent();this.runButton.Enabled = true;this.continueButton.Enabled = false;Sequence sequence = this.sequenceDiagram.Sequence;sequence.OnEnterBreak += Sequence_OnEnterBreak;sequence.OnExitBreak += Sequence_OnExitBreak;
}

怎么运行的

该控件包含对Sequence类的引用,该类封装了序列的全部信息。诸如参与者,激活,消息,时间步之类的元素存储在此类的实例中。

Tick()方法

在同一时间范围内发生的事件将以任意顺序添加到序列中。sequence.Tick()调用特别重要:正是在这些调用中:

  1. 发生中断事件并且SequenceDiagramControl抓住程序执行,直到用户采取行动以恢复。
  2. 序列的逻辑时钟增加1。

断点功能的实现细节如下:

  1. 每当调用sequence.Tick()方法时,基础Sequence对象都会调用其注册的OnEnterBreak()处理程序。这将启用其父窗体以执行诸如启用其continueButton的任务。
  2. 使用以下方法,序列保持等待状态:
private void ResponsiveWait()
{this.wait = true;for (;;){if (!this.wait)break;if (this.exit)break;System.Windows.Forms.Application.DoEvents();System.Threading.Thread.Sleep(200);}
}

Application.DoEvent()允许在不阻塞自身或其所在应用程序的情况下获取执行流。不鼓励使用Application.DoEvents(),而应使用其他技术,如线程。但是对于该项目的需求(例如对调试后的应用程序的干扰最小),我发现它是最合适的方法。

  1. 当用户单击时continueButton,将调用sequence.Continue()方法,等待状态结束。
  2. 序列类调用已注册的OnExitBreak()事件处理程序。这将启用其父窗体执行任务,例如禁用其continueButton,直到下一次中断。

元素渲染

元素的视觉呈现在SequenceDiagramControl类中进行。每个UML元素都有一个方法和一个名为p0的参考点变量。

API引用

Sequence类是SequenceDiagramControl的数据模型的基础对象。有关序列的所有信息都存储在此类中。它具有可用参与者、激活、消息和框的集合。

Box是对相关参与者进行分组的可选元素。

Participant拥有一个激活集合,每个激活都有一个称为标签的名称/值对集合。参与者通过Message进行交流。

顺序

Sequence类封装序列内的全部数据。它着重于参与者之间消息的时间顺序以及消息的发送顺序。顺序中的重点是第一件发生的事情,然后发生第二件事,依此类推。

API用法


sequence.Clear();

清除当前状态和序列的所有成员。序列返回到其初始状态。


sequence.Tick();

顺序图的重点是可视化系统的变化以及随时间推移的元素通信。x轴显示序列的成员(称为参与者),而y轴表示时间。

在SequenceDiagramControl模型中,时间标记表示为离散值。每当出现时间刻度时,序列都会前进到下一个时间步长值。时间刻度是用户可以做出响应的中断点。


参加者

参与者是参与序列的代表或对象。它们通常放在图的顶部。参与者通常以矩形表示,其名称放在框中。根据UML规范,此名称可以带下划线,表示参与者在顺序图中表示类的特定实例。诸如UML构造型之类的其他信息也可以包含在参与者矩形内。

参与者的生命线从参与者的底部开始显示为垂直虚线。它们代表了参与者随着时间的生命周期和互动。

Participant foo1 = sequence.Participants.Create("Foo1", type: EParticipantType.Actor);
Participant foo2 = sequence.Participants.Create("Foo2", type: EParticipantType.Boundary);
Participant foo3 = sequence.Participants.Create("Foo3", type: EParticipantType.Control);
Participant foo4 = sequence.Participants.Create("Foo4", type: EParticipantType.Entity);
Participant foo5 = sequence.Participants.Create("Foo5", type: EParticipantType.Database);
Participant foo6 = sequence.Participants.Create("Foo6", type: EParticipantType.Collections);
sequence.Messages.Add("To boundary", foo1, foo2);
sequence.Tick();sequence.Messages.Add("To control", foo1, foo3);
sequence.Tick();sequence.Messages.Add("To entity", foo1, foo4);
sequence.Tick();sequence.Messages.Add("To database", foo1, foo5);
sequence.Tick();sequence.Messages.Add("To collections", foo1, foo6);
sequence.Tick();

API用法

Participant participant = sequence.Participants.Create(string name, bool underlined = false,
Color? color = null, Color? textColor = null, EParticipantType? type = null, Box box = null,
bool createNow = false);

它创建一个新的参与者并将其放置在序列中。如果序列中已有指定名称的参与者,则调用失败。

  • name:参与者名称。
  • underlined:参与者的姓名是否将显示为带下划线的文本。UML中带下划线的文本表示类的特定实例。
  • color:参与者的背景色。
  • textColor:参与者的文字颜色。
  • type:参与者的类型。它影响参与者的显示方式(方框,边界,控件,实体,数据库,集合)。
  • box:参与者所属的方框。此值可能是null。
  • createNow:通常会省略此值,从而导致参与者位于图的顶部。设置此值将强调正在创建参与者,并且其生存期将从当前时间步开始。

Participant participant = sequence.Participants.CreateOrGet
(string name, bool underlined = false, Color? color = null, Color? textColor = null,
EParticipantType? type = null, Box box = null, bool createNow = false);

如果存在具有给定名称的参与者,则将其返回。

如果不存在具有给定名称的参与者,它将创建一个新参与者,将其放置在序列中,然后返回。

  • name:参与者名称。
  • underlined:参与者的姓名是否将显示为带下划线的文本。UML图中带下划线的文本表示类的特定实例。
  • color:参与者的背景色。
  • textColor:参与者的文字颜色。
  • type:参与者的类型。它影响参与者的显示方式(方框,边界,控件,实体,数据库,集合)。
  • box:参与者所属的方框。此值可能是null。
  • createNow:忽略此值,导致参与者被放置在图的顶部。设置此值将强调正在创建参与者,并且其生存期将从当前时间步开始。

Participant participant = sequence.Participants[name];

它返回给定名称的参与者。如果不存在具有给定名称的参与者,则调用失败。

  • name:参与者名称。

participant.Destroy();

结束参与者的当前激活状态。


消息

消息代表两个参与者之间传输的信息。参与者可能会向自己发送消息。消息可以是同步的也可以是异步的,它们可以反映操作的开始和执行或信号的发送和接收。

Participant bob = sequence.Participants.Create("Bob");
Participant alice = sequence.Participants.Create("Alice");
sequence.Messages.Add("hello", bob, alice, color: Color.Red);
sequence.Tick();sequence.Messages.Add("ok", alice, bob, color: Color.Blue);
sequence.Tick();
Participant alice = sequence.Participants.Create("Alice");
sequence.Messages.Add("signal to self", alice);
sequence.Tick();

API用法

Message message = sequence.Messages.Add(string name, Participant from,
Participant to, Color? color = null, DashStyle? dashStyle = null);

在源参与者和目标参与者之间创建新消息。

  • name:消息名称。
  • from:消息的源参与者。
  • to:消息的目标参与者。
  • color:呈现消息的颜色。
  • arrowHead:消息的箭头。不同的箭头代表不同类型的消息。
  • dashStyle:消息行的短划线样式。不同的破折号样式表示不同类型的消息。

Message message = sequence.Messages.Add(string name, Participant self,
Color? color = null, DashStyle? dashStyle = null);

创建一个新的自消息。参与者向自己发送一条消息。

  • name:消息名称。
  • self:消息的所有者。
  • color:呈现消息的颜色。
  • arrowHead:消息的箭头。不同的箭头代表不同类型的消息。
  • dashStyle:消息行的短划线样式。不同的破折号样式表示不同类型的消息。

激活

激活(也称为控制元素/执行焦点)是参与者执行操作的时间段。对象忙于执行过程或等待回复的时间表示为垂直放置在其生命线上的矩形。矩形的顶部和底部分别与开始时间和完成时间对齐。激活可以是递归的。

Participant user = this.sequence.Participants.Create("User");
Participant a = this.sequence.Participants.Create("A");
Participant b = this.sequence.Participants.Create("B");
sequence.Messages.Add("DoWork", user, a);
a.Activate(color: Color.FromArgb(0xff, 0xbb, 0xbb));
sequence.Tick();sequence.Messages.Add("Internal call", a);
a.Activate(color: Color.DarkSalmon);
sequence.Tick();sequence.Messages.Add("<< createRequest >>", a, b);
b.Activate();
sequence.Tick();sequence.Messages.Add("RequestCreated", b, a, dashStyle: DashStyle.Dash);
b.Deactivate();
a.Deactivate();
sequence.Tick();sequence.Messages.Add("Done", a, user);
a.Deactivate();
sequence.Tick();

API用法

participant.Activate(string name = null, Color? color = null);

为参与者初始化激活。激活可以是递归的。

  • name:激活名称。
  • color:激活的背景色。

participant.Deactive();

停用参与者的当前激活。


方框

方框有助于组织顺序图。相互关联的参与者可以分组在一个框中。

Box box = sequence.Boxes.Create("Internal Service");
box.Color = Color.LightBlue;
Participant bob = sequence.Participants.Create("bob", box: box);
Participant alice = sequence.Participants.Create("alice", box: box);
Participant other = sequence.Participants.Create("other");
sequence.Messages.Add("hello", bob, alice);
sequence.Tick();sequence.Messages.Add("hello", alice, other);
sequence.Tick();

API用法

Box box = sequence.Boxes.Create(string name, Color? color = null);

它创建一个新框并将其放置在序列中。如果序列中已经有一个具有指定名称的框,则调用将失败。

  • name:框名称。
  • color:框的背景色。

Box box = sequence.Boxes.CreateOrGet(string name, Color? color = null);

如果存在具有给定名称的参与者,则将其返回。

如果不存在具有给定名称的参与者,它将创建一个新参与者,将其放置在序列中,然后返回。

  • name:框名称。
  • color:框的背景色。

Box box = sequence.Boxes[name];

它返回具有给定名称的框。如果不存在具有给定名称的框,则调用失败。

  • name:参与者名称。

SequenceDiagramControl + AOP库=调试器

SequenceDiagramDebugger不是SequenceDiagramControl的一部分。而是,它是对SequenceDiagramControl的具体实际使用的演示。除此之外,对于现有的AOP(面向方面​​编程)示例一直存在一种批评,即几乎所有示例都涉及方法调用的日志记录或访问控制。在这种情况下,AOP用于替代需求:执行可视化。

调试器示例用作概念证明,并具有诸如仅支持使用单个线程的应用程序之类的限制。

AOP启用应用程序的拦截方法。然后,这些被拦截的方法调用将通过SequenceDiagramControl可视化。使用控件的附加内置中断功能,可以调试应用程序的执行流程。

在应用程序和顺序图元素之间的映射如下实现:

  • 应用->顺序
  • 申请类别->参加者
  • 类方法持续时间->激活
  • 方法调用->消息

一个重要的目标是启用调试程序,而对主机应用程序的更改最少。这是通过向调试后的应用程序添加一行代码来实现的,以便我们的工具与之集成:

public MainForm()
{InitializeComponent();SequenceDiagramDebugger.Init(this, "TestApp.");
}

SequenceDiagramDebugger.Init(this, "TestApp"); 有两个目的:

  1. 它将已调试应用程序的所有方法编织在“TestApp”命名空间中。
  2. 它打开我们的DebuggerForm,其中包含一个SequenceDiagramControl。

在执行过程中,AOP库通过advisors通知我们方法入口和出口的每一次相关事件。这些被拦截的方法入口和出口然后在我们的SequenceDiagramControlbased中可视化SequenceDiagramDebugger。

在该示例中,单击一次TestApp的“计算”按钮,然后单击DebuggerForm的“继续”,直到执行结束。

兴趣点

顺序图特征未实现

UML顺序图规范的某些部分(例如表示循环,分支和替代执行流程的元素)仅在该图用于记录流程的文档时才有意义。在SequenceDiagramControl中省略了这些功能,因为控件的焦点是动态可视化已发生的事情,而不是可能发生的事情。

PlantUML

PlantUML是一种开放源代码工具,可帮助从符合其图定义语法的文本文件中创建各种类型的UML和非UML图。您可以使用工具的文本格式指定UML图表定义,而与SequenceDiagramControl不同,它会创建图表的静态图像表示形式。它支持序列、用例、类、活动、组件、状态、对象、部署和时间UML图,以及许多非UML图。

长期以来,我一直在使用PlantUML工具来获取技术文档,其易于使用的术语给我留下了深刻的印象。因此,我的设计目标之一就是尽可能地遵循PlantUML的元素命名,并比较相同序列的PlantUML和SequenceDiagramControl的表达。我提供的所有功能示例在PlantUml工具顺序图创建页面中都有一个对应的示例。

在本节中,我提供了PlantUML文本定义等效项以及我在本文开头描述的两个功能示例的输出,因此您可以比较它们的异同:

与第一个功能示例等效的PlantUML文本定义:

@startuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication ResponseAlice -> Bob: Another authentication Request
Alice <-- Bob: Another authentication Response
@enduml

当将此文本输入到PlantUML解析器时,您将获得以下(静态)顺序图:

这与我上面描述的第二个特征示例的PlantUML等效。

@startuml
participant UserUser -> A: DoWork
activate AA -> B: << createRequest >>
activate BB -> C: DoWork
activate C
C --> B: WorkDone
destroy CB --> A: RequestCreated
deactivate BA -> User: Done
deactivate A@enduml

其PlantUML输出为:

NConcern和CNeptune

NConcern和CNeptune是用于截取SequenceDiagramDebugger示例中外部应用程序的方法调用的AOP库。这些捕获的方法调用在SequenceDiagramControl 中可视化。这些库功能强大且设计合理:我能够以最小的努力将它们集成在一起。

NConcern提供了AOP的功能和API(例如advisors)。

CNeptune是基于mono.cecil的实用程序,用于重写.NET程序集以使其可注入。

动态顺序图可视化控件相关推荐

  1. 【storybook】你需要一款能在独立环境下开发组件并生成可视化控件文档的框架吗?(一)

    storybook 介绍 入门 说说用法 prop-types .stories.jsx 下一篇: https://blog.csdn.net/tuzi007a/article/details/129 ...

  2. 体验Dundas Dashboard数据可视化控件

    概述:Dundas公司开发的Dundas Dashboard是集所有需求于一体的商业智能仪表盘,这款仪表盘控件提供大量完全可定制的交互式图表.仪表.地图和记分卡等等,开启即可使用,这意味着您总能快捷方 ...

  3. 【storybook】你需要一款能在独立环境下开发组件并生成可视化控件文档的框架吗?(二)

    storybook 回顾 继续说说用法 配置文件介绍 回顾 上篇博客地址: https://blog.csdn.net/tuzi007a/article/details/129192502 说了部分用 ...

  4. unity UGUI系统梳理 - 常用可视化控件

    作为一名合格的UI仔>.<,我发现很多UI很久没有使用了,所以我决定做一个UGUI系列博客重新梳理一下 1.Image 在没有放入图片下,image控件长这样 注意 我一般没交互需求的情况 ...

  5. autojs可视化控件位置

    牙叔教程 简单易学 使用场景 当我们找控件的时候, 代码查找的结果, 可能不符合我们的预期, 这个时候, 最好就把找到的控件的位置, 显示在屏幕上面, 方便我们排查问题 显示位置的方式 可以是一个点, ...

  6. WPF实现可视化控件打印及打印预览

    打印预览XAML代码: <controls:WindowEx x:Class="SunCreate.Vipf.Client.UI.MapPrintPreview"xmlns= ...

  7. 【storybook】你需要一款能在独立环境下开发组件并生成可视化控件文档的框架吗?(三)

    storybook 插件addons 核心插件 插件API argTypes 写文档 组件注释法 MDX 生成在线可视化UI文档 上一篇: https://blog.csdn.net/tuzi007a ...

  8. WPF数据可视化控件(一) LED风格数字控件

    原帖地址:https://blog.csdn.net/zhuo_wp/article/details/81561190 资源源码:https://download.csdn.net/download/ ...

  9. easyui 动态设置单元格控件_动态显示最大最小值的折线图

    小伙伴们好啊,今天和大家分享一个图表有关的知识. 折线图想必大家已经司空见惯,今天就要在简单的折线上,做出不简单的效果. 用动态折线图,展示一周销售的变化,并且自动突出最大最小值. 1.准备数据源 以 ...

最新文章

  1. 7. U9成本核算基本流程概述
  2. 学习CTF(二进制安全)一个月多的奇妙冒险~;
  3. webpack 打包第三方库_webpack打包分离第三方库和业务代码
  4. c语言实现socket转json,C++解析JSON进行网络传输--一个通过JSON方式的socket传输
  5. Python猫荐书系列:文也深度学习,理也深度学习
  6. 【七】jmeter 连接 mysql 数据库(Jmeter 连接数据池)配置:JDBC Connection Configuration
  7. (扫盲)WebSocket 教程
  8. Windows 10 如何离线安装NetFx3
  9. 上班我是这样玩微信的,带你一起玩?
  10. 乒乓球单循环赛_乒乓球淘汰赛制和单循环赛制的比赛方法是什么?
  11. 红帽linux挑战赛题目,红帽Linux挑战赛模拟题
  12. 中文编码之GB2312,Big5,GBK简介
  13. Java实现自动发送电子邮件 发送邮件验证码(附全部源码)
  14. bzoj 3739 DZY loves math VIII
  15. Asp.Net之分页查询
  16. 快乐的牛奶商 c语言6,C语言程序设计基础实训手册
  17. [案例4-2]饲养员喂养动物
  18. 图像增强算法汇总(直方图均衡化、拉普拉斯、Log变换、gamma伽马变换)附MATLAB代码
  19. 面试题--小白鼠实验
  20. 大厂加持,元宇宙是炒作还是未来?

热门文章

  1. 用html5做一个介绍自己家乡的页面_厚溥资讯 | HTML5的小知识点小集合(上)
  2. 决策树 prepruning_决策树与随机森林
  3. 计算机d盘不显示容量,电脑D盘可用空间小,可是看不到文件
  4. 安卓设置原生alert设置圆角_安卓手机设置充电提示音全新最全教程
  5. python绘制折线图先对数据进行处理_python气象数据分析并绘制折线图-女性时尚流行美容健康娱乐mv-ida网...
  6. flink离线mysql_Flink 流模式跑离线任务
  7. mysql server出现_查询各阶段时,一旦mysql server出现各种故障下的表现形式
  8. 水果手绘插画素材|一眼就想吃了!
  9. 导航菜单UI设计中的作用,优秀案例临摹起来!
  10. UI超实用通用图标素材模板