龙行于水 發表於 2020-11-4 09:45:00

一路踩坑,被迫聊聊 C# 代码调试技巧和远程调试

<h2 id="一背景">一:背景</h2>
<h3 id="1-讲故事">1. 讲故事</h3>
<p>每次项目预交付的时候,总会遇到各种奇葩的坑,我觉得有必要梳理一下以及如何快速解决的,让后来人避避坑,这篇就聊聊自己的所闻所遇:</p>
<ul>
<li>我去,本地环境代码跑的哧溜,上了测试环境出问题</li>
<li>我去, 第三方提供的 dll 跑出 bug 了</li>
</ul>
<h2 id="二两个大坑的解决方案">二:两个大坑的解决方案</h2>
<h3 id="1-本地环境没问题上了测试出问题">1. 本地环境没问题,上了测试出问题</h3>
<p>相信很多朋友都有我这样类似的遭遇,明明程序代码,配置文件都一样,挪了一个窝就出问题,你说气人不,既然问题出了那怎么快速解决呢? 对,就是用调试,但程序部署在 centos 上,送一个 visualstudio 上去也不现实,在这种限制级条件下还想调试怎么办呢?不错,可以上远程调试,然后就很快查到了测试机器中的某一个环境变量搞错了,事情的来龙去脉搞清楚了,接下来就看看怎么实现 local 到 centos 的 远程调试。</p>
<h4 id="1-测试代码">1) 测试代码</h4>
<p>为了方便演示,我就在 Action 中读取 strategy 环境变量。</p>
<pre><code class="language-C#">
    public class HomeController : Controller
    {
      public IActionResult Index()
      {
            ViewBag.strategy = Environment.GetEnvironmentVariable("strategy");

            return View();
      }
    }

</code></pre>
<h4 id="2-安装-ssh">2) 安装 SSH</h4>
<p>要远程调试,需要在远端机安装 SSH,因为后面附加进程调试 就要借助 SSH 打通。</p>
<pre><code class="language-bash">
yum install openssh-server unzip curl

</code></pre>
<p>安装完成后,就能看到 22 端口已启动</p>
<pre><code class="language-bash">
# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address         Foreign Address         State       PID/Program name   
tcp      0      0 0.0.0.0:22            0.0.0.0:*               LISTEN      1126/sshd         
tcp      0      0 127.0.0.1:631         0.0.0.0:*               LISTEN      3037/cupsd         
tcp      0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      1739/master   
tcp6       0      0 :::22                   :::*                  LISTEN      1126/sshd         
tcp6       0      0 ::1:631               :::*                  LISTEN      3037/cupsd         
tcp6       0      0 ::1:25                  :::*                  LISTEN      1739/master

</code></pre>
<h4 id="3-程序的发布配置">3) 程序的发布配置</h4>
<p>发布配置上,第一个要确保是 debug 版本,第二个要确保是 可移植模式 (Portable), 如下图:</p>
<img src="https://img2020.cnblogs.com/other/214741/202011/214741-20201104094518165-1477483385.png" width="600" alt="图片名称" align="center">
<h4 id="4-使用附加进程调试">4) 使用附加进程调试</h4>
<p>在菜单栏依次选择:Debug -&gt;Attach To Process,然后填写 ssh 需要的各种信息,如下图:</p>
<img src="https://img2020.cnblogs.com/other/214741/202011/214741-20201104094518622-402625700.png" width="600" alt="图片名称" align="center">
<p>点击 Connect 后,就能看到远端机器的 dotnet程序 进程号,选择该进程进行附加,在 Select Code Type 中选择 <code>Nanaged (.NET Core for Unix)</code>即可,如下图:</p>
<img src="https://img2020.cnblogs.com/other/214741/202011/214741-20201104094518839-1624161425.png" width="600" alt="图片名称" align="center">
<h4 id="5-顺利调试">5) 顺利调试</h4>
<p>在 浏览器中键入: <code>http://192.168.142.130/Home/Index</code> ,可以看到我的 C# 代码被命中,也顺利的拿到了远端机器的 环境变量,问题也就迎刃而解。</p>
<img src="https://img2020.cnblogs.com/other/214741/202011/214741-20201104094519102-811929746.png" width="600" alt="图片名称" align="center">
<h3 id="2-第三方-dll-出-bug-了">2. 第三方 dll 出 bug 了</h3>
<p>调试程序除了使用 F9 进行调试,相信也有不少朋友知道断点是可以编辑的,比如说:设置表达式断点,过滤器断点,命中次数断点,动作断点,下如图:</p>
<p><img src="https://img2020.cnblogs.com/other/214741/202011/214741-20201104094519461-1550369286.png" alt="" loading="lazy"></p>
<p>第一个问题就来了,这些花式断点,你真的会用吗?真的会经常用吗?</p>
<p>让我来回答的话,不到万不得已我是不会用的,我更愿意在代码中加入利于调试的测试语句,原因有三点:</p>
<ul>
<li>更加灵活</li>
</ul>
<p>这个显而易见,在面板中设置条件相比用纯语句设置要麻烦得多,点来点去,而且还要条件叠加,复杂的很,我是不喜欢。</p>
<ul>
<li>功能强大</li>
</ul>
<p>编辑面板上只有简单的并且关系,而且各个条件还是同级别的,无法做到各个条件的或者关系以及层级或者递归的包含关系,所以。。。没办法。。。</p>
<ul>
<li>更易于保存</li>
</ul>
<p>这个就有意思了,在断点上右键是弹出编辑面板,点击左键是关闭断点,问题就出在这里,经常由于手贱,本想点右键结果点了左键 😨😨😨。。。。 好不容易设置好的条件没了。。。真的没了😭😭😭,从此以后,路转黑。如下图:</p>
<p><img src="https://img2020.cnblogs.com/other/214741/202011/214741-20201104094519725-283718634.png" alt="" loading="lazy"></p>
<p>那这么说断点编辑真的没用吗? 我觉得只有在不能修改语句的调试场景下能够大显身手,比如我遇到的调试厂家封装的dll,哈哈,既然说到了断点,我就用 dnspy 演示几个断点给大家复习一下吧!</p>
<h4 id="1-测试代码-1">1) 测试代码</h4>
<p>为方便演示,用 for 循环案例是最好的。</p>
<pre><code class="language-C#">
      public static void Main(string[] args)
      {
            var sum = 0;

            for (int i = 0; i &lt; 10000; i++)
            {
                sum += i;
            }

            Console.WriteLine($"sum={sum}");
      }

</code></pre>
<h4 id="2-我希望在-sum--1035-的时候命中断点">2) 我希望在 sum = 1035 的时候命中断点</h4>
<p>这个用条件表达式断点就可以了,非常简单,如下所示:</p>
<img src="https://img2020.cnblogs.com/other/214741/202011/214741-20201104094520013-1681633501.png" width="600" height="200" alt="图片名称" align="center">
<h4 id="3-找到所有能够被-1800-整除的数并且记录下当时的-i-和-sum-值">3) 找到所有能够被 1800 整除的数,并且记录下当时的 i 和 sum 值</h4>
<p>这里就可以用到 Action 断点的日志记录,在 for 循环迭代中,不需要中断断点,只需记录某一个特定状态下当前的 i 和 sum 的值,对调试代码非常有帮助,如下图:</p>
<img src="https://img2020.cnblogs.com/other/214741/202011/214741-20201104094520446-1069716446.png" width="600" height="200" alt="图片名称" align="center">
<h2 id="三总结">三:总结</h2>
<p>总的来说这两个经验也算我一步一步踩坑过来的,如果能帮到你就更好了,本篇就聊这么多,下篇再见!</p>
<p><strong>更多高质量干货:参见我的 GitHub: dotnetfly</strong></p>
<img src="https://img2020.cnblogs.com/blog/214741/202005/214741-20200522143723695-575216767.png" width="600" height="200" alt="图片名称" align="center"><br><br>
来源:https://www.cnblogs.com/huangxincheng/p/13924326.html
頁: [1]
查看完整版本: 一路踩坑,被迫聊聊 C# 代码调试技巧和远程调试