簡體   English   中英

如何捕獲取消長期延遲的DTF自定義操作?

[英]How do I trap Cancelling of a long-running deferred DTF Custom Action?

我有一個用DTF編寫的Deferred Custom Action DLL,它將一組.RDL文件發布到SQL Server Reporting Web Service。 一切運行良好,我可以在各種Try Catch塊中捕獲大多數錯誤情況。

我唯一遇到的麻煩是,如果用戶在發布過程中按下安裝程序中的“取消”按鈕。 它確實會立即彈出一條消息,詢問我是否要取消安裝,但是如果我回答“ 是”,則會拋出一條消息:

拋出類型為Microsoft.Deployment.WindowsInstaller.InstallCanceledException的異常

還有一個確定按鈕。

我嘗試添加一個特殊的異常處理程序

catch (InstallCanceledException ex)
{
}

先於其他例外,但似乎並沒有捕獲到這一特殊例外。

有什么建議在取消長時間運行的延遲自定義操作期間如何處理InstallCanceledException?

產品團隊考慮使用其中一種應用程序,但是普通用戶運行這些應用程序,他們不一定知道Web服務URL或沒有權限將報告發布到Web服務。 我放入的安裝程序通常用於運行SQL腳本,並且我要向安裝程序添加第二個功能以發布報告。 實際上,它現在工作得太好了,無法放棄。 產品已經看到我已經完成的工作,並且他們喜歡它。 MSI進度欄將隨着每個報告的發布而更新。 MSI會提示您輸入URI和用戶憑據,並且它已經知道.RDL文件所在的文件夾。當它們單擊下一步按鈕時,我會對URI進行驗證,因此當我在執行序列中運行Deferred操作時,良好的URI和憑據。 我什至走得很遠,甚至在進行發布時我都斷開了與VPN的連接,但由於出現錯誤而失敗了。 從字面上看,僅當用戶按“取消”時,我才似乎無法捕獲該內容,但這也不是這項工作要進行的突破。

隱藏“取消”按鈕是不合適的選項,因為如果他們隨時取消,則可以。

public static ActionResult PublishSSRSReports(Session session)
    {

        session.Log("Begin PublishSSRSReports");

        bool bFolderExists = false;

        string sCustomActionData;
        sCustomActionData = session["CustomActionData"];

        string INSTALLDIR = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/InstallDir="));
        string SSRSURL = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/SsrsUrl="));
        string USERCREDENTIALS = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/Credentials="));
        string USERNAME = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/Username="));
        string PASSWORD = Convert.ToString(MsiGetCustomActionDataAttribute(sCustomActionData, "/Password="));


        string ReportsFolderPath = INSTALLDIR + "SSRSReports";
        DirectoryInfo directory = new DirectoryInfo(ReportsFolderPath);

        FileInfo[] reports = directory.GetFiles("*.rdl"); //Getting all RDL files

        ResetProgressBar(session, reports.Length);

        CatalogItem[] catalogitem = null;

        using (ReportingService2010 rsc = new ReportingService2010())
        {

            rsc.Url = SSRSURL; 

            if (USERCREDENTIALS == "0")
            {
                rsc.Credentials = System.Net.CredentialCache.DefaultCredentials; //User credential for Reporting Service
                                                                                 //the current logged system user
            }
            if (USERCREDENTIALS == "1")
            {
                string[] userdomain = USERNAME.Split(Convert.ToChar("\\"));
                rsc.Credentials = new System.Net.NetworkCredential(userdomain[1], PASSWORD, userdomain[0]);

            }
            catalogitem = rsc.ListChildren(@"/", false);
            foreach (CatalogItem catalog in catalogitem)
            {
                if (catalog.Name == (DP))
                {
                    EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, DP + " folder already exists");
                    bFolderExists = true;
                }
            }

            if (bFolderExists == false)
            {
                rsc.CreateFolder(DP, @"/", null);
            }

            Warning[] Warnings = null;
            foreach (FileInfo ReportFile in reports)
            {
                Byte[] definition = null;
                Warning[] warnings = null;

                try
                {
                    FileStream stream = ReportFile.OpenRead();
                    definition = new Byte[stream.Length];
                    stream.Read(definition, 0, (int)stream.Length);
                    stream.Close();
                }
                catch (InstallCanceledException ex)
                {
                    //session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
                    EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
                    return ActionResult.UserExit;
                }

                catch (IOException ex)
                {
                    session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
                    EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
                    return ActionResult.Failure;
                }
                catch (Exception ex)
                {
                    session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
                    EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
                    return ActionResult.Failure;
                }

                try
                {
                    CatalogItem report = rsc.CreateCatalogItem("Report", ReportFile.Name, @"/" + DP, true, definition, null, out Warnings);

                    DisplayActionData(session, ReportFile.Name);
                    IncrementProgressBar(session, 1);

                    if (report != null)
                    {
                        EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ReportFile.Name + " Published Successfully ");
                    }
                    if (warnings != null)
                    {
                        foreach (Warning warning in warnings)
                        {
                            EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, string.Format("Report: {0} has warnings", warning.Message));
                        }
                    }
                    else
                    {
                        EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, string.Format("Report: {0} created successfully with no warnings", ReportFile.Name));
                    }
                }

                catch (InstallCanceledException ex)
                {
                    //session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
                    EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
                    return ActionResult.UserExit;
                }

                catch (SoapException ex)
                {
                    session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
                    EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Detail.InnerXml.ToString());
                    return ActionResult.Failure;
                }
                catch (Exception ex)
                {
                    session.Message(InstallMessage.Error, new Record { FormatString = ex.Message });
                    EventLog.WriteEntry(AppDomain.CurrentDomain.FriendlyName, ex.Message);
                    return ActionResult.Failure;
                }
            }

        }

        return ActionResult.Success;

我在班上也有這些

private const string SpaceForwardSlash = " /";
    private const string DP = "Test";

在DTF源代碼中,我看到拋出InstallCanceledException的唯一地方是Session.Message()。 這是MsiProcessMessage Windows API函數的包裝。 在我看來,如果您使用Session.Message()從托管自定義操作中顯示消息框,然后單擊“取消”按鈕,您將遇到此異常。 DTF看到消息框“取消”返回代碼,並拋出InstallCanceledException。 也許然后它陷入某個地方的catch塊中(可能是一個不同的動作?),您在其中調用類似於

session.Message(InstallMessage.Error, new Record { FormatString = ex.Message })

顯示第二個僅包含異常的消息框。

在看不到您的MSI源或完整的日志文件的情況下,我無法將所有內容完全拼湊成100%,但這也許會有所幫助。

這是在DTF源中定義Session.Message()的方式:

public MessageResult Message(InstallMessage messageType, Record record)
{
    if (record == null)
    {
        throw new ArgumentNullException("record");
    }

    int ret = RemotableNativeMethods.MsiProcessMessage((int) this.Handle, (uint) messageType, (int) record.Handle);
    if (ret < 0)
    {
        throw new InstallerException();
    }
    else if (ret == (int) MessageResult.Cancel)
    {
        throw new InstallCanceledException();
    }
    return (MessageResult) ret;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM