65.9K
CodeProject 正在变化。 阅读更多。
Home

Lotus Notes 到 Team Foundation Server

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2015年8月4日

CPOL

8分钟阅读

viewsIcon

14173

电子邮件到工作项。

Microsoft Team Foundation Server (TFS) 在许多组织中用于缺陷跟踪。客户可以通过各种渠道(包括电话和电子邮件)记录缺陷。有一些插件可以将 Microsoft Outlook 的电子邮件转换为 TFS 中的工作项。但是,目前还没有插件可以实现 Lotus Notes 电子邮件服务与 TFS 的集成。本文将介绍 Lotus Notes 与 TFS 之间的集成问题。

引言

客户帮助台会收到大量工单,这些工单将被分类并管理在 TFS 或 HP Application Lifecycle Manager (ALM) 等缺陷管理工具中。大多数情况下,工单是通过电子邮件接收的,支持团队会根据电子邮件内容创建缺陷或工单,并将其分配给特定的/相关的组。对于 Outlook,有一个插件可以与 TFS 集成。这有助于支持团队通过点击 Outlook 中的几个按钮在 TFS 中创建缺陷!Lotus Notes 是另一个广泛使用的电子邮件客户端,目前还没有插件可以实现此功能。这需要手动创建缺陷并将电子邮件内容复制到缺陷中,等等。

本文旨在为 Lotus Notes 到 TFS 工作项的集成过程提供解决方案。我们采用了两阶段方法 - 第一阶段是在 Lotus Notes 外部提供一个独立的 GUI,用于列出所有电子邮件并在 TFS 中创建不同的工作项;在第二阶段,我们将研究创建一个 Lotus Notes 的 Java 插件,该插件将调用 .NET 服务将详细信息传递给 TFS。作为微软技术布道者,我将带您完成第一阶段,并仅解释第二阶段的方法。Java 社区中的任何人都肯定可以采用第二阶段的方法,开发一个 Lotus Notes 插件,从而实现 Lotus Notes 与 TFS 的无缝集成。

 

第一阶段:WPF 应用程序

在第一阶段,我们将创建一个独立的 Windows 应用程序,该应用程序将从 Lotus Notes 中提取电子邮件信息并将其写入 TFS 作为工作项。下图显示了流程。

假设:解决方案将部署的系统已安装并配置了 Lotus Notes

创建新的 WPF 应用程序

打开 Visual Studio 并创建一个新的 WPF 应用程序。让我们从集成 Lotus Notes 开始开发。Lotus Notes 提供基于 COM 的 .NET 程序集,用于访问电子邮件。这些程序集将安装在已安装并配置了 Lotus Notes 的客户端系统中。

添加 Lotus Domino Objects 引用

添加 Lotus Domino Objects 引用

  1. 在解决方案资源管理器中右键单击项目名称,然后选择“添加”->“引用”。

  2. 在“引用管理器”窗口中选择“COM”部分,然后选择“Lotus Domino Objects”程序集。

  3. 单击“确定”将引用添加到项目中。

添加 TFS 引用

将以下 TFS 程序集引用添加到项目中。这些程序集可以在以下位置找到:

C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE\Reference Assemblies\v2.0\

  1. Microsoft.TeamFoundation.Common.dll

  2. Microsoft.TeamFoundation.Client.dll

  3. Microsoft.TeamFoundation.WorkItemTracking.Client.dll

从 Lotus Notes 检索收件箱

  1. 检索 Lotus Notes 中的收件箱详细信息。

  2. 使用 Lotus Notes 数据库名称和当前用户密码连接到 Lotus Notes。

  3. 提供当前用户的 Lotus Notes 密码以检索电子邮件文件。

Lotus Notes 数据库设置

Lotus Notes 数据库详细信息可从 Lotus Notes 配置中获取。

  1. 打开 Lotus Notes,导航到“文件”->“首选项”->“位置”。

  2. 选择当前位置,然后单击“编辑”。此时将出现“编辑位置”对话框。

  3. 单击“邮件”选项卡,然后检查“邮件文件”选项的配置值。这将指示 Lotus Notes 的数据库名称。

设计 WPF 屏幕

设计一个 UI 来捕获用户独有的数据库名称和密码。让我们定义一个简单的 UI,其中包含两个文本框用于接受详细信息,以及一个“获取电子邮件”按钮,用于调用根据用户输入检索收件箱详细信息的函数。

现在,向主窗口添加一个数据网格,以显示收件箱中的电子邮件。我们定义用于显示字段的列:“发件人”或发送者、电子邮件日期和主题。

以下 XAML 代码片段定义了一个名为“mailGrid”的简单数据网格。


<DataGrid HorizontalAlignment="Left" Height="429" Margin="21,183,0,0" VerticalAlignment="Top" AutoGenerateColumns="False" Width="911" x:Name="mailGrid" ItemsSource="{Binding}" >

            <DataGrid.Columns>
                <DataGridTextColumn Header="From" Binding="{Binding From}" Width="180" />
                <DataGridTextColumn Header="Date" Binding="{Binding Date}" Width="100" />
                <DataGridTextColumn Header="Subject" Binding="{Binding Subject}" Width="*"/>

 </DataGrid.Columns>
        </DataGrid>
检索 Notes 收件箱

我们使用 Domino COM 程序集中的各种类和构造来检索 Lotus Notes 中的电子邮件。NoteSession 是 Domino 程序集中的主要类。创建 NoteSession 类的对象,并使用密码进行初始化。

_lotesNotesSession = new NotesSession();                               
_lotesNotesSession.Initialize(pwd.Password);

调用 GetDatabase 方法,并传入数据库名称。Lotus Notes 的数据库对象定义了不同的视图,如收件箱、已发送、发件箱等。获取收件箱视图以检索邮件。

            _localDatabase = _lotesNotesSession.GetDatabase("", dbName.Text, false);
           _mailView = _localDatabase.GetView("($Inbox)");

GetDatabase 方法接受三个参数。

  1. 服务器名称:指定服务器名称,当您需要直接从服务器获取电子邮件时。

  2. 文件名:指定 Lotus Notes 客户端的数据库名称,其中电子邮件将从客户端可用。

  3. 失败时创建:布尔值

我们使用 Lotus Notes 本地实例的数据库名称来检索与本地 Lotus Notes 数据库同步的电子邮件。

从邮件视图获取所有条目,并从每个条目中检索 NoteDocument。

            NotesViewEntryCollection notesViewCollection = _mailView.AllEntries;
           ---------------------
                NotesViewEntry viewEntry = notesViewCollection.GetNthEntry(rowCount);
               NotesDocument document = viewEntry.Document;

从文档中检索 NoteItem 集合,它代表电子邮件组件。

                object documentItems = document.Items;
          Array itemArray1 = (System.Array)documentItems;
                                  ---------------------
         NotesItem notesItem = (NotesItem)itemArray1.GetValue(itemCount);

从 NotesItem 检索数据

                   if (notesItem.Name == "INetFrom")
                        {
                            dr["From"] = notesItem.Text;
                        }
                        if (notesItem.Name == "PostedDate")
                            dr["Date"] = notesItem.Text;

                        if (notesItem.Name == "Subject")
                            dr["Subject"] = notesItem.Text;

                        if (notesItem.Name == "Body")
                            dr["Body"] = notesItem.Text;

以下是从本地 Lotus Notes 数据库检索电子邮件数据的完整代码。

private void btnGetMails_Click(object sender, RoutedEventArgs e)
        {

            List<string> senders = new List<string>();
            dtmails.Rows.Clear();
            _lotesNotesSession = new NotesSession();
            _lotesNotesSession.Initialize(pwd.Password);

            _localDatabase = _lotesNotesSession.GetDatabase("", dbName.Text, false);
            _mailView = _localDatabase.GetView("($Inbox)");


            NotesViewEntryCollection notesViewCollection = _mailView.AllEntries;
            for (int rowCount = 1; rowCount <= notesViewCollection.Count; rowCount++)
            {

                NotesViewEntry viewEntry = notesViewCollection.GetNthEntry(rowCount);
                NotesDocument document = viewEntry.Document;
                object documentItems = document.Items;
                Array itemArray1 = (System.Array)documentItems;

                DataRow dr = dtmails.NewRow();
                for (int itemCount = 0; itemCount < itemArray1.Length; itemCount++)
                {
                    NotesItem notesItem = (NotesItem)itemArray1.GetValue(itemCount);
                    if (notesItem.Text != null)
                    {
                        if (notesItem.Name == "INetFrom")
                        {
                            dr["From"] = notesItem.Text;
                            if (!senders.Contains(notesItem.Text))
                                senders.Add(notesItem.Text);
                        }
                        if (notesItem.Name == "PostedDate")
                            dr["Date"] = notesItem.Text;

                        if (notesItem.Name == "Subject")
                            dr["Subject"] = notesItem.Text;

                        if (notesItem.Name == "Body")
                            dr["Body"] = notesItem.Text;
                    }
                }

                if (!string.IsNullOrEmpty(dr["From"].ToString()))
                    dtmails.Rows.Add(dr);
            }
            mailGrid.DataContext = dtmails;        

            senders.Sort();
            senderName.DataContext = senders;
        }

让我们对应用程序进行一些修改,以便在单独的窗口中显示整个邮件正文。定义另一个窗口,其中包含一个关闭按钮,用于显示邮件正文的详细信息。

<Grid>
        <ScrollViewer>
            <TextBlock x:Name="mailData" Padding="20,0,0,0">
             </TextBlock>
        </ScrollViewer>

        <Button Content="Close" HorizontalAlignment="Left" Height="24" Margin="657,536,0,0" VerticalAlignment="Top" Width="90" x:Name="btnClose" Click="btnClose_Click"/>

    </Grid>

当窗口加载时,将 mailData 文本块设置为来自 Utilities 类的。Utilities 类是一个静态类,用于在两个窗口之间传递数据以及定义静态方法。Utilities 类的 MailBody 属性将从主窗口设置。

private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            mailData.Text = Utilities.MailBody;
        }

现在,让我们对主窗口进行一些更改,以调用带有选定电子邮件详细信息的新窗口。向数据网格添加一个模板列和一个按钮。

<DataGridTemplateColumn Width="60" Header="View">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Click="ShowDetails">Details</Button>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

在主窗口的代码隐藏中定义 ShowDetails 方法。ShowDetails 将 Utilities 类的 MailBody 属性设置为选定电子邮件的正文,并将 MailDetails 窗口作为对话框调用。

   void ShowDetails(object sender, RoutedEventArgs e)
        {
            if(mailGrid.SelectedItems.Count>0)
            {
                System.Data.DataRowView dataView = (System.Data.DataRowView)mailGrid.SelectedItems[0];
                DataRow data = dataView.Row;
                Utilities.MailBody = data["Body"].ToString();
                MailDetails obj = new MailDetails();
                obj.ShowDialog();
            }
        }

运行项目,并指定 Lotus Notes 的数据库和密码以检索电子邮件详细信息。以下屏幕显示了带有加载的收件箱内容的主窗口。

    

正如您所见,除了我们讨论的内容之外,我们在收件箱视图的顶部添加了一些过滤器,用于根据发件人和日期过滤记录或搜索记录。过滤器的实现将在以下代码片段中进行说明。

   private void btnFilter_Click(object sender, RoutedEventArgs e)
        {           
            string query = string.Empty;
            if (senderName.SelectedIndex > -1)
                query += " From ='" + senderName.SelectedValue.ToString() + "'";

            if(_operator.SelectedIndex>-1)
            {
                if (senderName.SelectedIndex > -1)
                    query += " AND ";
                query += " Date " + _operator.Text + " '" + sentDate.SelectedDate.ToString() + "'";
            }


            if(!string.IsNullOrEmpty(query))
            {
                var filteredData = dtmails.Select(query);
                mailGrid.DataContext = null;
                if(filteredData.Count()>0)
                    mailGrid.DataContext = filteredData.CopyToDataTable();
            }
        } 

在 TFS 中创建工作项

将从 Lotus Notes 中检索电子邮件,并在应用程序中显示,并提供搜索选项。现在,让我们连接到 TFS 项目,并根据应用程序中选定的电子邮件创建工作项。

假设:- 用户应具有 TFS 访问权限。

设计 WPF 屏幕

设计 UI 以捕获用于连接的 TFS 服务器信息。一旦用户指定了 TFS 服务器详细信息,将显示关联的项目集合、项目和工作项供用户选择。

用户应提供 TFS 服务器详细信息,然后单击“重新加载”按钮以加载项目集合详细信息。当项目集合选择发生更改时,系统将查询 TFS 以获取相应的项目信息。根据项目选择,将填充工作项名称。

TFS 的实用工具方法

定义实用工具方法以从 TFS 检索项目集合详细信息。GetProjectCollection 方法将连接到指定的 TFS 服务器,并检索项目集合详细信息。这将获取用户有权访问的项目集合。

通过将 TFS 服务器详细信息传递给 TfsConfigurationServerFactory 的 GetConfigurationServer 方法,获取 TfsConfigurationServer 的实例。获取 TfsConfigurationServer 的团队项目集合目录。从目录中检索团队项目集合名称。

  public static List<string> GetProjectCollection(string tfsServerName)
        {
            List<string> projCollection = new List<string>();
            Uri tfsUri = new Uri(tfsServerName);

           TfsConfigurationServer configurationServer =
                TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
            configurationServer.EnsureAuthenticated();

            // Get the catalog of team project collections
             ReadOnlyCollection<CatalogNode> collectionNodes = 
                configurationServer.CatalogNode.QueryChildren(
                         new[] { CatalogResourceTypes.ProjectCollection },
                         false, CatalogQueryOptions.None);


            // List the team project collections
            foreach (CatalogNode collectionNode in collectionNodes)
            {
                // Use the InstanceId property to get the team project collection
                Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
                TfsTeamProjectCollection teamProjectCollection = 
                            configurationServer.GetTeamProjectCollection(collectionId);


                string colName = teamProjectCollection.Name;
                if (colName.IndexOf("\\") > -1)
                    colName = colName.Substring(colName.IndexOf("\\") + 1);

                projCollection.Add(colName);
            }
            return projCollection;
        }

现在,定义另一个实用工具方法以检索指定团队项目下的团队项目列表。将项目集合 URI 传递给 TfsTeamProjectCollectionFactory 的 GetTeamProjectCollection 方法。从团队项目集合对象中检索团队项目目录。

     public static List<string> GetProjects(string tfsServerName, string projectCollName)
        {
            List<string> projects = new List<string>();
            Uri collectionUri = new Uri(tfsServerName + "\\" + projectCollName);

            var TeamProjectCollection = 
                     TfsTeamProjectCollectionFactory.GetTeamProjectCollection(collectionUri);

            ReadOnlyCollection<CatalogNode> projectNodes = 
                   TeamProjectCollection.CatalogNode.QueryChildren(
                            new[] { CatalogResourceTypes.TeamProject },
                            false, CatalogQueryOptions.None);

            // List the team projects in the collection
            foreach (CatalogNode projectNode in projectNodes)
            {
                   projects.Add(projectNode.Resource.DisplayName);
            }

            return projects;
        }

定义另一个实用工具方法以检索所选团队项目下的工作项。通过传递项目集合 URI 来获取团队项目集合。从团队项目集合对象中,获取 WorkItemStore 服务,该服务又包含指定团队项目集合下的项目。从项目中检索工作项类型。

      public static List<string> GetWorkItemTypes(string projectName, string tfsServerName, string projectCollName)
        {
            List<string> workItems = new List<string>();
            Uri collectionUri = new Uri(tfsServerName + "\\" + projectCollName);
            TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(collectionUri);
            WorkItemStore workItemStore = tpc.GetService<WorkItemStore>();
            Project teamProject = workItemStore.Projects[projectName];


            var workItemTypes = teamProject.WorkItemTypes;
            foreach (WorkItemType wt in workItemTypes)
            {
                workItems.Add(wt.Name);
            }
            return workItems;
        }

将 TFS 详细信息绑定到 WPF 控件

绑定项目集合下拉列表

projectCollection.DataContext = Utilities.GetProjectCollection(tfsServer.Text);

绑定项目下拉列表。

projects.DataContext = Utilities.GetProjects(tfsServer.Text, projectCollection.SelectedValue.ToString());

在项目更改时绑定工作项详细信息

workItems.DataContext = Utilities.GetWorkItemTypes(projects.SelectedValue.ToString(), tfsServer.Text, projectCollection.SelectedValue.ToString());

运行并验证应用程序

运行应用程序,并提供 Lotus Notes 数据库名称和密码。通过单击“获取电子邮件”按钮加载收件箱。通过按住 Shift 键选择一个或多个电子邮件,以在 TFS 中创建工作项。

指定 TFS 服务器名称,然后单击“重新加载”按钮以加载项目集合详细信息。选择一个团队项目集合,这将加载所选项目集合下的项目。从“项目”下拉列表中选择一个项目,以加载相应的工作项类型。

选择要创建的工作项类型,然后单击“创建工作项”按钮,在 TFS 中所选项目下创建工作项。

完成工作项创建后,将显示一个弹出窗口,显示创建的工作项数量。

在 TFS 中验证新创建的工作项,以确认从 Lotus Notes 电子邮件创建工作项已完成。

第二阶段:Lotus Notes 插件

上述解决方案可以修改为 .NET 服务,并支持不同的数据格式,如 JSON、XML 和 SOAP。基于 Java 的 Lotus Notes 插件可以调用该服务,将电子邮件详细信息直接推送到 TFS。下图显示了 Lotus Notes 与 TFS 的最终预期集成。

社区中的 Java 专家可以考虑实现此解决方案的第二阶段,以实现 Lotus Note 与 TFS 的无缝集成。

© . All rights reserved.