【问题标题】:Debugging C# Custom Installer Classes调试 C# 自定义安装程序类
【发布时间】:2010-09-21 17:26:15
【问题描述】:

我编写了一个扩展 Installer 并覆盖 afterInstall 的安装类,但我得到一个空指针异常。我该如何调试我的课程?

【问题讨论】:

    标签: c# .net installation


    【解决方案1】:

    构建一个 VM,安装 Visual Studio,复制它(或创建一个差异化虚拟硬盘)并在 VM 下的调试器下运行安装程序。

    这就是我会做的(但我不是专家)。

    【讨论】:

    • 将此与 System.Diagnostics.Debugger.Break() 技巧结合起来,生活会变得非常擅长产生可调试的重现。
    【解决方案2】:

    在 Debug->Processes->Attach 或 CTRL + ALT + P 中将安装程序进程附加到 Visual Studio 设置断点,你应该可以去

    【讨论】:

    • 安装过程是什么(名称?)
    【解决方案3】:

    对于难以调试的代码部分来说很方便的是

    System.Diagnostics.Debugger.Break()
    

    将抛出任何已安装的调试器(VStudio、WinDbg、远程调试器等)捕获的断点。

    使用它来调试非常棘手的区域,其中常规 F5+Go 或“附加到进程”难以或无法执行,一些示例包括:

    • 短期进程
    • 时间敏感的流程
    • 闯入衍生的子进程
    • 安装程序
    • 服务停止/启动
    • 分布式系统

    【讨论】:

    • 不适合我,没有先做 System.Diagnostics.Debugger.Launch()
    • Hey Mark - Break 尝试启动自动调试注册表项中指定的任何调试器。我可以想象,如果没有指定调试器,它什么也不做——然后尝试附加它——什么也不做。通过显式启动它,您可以附加该实例。 msdn.microsoft.com/en-us/library/windows/desktop/… 有更多详细信息。还有一个用于指定默认调试器的隐藏对话框 - 目前让我无法理解。
    • 另外,请务必在调试模式下构建安装程序,以便调试文件在那里。我还必须disable "Enable Just My Code"。像魅力一样工作!谢谢!
    【解决方案4】:

    我使用 EventLog.WriteEntry("source", "message"),并在安装时检查 EventLog。也许不是最佳的,但对我有用:)

    【讨论】:

    • 我也会这样做....写入日志并在应用程序完成执行后检查日志,以便清楚地了解正在发生的事情....断言您足够迂腐的事实!
    【解决方案5】:

    我发现最好的方法是编写单元测试,然后从单元测试中新建和初始化安装程序类:

    [TestClass] public class InstallerTest {
    [TestMethod]
    public void InstallTest() {
      // substitute with your installer component here
      DataWarehouseInstall installer = new DataWarehouseInstall();
    
      string assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    
      string installLogFilePath = Path.Combine(assemblyDirectory, "install.log");
      installer.Context = new System.Configuration.Install.InstallContext(installLogFilePath, null);      
    
      // Refactor to set any parameters for your installer here
      installer.Context.Parameters.Add("Server", ".");
      //installer.Context.Parameters.Add("User", "");
      //installer.Context.Parameters.Add("Password", "");
      installer.Context.Parameters.Add("DatabaseName", "MyDatabaseInstallMsiTest");
      //installer.Context.Parameters.Add("DatabasePath", "");
    
      // Our test isn't injecting any save state so we give a default instance for the stateSaver
      installer.Install(new Hashtable());
    } }
    

    至少它可以更好地利用 IDE 工具。这对于具有大量组件的大型安装程序特别有用。然后,您还可以创建有序的单元测试并按顺序运行它们,以在调试或自动构建期间模仿您的安装程序。

    另一个技巧是通用 SOLID/GRASS 软件原则...在整洁/薄层中开发,保持您实际的“自定义操作”安装程序逻辑非常简单,而是调用您拥有的任何可重用 API 内容,这些内容特定于您的安装程序(s),就像我们习惯于 UI 开发一样。 (无论如何,安装程序只是另一个 UI。)如果您的目标是在产品的所有安装程序之间共享某种 UI 体验,这一点尤其重要。

    【讨论】:

      【解决方案6】:

      您还可以使用 installUtil.exe 实用程序来测试您的安装程序组件。

      如果您使用 Installer 类创建了 c# 类程序集,请更改调试设置以启动外部程序“C:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe” 并相应地输入你的命令行参数(例如 /Args=myargument "path to the assembly")

      与上次设置断点一样,按 f5 即可调试代码。 --视差

      【讨论】:

        【解决方案7】:

        我使用以下类将简单的日志写入目标目录。在我看来,这比尝试使用 Visual Studio 调试器更容易。

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        using System.IO;
        
        namespace MyCompany.Deployment
        {
            /// <summary>
            /// Enables a quick and easy method of debugging custom actions.
            /// </summary>
            class LogFile
            {
                const string FileName = "MyCompany.Deployment.log";
                readonly string _filePath;
        
                public LogFile(string primaryOutputPath)
                {
                    var dir = Path.GetDirectoryName(primaryOutputPath);
                    _filePath = Path.Combine(dir, FileName);
                }
        
                public void Print(Exception ex)
                {
                    File.AppendAllText(_filePath, "Error: " + ex.Message + Environment.NewLine +
                            "Stack Trace: " + Environment.NewLine + ex.StackTrace + Environment.NewLine);
                }
        
                public void Print(string format, params object[] args)
                {
                    var text = String.Format(format, args) + Environment.NewLine;
        
                    File.AppendAllText(_filePath, text);
                }
        
                public void PrintLine() { Print(""); }
            }
        }
        

        【讨论】:

          【解决方案8】:

          出于记录目的(在 3.5 中)如何使用:

          Context.LogMessage("My message");
          

          【讨论】:

            【解决方案9】:

            很惊讶没有人真正回答。将 MessageBox.Show("hello") 放入自定义操作的 Install() 成员中。在调试配置中构建部署。安装。当 MessageBox 出现时,进入 VS IDE、Debug、Attach Process 并查找标记为“Managed”的 msiexec 实例。将调试器附加到该 msiexec 实例。现在返回自定义操作的源并在调用 MessageBox.Show() 之后立即放置一个断点。关闭 MessageBox,您的断点将被命中,您正在 IDE 中进行调试!

            【讨论】:

            • +1:虽然确保Show All Processes复选框被选中可能值得注意。此外,可以GetCurrentProcess 并用Id 肯定地识别正确的过程。 :)
            • 当您可以致电System.Diagnostics.Debugger.Break() 时为什么要使用它?您必须添加 WindowsForms dll 才能使用 MessageBox。此外,对于 CustomInstallers,进程名称将为 InstallUtil。
            【解决方案10】:

            在您的安装程序方法中添加 Debugger.Launch() 语句,该语句将启动“Visual Studio 即时调试器”,您可以在其中附加一个 Visual Studio 实例并调试您的安装程序类 (MSI)。这也应该适用于 Visual Studio 2010。但是您需要具有管理权限才能执行此操作。如果您没有管理权限,您可能会遇到问题。因此,以管理员身份登录以调试 MSI。例如:

            public override void Install(System.Collections.IDictionary stateSaver)
            {
                Debugger.Launch();
                base.Install(stateSaver);
            
            }
            

            在 Visual Studio 2005 中,即使是 Debugger.Break() 也可以正常工作,但不知何故这不适用于 Visual Studio 2010。

            【讨论】:

            • +1 但您需要拥有管理权限才能执行此操作。这是唯一的答案,我认为这是我的问题。
            【解决方案11】:

            在要调试的方法的开头写下如下代码

            #if DEBUG
            MessageBox.Show(Process.GetCurrentProcess().Id.ToString());
            #endif
            

            所以当你的方法被调用时,上面的代码将被命中,然后你可以使用上面的进程 ID 将调试器附加到进程(ctrl+alt+p)。您可能必须以提升的权限启动 VS。

            【讨论】:

              【解决方案12】:

              您可以通过将以下部分添加到 .csproj 或 .csproj.user 文件来自动调试安装程序项目:

              <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
                <StartAction>Program</StartAction>
                <StartProgram>$(MSBuildBinPath)\installutil.exe</StartProgram>
                <StartArguments>$(AssemblyName).dll</StartArguments>
              </PropertyGroup>
              

              如果您希望其他开发人员从此更改中受益,请使用项目文件;如果您想自己使用,请使用 .user 文件。

              【讨论】:

                【解决方案13】:

                以上都不适合我。这实际上是有效的。请注意,您需要插入“两行”。

                using System.Diagnostics;
                
                MessageBox.Show("Test is about to begin");
                Debugger.Launch();
                

                【讨论】:

                  【解决方案14】:

                  这实际上对我有用。

                  System.Diagnostics.Debugger.Launch();
                  

                  然后右键单击安装程序项目并按“安装”

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2015-06-20
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-01-11
                    • 2014-05-24
                    • 1970-01-01
                    相关资源
                    最近更新 更多