简体   繁体   English

如何捕获取消长期延迟的DTF自定义操作?

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

I've got a Deferred Custom Action DLL written in DTF that publishes a set of .RDL files to the SQL Server Reporting Web Service. 我有一个用DTF编写的Deferred Custom Action DLL,它将一组.RDL文件发布到SQL Server Reporting Web Service。 All is working well and I can trap most of the error conditions in various Try Catch blocks. 一切运行良好,我可以在各种Try Catch块中捕获大多数错误情况。

The only thing I am having trouble with is if the user presses the Cancel button in the installer while the publish is happening. 我唯一遇到的麻烦是,如果用户在发布过程中按下安装程序中的“取消”按钮。 It does immediately pop up a message asking if I want to Cancel the install, but if I answer Yes then it throws a message : 它确实会立即弹出一条消息,询问我是否要取消安装,但是如果我回答“ 是”,则会抛出一条消息:

Exception of type Microsoft.Deployment.WindowsInstaller.InstallCanceledException was thrown 抛出类型为Microsoft.Deployment.WindowsInstaller.InstallCanceledException的异常

and just an OK button. 还有一个确定按钮。

I've tried adding a special Exception handler of 我尝试添加一个特殊的异常处理程序

catch (InstallCanceledException ex)
{
}

prior to other exceptions, but it just doesn't seem to capture this one particular exception. 先于其他例外,但似乎并没有捕获到这一特殊例外。

Any suggestions how to handle the InstallCanceledException during a Cancel of a long-running Deferred Custom Action? 有什么建议在取消长时间运行的延迟自定义操作期间如何处理InstallCanceledException?

The product team looked at using one of the applications but normal users run the applications and they wouldn't necessarily know the web service URL or have permissions to publish the reports to the web service. 产品团队考虑使用其中一种应用程序,但是普通用户运行这些应用程序,他们不一定知道Web服务URL或没有权限将报告发布到Web服务。 The installer I have put this in is usually used for running SQL Scripts and I'm adding a second Feature to the installer to Publish the reports. 我放入的安装程序通常用于运行SQL脚本,并且我要向安装程序添加第二个功能以发布报告。 It's actually working too well to abandon it now. 实际上,它现在工作得太好了,无法放弃。 Product has seen what I've done already and they love it. 产品已经看到我已经完成的工作,并且他们喜欢它。 The MSI Progress Bar is updating with the name of each report as they are published. MSI进度栏将随着每个报告的发布而更新。 The MSI prompts for the URI and user credentials and it already knows what folder the .RDL files are in. I run a Validation on the URI when they click the next button so by the time I run the Deferred action in the Execution Sequence it has a good URI and credentials. MSI会提示您输入URI和用户凭据,并且它已经知道.RDL文件所在的文件夹。当它们单击下一步按钮时,我会对URI进行验证,因此当我在执行序列中运行Deferred操作时,良好的URI和凭据。 I've even gone so far as while the publish is occurring I disconnect from VPN and it fails with a proper error. 我什至走得很远,甚至在进行发布时我都断开了与VPN的连接,但由于出现错误而失败了。 It is literally only when the user presses Cancel that I can't seem to trap that one, but it is also not a showstopper for this work to go out. 从字面上看,仅当用户按“取消”时,我才似乎无法捕获该内容,但这也不是这项工作要进行的突破。

Hiding the Cancel button is not an appropriate option since it is fine if they Cancel at any time. 隐藏“取消”按钮是不合适的选项,因为如果他们随时取消,则可以。

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;

I've also got these in the class 我在班上也有这些

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

In the DTF source code the only place I see an InstallCanceledException being thrown is in Session.Message(). 在DTF源代码中,我看到抛出InstallCanceledException的唯一地方是Session.Message()。 This is a wrapper for the MsiProcessMessage Windows API function. 这是MsiProcessMessage Windows API函数的包装。 It looks to me like you would get this exception if you used Session.Message() to display a message box from a managed custom action, and then clicked the 'Cancel' button. 在我看来,如果您使用Session.Message()从托管自定义操作中显示消息框,然后单击“取消”按钮,您将遇到此异常。 DTF sees the message box 'cancel' return code and throws an InstallCanceledException. DTF看到消息框“取消”返回代码,并抛出InstallCanceledException。 Perhaps it's then falling into a catch block somewhere (could be a different action?) where you call something similar to 也许然后它陷入某个地方的catch块中(可能是一个不同的动作?),您在其中调用类似于

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

which displays the second message box containing just the exception. 显示第二个仅包含异常的消息框。

I can't quite piece everything together 100% without seeing your MSI source or a complete log file, but maybe this will help. 在看不到您的MSI源或完整的日志文件的情况下,我无法将所有内容完全拼凑成100%,但这也许会有所帮助。

Here's how Session.Message() is defined in the DTF source: 这是在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