AppDNA

分组转发路径报告

本主题概述了高级转发路径功能,您可以使用该功能按脚本中定义的类别(例如适合在特定平台上部署)或应用程序所属的 AppDNA 应用程序组对应用程序进行分组。您可以在组级别聚合应用程序值(例如,为每个组创建小计),并在报告级别创建合计。这意味着,例如,如果应用程序组代表业务部门,则可以创建“转发路径”报告,按业务部门对应用程序进行分组,并显示每个应用程序的小计。

概述

下图显示了一个转发路径报告的片段,其中应用程序已根据其 Windows 7 和 App-V 报告的 RAG 状态对应用程序进行分组。对于每个组,将显示修复的总成本以及组中应用程序的计数。您可以展开每个组以查看其中的应用程序。顶部的总行显示整个报告的总计。

转发路径报告图像

我们将在下面的示例中构建生成此报告的转发路径方案。为了使示例尽可能简单,我们将为每个应用程序使用硬编码的修复成本。在现实生活中,您可能会根据应用程序的复杂性和所需的修复来计算此值。有关以这种方式计算成本的示例,请参阅在正向路径方案中使用工作量计算器变量

设想方案功能

分组的转发路径报告的方案通常实现以下标准的转发路径函数:

  • Initialize() — AppDNA 在脚本开始时自动调用此函数一次。通常,此函数初始化变量。
  • ForwardPath() — 这是所有转发路径方案都必须实现的标准函数。AppDNA 为运行报告时选择的每个应用程序调用此函数一次。在分组的转发路径报告中,此函数创建应用程序放置到的类别(称为报告组)。报告组可以通过代码中的逻辑创建,也可以基于应用程序组应用程序已经属于的。
  • ProcessGroups() — AppDNA 为由 ForwardPath () 函数生成的每个报告组调用此函数一次。此函数定义组级别报告列及其包含的值。
  • GetGroupColumnSummary() — AppDNA 为在 ProcessGroups() 函数中定义的每个列调用此函数一次。通常,此函数定义报告级别的总计。
  • OnProcessingComplete() — 这是一个可选的函数,AppDNA 在所有其余处理完成后调用一次。您可以使用此函数在显示报告之前执行任何最终处理。

下图显示了 AppDNA 如何在运行报告时调用函数。图后面是每个高级功能的说明,以及一个示例,共同创建上述概述部分中显示的报告。

高级功能

注意:本主题中的一些示例使用下划线 (_) 表示法将长行分为两行或多行。这样,当包含在 PDF 中时,示例代码片段可以正确呈现。有关此符号 MSDN 库的更多信息,请参阅。

Initialize()

如果在场景中指定,AppDNA 会在脚本开始时自动调用一次Initialize() 函数。Initialize() 函数必须具有以下签名:

Public Overrides Sub Initialize()
   ' Enter your code here.
End Sub

在这个例子中,我们将使用 Initialize() 函数初始化变量,我们将使用这些变量来存储应用程序值,以便它们可以在组级别进行聚合。但是,首先我们必须声明我们想要在整个场景中使用的变量。因为我们将在多个函数中使用这些变量,所以我们将在脚本开始时(在 Initialize() 函数之前)定义它们,如下所示:

' Declare a Dictionary variable to store the remediation
' costs for each application in the group.
Private Dim costs As Dictionary(Of String, List(Of Integer)) _
   = New Dictionary(Of String, List(Of Integer))

' Declare string variables that store the names of the
' report groups.
Private Dim win7group As String = "Windows 7"
Private Dim appvgroup As String = "App-V"
Private Dim othergroup As String = "Retire"

在这个例子中,我们声明了一个名为成本的字典变量。有关MSDN 库此标准 .NET 类的文档,请参阅。字典变量可以存储键和值的集合。在此示例中,键是一个字符串(我们将使用它来存储报告组名称),值是整数列表(我们将使用它存储报告组中所有应用程序的修复成本)。请参MSDN 库阅 List 类的文档。

除了字典,我们还声明了三个字符串变量来存储我们将要创建的三个报告组的名称。

现在我们准备好实现 Initialize() 函数。这里是:

Public Overrides Sub Initialize()
   costs.Add(win7group, New List(Of Integer))
   costs.Add(appvgroup, New List(Of Integer))
   costs.Add(othergroup, New List(Of Integer))
End Sub

在此示例中,我们只是为三个报告组中的每个组添加了一个项目到我们的成本字典变量中。我们已经使用我们之前声明的三个字符串变量指定了项目键,以存储报告组的名称。

ForwardPath()

ForwardPath() 函数是所有转发路径方案必须实现的标准函数。ForwardPath() 函数必须具有以下签名:

Public Function ForwardPath(ByVal currentApplication _
   As Application) As Output
      ' Enter your code here.
End Function

在这个例子中,我们将将应用程序分为三个报告组-我们将具有绿色 Windows 7 RAG 状态的应用程序添加到“Windows 7”报告组中,我们将具有绿色 App-V RAG 状态的应用程序添加到“App-V”报告组中,我们将其余的应用程序添加设置为“退休”报告组。对于每个应用程序,我们将在字典中添加一个随机硬编码数字,以表示修复应用程序的成本:

Public Function ForwardPath(ByVal currentApplication _
   As Application) As Output

   Dim result As New Output()

   ' Is the application green for Windows 7?
   If (currentApplication.Modules.Windows7.RAG = RAG.Green) _
     Then
      result.Outcome = "Windows 7 OK"
      result.RAG = RAG.Green
      result.Cost = 33

      ' Add the application to the "Windows 7" group.
      result.ReportGroups.Add(win7group)

      ' Add the remediation cost to the dictionary variable.
      costs.Item(win7group).Add(33)
   Else

      ' Is the application green for App-V?
      If (currentApplication.Modules.AppV.RAG = RAG.Green) Then
         result.Outcome = "App-V OK"
         result.RAG = RAG.Green
         result.Cost = 170

         ' Add the application to the "App-V" group.
         result.ReportGroups.Add(appvgroup)

         ' Add the remediation cost to the dictionary variable.
         costs.Item(appvgroup).Add(170)
      Else

         ' The application is not green for Windows 7 or App-V.
         result.Outcome = "Not suitable for migration."
         result.RAG = RAG.Red
         result.Cost = 713

         ' Add the application to the "Retire" group.
         result.ReportGroups.Add(othergroup)

         ' Add the replacement cost to the dictionary variable.
         costs.Item(othergroup).Add(713)
      End If
   End If

   result.Display.SourcePath.Visible = false

   ForwardPath = result

End Function

请注意,我们已经使用了如果… 那么… 其他语句根据 Windows 7 和 App-V 报告的 RAG 状态将应用程序划分为三个报告组。我们可以将报告组基于应用程序所属的应用程序组。本主题后面的示例将向您展示如何执行此操作。

注意:可以将同一应用程序添加到多个组。如果执行此操作,则在运行报告时,应用程序将显示在已添加到的每个组下,并且其值将聚合到每个组的总计中。这可能会导致应用程序的值被多次添加到报告中。根据报告的不同,这可能会引起误解。作为脚本作者,您可以确保不会将应用程序添加到多个组中,除非这是您的意图。

ProcessGroups()

如果在方案中指定,AppDNA 会为由 ForwardPath() 函数生成的每个报告组调用ProcessGroups() 函数。通常,您可以使用 ProcessGroups() 函数来定义在转发路径报告中的组级别出现的列。

ProcessGroups() 函数必须具有以下签名:

Public Overrides Sub ProcessGroup(group As _
   ForwardPathReportGroup)
      ' Enter your code here.
End Sub

请注意,ForwardPathReportGroup 对象被传递到此函数中。这表示当前报告组。它有两个属性:名称(用于存储组名字符串称)和 CustomColumns(用于存储组名称),后者是字符串字典。您可以使用 CustomColumns 属性指定在组级别显示的列的名称以及它们包含的内容。

这里是一个例子:

Public Overrides Sub ProcessGroup(group As _
   ForwardPathReportGroup)

   ' 1. Define a report group column to show the total
   ' cost for the applications in the group and format it
   ' as currency.
   group.Columns.Item("Cost").Value = _
      costs.Item(group.Name).Sum()
   group.Columns.Item("Cost").Format = "{0:C}"
   group.Columns.Item("Cost").Culture = "en-US"

   ' 2. Define a report group column to show the number of
   ' applications in the group.
   group.Columns.Item("Count").Value = _
      costs.Item(group.Name).Count

   ' 3. Define a report group column that has a link to
   ' further information.
   group.Columns.Item("Link").Value = _
   "<a target=""_blank"" href=""http://www.google.com"">More information</a>"

End Sub

请注意,我们定义了三列:

  1. 这定义了“成本”列,该列显示每个组中应用程序的总修复成本。为了获取总成本,我们使用 List.Sum() 方法聚合成本字典变量中为该组存储的所有成本值。List 类具有其他聚合函数,您可以使用这些函数获取为组存储的平均值、最小值或最大值(例如)。请参MSDN 库阅 List 类的文档。

    请注意,我们已将列上的 Format 属性设置为 {0:C}(指定值为货币)。我们已将文化属性设置为 en-US 的值,以指定货币符号是美元符号。有关格式化输出对转发路径报告进行排序和格式化的更多信息,请参阅。

  2. 这定义了 Count 列,该列显示每个组中的应用程序数量。这次,我们使用 List.count() 方法来获取成本字典变量中为组存储的项目数量(表示应用程序)。

  3. 这定义了链接列,其中包括定义硬编码超链接的 HTML 代码。这是一个过于简单的示例,它演示了您可以在列中包含 HTML 代码。

注意:AppDNA 会自动生成一个显示组名称的列。这称为“组”列。

GetGroupColumnSummary()

如果在场景中指定了,AppDNA 会自动调用在 ProcessGroups() 函数中定义的每个列的 GetGroupColumnSummary() 函数,以及自动生成的“组”列(存储组名称)。GetGroupColumnSummary() 函数必须具有以下签名:

Public Overrides Function GetGroupColumnSummary(groupColumnName _
   As String) As String
      ' Enter your code here.
End Function

请注意,列的名称作为字符串传递到函数中,函数返回一个字符串,该字符串是插入到报告总行中相应列中的文本。

您可以使用 GetGroupColumnSummary() 函数来定义报告级别的值。例如:

Public Overrides Function GetGroupColumnSummary(groupColumnName _
   As String) As String

   If groupColumnName = "Group" Then

      ' Put the text "Total" in the automatically-generated
      ' "Group" column.
      GetGroupColumnSummary = "<b>Total</b>"

   Else If groupColumnName = "Cost" Then

      ' Declare a variable to store the total cost.
      Dim sum As Decimal = 0

      ' Iterate through the costs variable to get the total cost.
      For Each key As String In costs.Keys
         sum += costs.Item(key).Sum()
      Next

      ' Format the total as currency.
      GetGroupColumnSummary = _
         String.Format(New _
            System.Globalization.CultureInfo("en-US"), _
            "{0:C}", sum)

   Else If groupColumnName = "Count" Then

      ' Declare a variable to store the overall count.
      Dim count As Integer = 0

      ' Iterate through the costs variable to get the total
      ' count.
      For Each key As String In costs.Keys
         count += costs.Item(key).count()
      Next

      GetGroupColumnSummary = String.Format(count)

   Else

      ' Leave the "Link" column blank.
      GetGroupColumnSummary = ""

   End If

End Function

AppDNA 为我们在 ProcessGroups() 函数中定义的每个组列调用一次此函数,以及自动生成的“组”列。因此,我们使用一个 IF… 那么… 其他语句来测试正在处理哪个列。让我们来看看我们正在为每一列做什么:

  1. 这是自动生成的组列。 对于此列,我们只是生成文本“总计”。 请注意,我们已将文本封装在 <b></b> 标签中。 这些是标准的 HTML 标签,用于指定文本应呈现为粗体。 您可以在任何列中使用任何 HTML 代码。

  2. 这是成本列。为了得到报告的总数,我们声明一个工作变量。然后我们遍历全局成本字典变量中的所有项目,并将它们的总值添加到工作变量中,然后返回该变量。

    返回值是一个字符串。我们使用了 String.Format() 方法将成本值格式化为货币,并使用CultureInfo类指定美元货币符号。有关格式化字符串MSDN 库的文档,请参阅。

  3. 对于计数列,我们使用了类似的技术为报告生成总值。

  4. 我们将链接列留空。

这使我们到了用于生成本主题开头显示的转发路径报告的方案中的代码的末尾。在本主题后面,我们将了解如何根据应用程序已经属于的 AppDNA 应用程序组创建报告组。

OnProcessingComplete()

如果在方案中指定,AppDNA 会在所有其余处理完成后自动调用 OnProcessingComplete() 一次。您可以使用此函数在显示报告之前执行任何最终处理。

OnProcessingComplete() 函数必须具有以下签名:

Public Overrides Sub OnProcessingComplete()
   ' Enter your code here.
End Sub

按 AppDNA 应用组分组

在本节中,我们将更改方案,以便根据应用程序已经属于的应用程序组对应用程序进行分组。如果任何应用程序不是组的成员,它将显示在“未分组”类别中。

在方案中,您可以通过应用程序 .group 属性找出应用程序所属的组。应用程序可以属于多个组。如上所述,如果您将所有组添加到报告中,应用程序将显示在其所属的每个组下。因此,根据脚本的编写方式,有可能会将应用程序修复成本多次添加到报告总额中。

这些函数包含详细的注释,说明它们是如何工作的。

Public Function ForwardPath(ByVal currentApplication _
   As Application) As Output

   Dim result As New Output()

   If (currentApplication.Modules.Windows7.RAG = RAG.Green) Then
      result.Outcome = "Windows 7 OK"
      result.RAG = RAG.Green
   Else
      ' If the RAG for Windows 7 is not green,
      ' check if it's green for App-V
      If (currentApplication.Modules.AppV.RAG = RAG.Green) Then
         result.Outcome = "App-V OK"
         result.RAG = RAG.Green
      Else
         result.Outcome = "Not suitable for migration."
         result.RAG = RAG.Red
      End If
    End If

   ' We're temporarily using a hard-coded cost.
   result.Cost = 713

   ' Iterate through the groups to which the application
   ' belongs.
   For Each group As String In currentApplication.Groups

      ' Add the application to the corresponding report group.
      result.ReportGroups.Add(group)

      ' Check whether the group has already been added to our
      ' global dictionary variable.
      If costs.ContainsKey(group) Then

         ' Add the application's cost to the global variable.
         costs.Item(group).Add(713)
      Else

         ' Add the group to the global variable and then
         ' add the application's cost.
         costs.Add(group, New List(Of Integer))
         costs.Item(group).Add(713)

      End If
   Next

   ForwardPath = result

End Function

Public Overrides Sub ProcessGroup(group As ForwardPathReportGroup)

   If costs.ContainsKey(group.Name) Then
      group.Columns.Item("Count").Value = _
         costs.Item(group.Name).Count
      group.Columns.Item("Cost").Value = _
         costs.Item(group.Name).Sum()
      group.Columns.Item("Cost").Format = "{0,-10:C}"
      group.Columns.Item("Cost").Culture = "en-US"
      group.Columns.Item("Link").Value = _
      "<a href=""http://www.google.com"">More information</a>"
   End If

End Sub

隐藏组的显示

有时,您可能希望显示没有分组的分组报告。您可以通过使用 ForwardPathReportSettings.DisplayGroups 属性来执行此操作。当您在方案中包含组处理代码时,此属性将自动设置为 true。但是,您可以在方案中将其显式设置为 false,以隐藏报告中组的显示。

在整个方案中,设置对象(类型为 ForwardPathReportSettings)都可用。通常您在 Initialize())函数中设置属性,如下所示:

Settings.DisplayGroups = false

要再次显示组,只需注释此行即可。

分组转发路径报告