VB.NET Visual Studio Outlook 2013 插件项目 - 事件似乎没有触发

VB.NET Visual Studio Outlook 2013 Addin Project - events appear not to be firing

感谢您抽空查看我的第一个 post。

我正在开发一个 Outlook 插件(使用 Visual Studio community 2013)以允许用户轻松地为我们的客户服务部门填充电子邮件模板。 该插件运行良好,但我需要添加一些功能,以便在实际发送电子邮件后将一些数据(以跟踪 KPI)记录到数据库中。

经过一些研究,我为应用程序 itemSend 事件实现了 Class 级事件处理程序。

这在开发机器上完美运行,但是当我在客户端上发布和安装应用程序时,事件似乎没有触发,因为没有调用将数据记录到数据库的代码。

由于无法正常工作,我尝试了一种解决方法,随后将其更改为使用已发送文件夹的 .ItemAdd 事件。 (代码是从 Pranav 那里借来的:https://easyvsto.wordpress.com/2010/07/27/how-to-save-mail-content-when-a-mail-is-sent-from-outlook/

这在开发机器上也能完美运行,但同样,在客户端机器上安装插件后,事件似乎无法触发。

由于我现在看到两种不同方法的相同行为,这让我觉得我显然没有做某事。我是漏掉了什么还是没有考虑到什么?

代码示例如下:

Imports Microsoft.Office.Tools.Ribbon
Imports System.Runtime.InteropServices
Imports System.IO
Imports MySql.Data.MySqlClient
Imports System.Diagnostics

Public Class ThisAddIn
Public WithEvents oSentFolder As Outlook.Folder
Public WithEvents oSentItems As Outlook.Items

Private Sub ThisAddIn_Startup() Handles Me.Startup
    oSentFolder = Globals.ThisAddIn.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail)
    oSentItems = oSentFolder.Items
End Sub

Private Sub InsertSurveyTimestamp() Handles oSentItems.ItemAdd
    System.Windows.Forms.MessageBox.Show("oSentItems.ItemAdd Event")
End Sub
Private Sub Application_ItemSend(ByVal oItem As Object, ByRef Cancel As Boolean) Handles Application.ItemSend
    System.Windows.Forms.MessageBox.Show("Application.ItemSend Event")
    log.WriteToErrorLog("Application ItemSend Reached", "", "Event")
    If TypeOf oItem Is Outlook.MailItem Then Call SentMailTimestamp(oItem)
    System.Windows.Forms.MessageBox.Show("end of Itemsend Event")
End Sub

Private Sub SentMailTimestamp(oitem As Outlook.MailItem)
    log.WriteToErrorLog("SentMailTimestamp Sub Reached", "", "Subroutine Flag")
    Try
        'Dim oitem As Outlook.MailItem = oSentItems.Item(oSentItems.Count) 'for use with oSentItems.ItemAdd event
        'Check the CSOSurvey property exists to make sure its a CSO Survey email, exit if not a CSOSurvey Email
        Dim o = oitem.ItemProperties("CSOSurvey")
        If (o IsNot Nothing) AndAlso (o.Value IsNot Nothing) Then
            System.Diagnostics.Debug.WriteLine("CSOsurvey email: " & o.Value.ToString)
            log.WriteToErrorLog("Email was CSO Survey", "Value: " & o.Value.ToString, "Email Property")
        Else
            System.Diagnostics.Debug.WriteLine("CSOsurvey email: Null")
            log.WriteToErrorLog("Email was NOT CSO Survey", "", "Email Property")
            oitem = Nothing
            o = Nothing
            Exit Sub
        End If
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
    'Save the timedatestamp of the email template being sent
    Using sqlCommand As New MySqlCommand
        Dim querystr As String = "INSERT INTO cs_survey_emaillog (SRID,exec,datetimestamp) values(@srid,@exec,@datetimestamp)"
        Dim mysqlconn As MySqlConnection
        Try
            mysqlconn = New MySqlConnection(GlobalVariables.connstr)
            mysqlConn.Open()
        Catch ex As MySqlException
            System.Windows.Forms.MessageBox.Show("Unable to write to Log. Please contact bst.uk@chep.com" & vbCrLf & ex.Message)
            log.WriteToErrorLog(ex.Message, ex.StackTrace, "MySQL Error")
            Exit Sub
        End Try
        If mysqlconn.State = Data.ConnectionState.Open Then
            Try
                With sqlCommand
                    .Connection = mysqlconn
                    .CommandText = querystr
                    .CommandType = Data.CommandType.Text
                    .Parameters.AddWithValue("@srid", ThisAddIn.templateSRID)
                    .Parameters.AddWithValue("@exec", ThisAddIn.GetUserName())
                    .Parameters.AddWithValue("@datetimestamp", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
                    Dim numrec As Integer = .ExecuteNonQuery()
                    If ThisAddIn.GetUserName = "mclachd" Then System.Windows.Forms.MessageBox.Show("Query executed. " + numrec.ToString + " Records sent")
                End With
            Catch ex As MySqlException
                log.WriteToErrorLog(ex.Message, ex.StackTrace, "MySQL Error")
            Finally
                mysqlconn.Close()
                mysqlconn.Dispose()
            End Try
        Else
            log.WriteToErrorLog("Could not open db connection", "", "MySQL Error")
            mysqlconn.Dispose()
        End If
    End Using
End Sub

在这种情况下,SentMailTimeStamp 例程从未达到。

如果我删除呼叫,那么两个消息框都将作为两个事件的结果显示。

如果您需要更多详细信息,请告诉我。

亲切的问候,

大卫

更新 根据 Cadogi 评论修改了代码。谢谢。

更新2 已将对 SentMailtimeStamp 路由的调用包装在 Try Catch 中,我确实在客户端中出现错误。

Private Sub Application_ItemSend(ByVal oItem As Object, ByRef Cancel As Boolean) Handles Application.ItemSend
    System.Windows.Forms.MessageBox.Show("Application.ItemSend Event")
    log.WriteToErrorLog("Application ItemSend Reached", "", "Event")
    Try
        If TypeOf oItem Is Outlook.MailItem Then Call SentMailTimestamp(oItem)
    Catch ex As Exception
        System.Windows.Forms.MessageBox.Show(ex.Message)
    End Try
    System.Windows.Forms.MessageBox.Show("end of Itemsend Event")
End Sub

错误信息是:

无法加载文件或程序集 'MySQL.Data, version=6.8.5.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d' 或其依赖项之一。系统无法找到指定的文件

太棒了,如果感觉进步了。我假设已发布的项目会包含所有需要的内容。

更新 3 我已经解决了这个问题,感谢 Hans,他向我指出了一些非常简单的调试课程 - 这是一个艰难的教训,因为这花了我几个星期的时间来解决。

汉斯完全正确。

There is something obvious you are missing, Office programs are not that accommodating to add-ins that misbehave. By default any exception they throw in an "awkward" place is swallowed without a diagnostic. The only way to tell that this happened is that code you think should have a side-effect is just not doing its job.

插件在开发机器上工作而不是客户端工作的原因是 MySQL.Data 引用需要 Copy Local 属性 设置为 True。

对于那些最终与我处于相似位置的人,解决方法是转到您的项目属性 -> 参考。突出显示 MySQL.Data 并将 Copy Local 属性 更改为 True

感谢大家的贡献,这对我的学习和缩小问题范围都有帮助。

您的加载项是否已在最终用户 PC 上启用?

当大量项目一次添加到文件夹(超过 16 个)时,不会触发项目 class 的 ItemAdd 事件。这是 Outlook 中的一个已知问题。

抱歉,没有足够的积分来发表评论...

您的 SentMailTimestamp() 例程是否可能在最终用户无法访问的网络部分上保存 KPI 的信息?我已经看到应用程序因此而在没有警告或错误的情况下失败。

另一件要检查的事情是 SentMailTimestamp() 是否应该使用 "Call" 关键字,因为它会干扰您的结果。例如

Private Sub Application_ItemSend(ByVal oItem As Object, ByRef Cancel As Boolean) Handles Application.ItemSend
MsgBox("Application.ItemSend Event")
SentMailTimestamp()
End Sub

基于此: https://msdn.microsoft.com/en-us/library/dz1z94ha.aspx

从上面 Link: "You can use the Call keyword when you call a Sub procedure, but that keyword isn't recommended for most uses. For more information, see Call Statement (Visual Basic)."

这是 link 它转发给:https://msdn.microsoft.com/en-us/library/sxz296wz.aspx

您显然遗漏了一些东西,Office 程序 适应行为不当的加载项。默认情况下,他们在 "awkward" 位置抛出的任何异常都会在没有诊断的情况下被吞噬。告诉这件事发生的唯一方法是你认为应该有副作用的代码只是没有完成它的工作。

您所做的一切都很好地涵盖了,google "VSTO exception handling"。其中之一是 this MSDN article,我将复制粘贴相关部分:

Visual Studio Tools for Office can write all errors that occur during startup to a log file or display each error in a message box. By default, these options are turned off for application-level projects. You can turn the options on by adding and setting environment variables. To display each error in a message box, set the VSTO_SUPPRESSDISPLAYALERTS variable to 0 (zero). You can suppress the messages by setting the variable to 1 (one). To write the errors to a log file, set the VSTO_LOGALERTS variable to 1 (one). Visual Studio Tools for Office creates the log file in the folder that contains the application manifest. The default name is .manifest.log. To stop logging errors, set the variable to 0 (zero)