Как перехватить отмену долгосрочного отложенного пользовательского действия DTF? - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть Отложенная библиотека пользовательских действий, написанная в DTF, которая публикует набор файлов .RDL в веб-службе отчетов SQL Server.Все работает хорошо, и я могу уловить большинство состояний ошибки в различных блоках Try Catch.

Единственная проблема, с которой я сталкиваюсь, - это если пользователь нажимает кнопку «Отмена» в установщике во время публикации.Он сразу же выдает сообщение, спрашивающее, хочу ли я отменить установку, но если я отвечаю Да , то выдает сообщение:

Исключение типа Microsoft.Deployment.WindowsInstaller.InstallCanceledException было сгенерировано

и просто кнопкой ОК.

Я пытался добавить специальный обработчик исключений

catch (InstallCanceledException ex)
{
}

до других исключений, нопохоже, что это одно конкретное исключение не отражает.

Любые предложения о том, как обрабатывать исключение InstallCanceledException при отмене долго выполняющегося отложенного настраиваемого действия?

Команда разработчиков рассмотрела возможность использования одного из приложений, но обычные пользователи запускают приложения и не хотятнеобязательно знать URL-адрес веб-службы или иметь разрешения на публикацию отчетов в веб-службе.Установщик, в который я это поместил, обычно используется для запуска сценариев 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";

1 Ответ

0 голосов
/ 04 декабря 2018

В исходном коде DTF единственное место, где я вижу выбрасываемое исключение InstallCanceledException, находится в Session.Message ().Это оболочка для функции Windows API MsiProcessMessage.Мне кажется, вы бы получили это исключение, если бы вы использовали Session.Message () для отображения окна сообщения из управляемого настраиваемого действия, а затем нажали кнопку «Отмена».DTF видит в окне сообщения код возврата «отмена» и выдает исключение InstallCanceledException.Возможно, он попадает в блок catch где-нибудь (может быть, другое действие?), Где вы вызываете что-то похожее на

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

, которое отображает второе окно сообщения, содержащее только исключение.

Я не могу на 100% собрать все воедино, не увидев ваш источник MSI или полный файл журнала, но, возможно, это поможет.

Вот как Session.Message () определено в источнике DTF:

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;
}
...