找出 .NET Core SDK 是否使用预览版的全局配置文件在哪里(探索篇)

你是否好奇 Visual Studio 2019 中的 .NET Core SDK 预览版开关是全局生效的,那个全局的配置在哪里呢?

本文将和你一起探索找到这个全局的配置文件。


使用 Process Monitor 探索

下载 Process Monitor

Process Monitor 是微软极品工具箱的一部分,你可以在此页面下载:

打开 Process Monitor

当你一开始打开 Process Monitor 的时候,列表中会立刻刷出大量的进程的操作记录。这么多的记录会让我们找到目标进程操作的文件有些吃力,于是我们需要设置规则。

Process Monitor 的工具栏按钮并不多,而且我们这一次的目标只会用到其中的两个:

Process Monitor 的工具栏按钮

设置过滤规则

在工具栏上点击“设置过滤器”,然后,添加我们感兴趣的两个进程名称:

前者是 Visual Studio 的进程名,后者是 MSBuild.exe 的进程名。我们使用这两个进程名称分别找到 Visual Studio 2019 是如何设置全局 .NET Core 预览配置的,并且在命令行中运行 MSBuild.exe 来验证确实是这个全局配置。

然后排除除了文件意外的所有事件类型,最终是如下过滤器:

设置过滤器

捕获 devenv.exe

现在,我们打开 Visual Studio 2019,然后停留到下面这个界面中。改变一下 .NET Core SDK 预览版选项的勾选状态。

设置 Visual Studio 2019 使用 .NET Core SDK 预览版

现在,我们点击一下“确定”,将立即可以在 Process Monitor 中看到一些文件的修改:

捕获到的文件修改

上面是在点击“确定”按钮一瞬间 Visual Studio 2019 的所有文件操作。你可以注意到左侧的时间,我的截图中从 45 秒到 48 秒是可能有效的文件读写,再后面已经延迟了 10 秒了,多半是其他的操作。

在这些文件中,可以很明显看到文件分为三类:

通过排除法,我们能得知最关键的文件就是那个 sdk.txt。去看一看那个文件的内容,发现只有一行:

UsePreviews=True

这基本上可以确认 Visual Studio 2019 设置是否使用 .NET Core SDK 预览版就是在这个文件中。

不过,这带来一个疑惑,就是这个路径特别不像是 .NET Core SDK 的配置路径,倒像是 Visual Studio 自己的设置配置。

于是必须通过其他途径来确认这是否就是真实的全局配置。

捕获 MSBuild.exe

现在,我们清除一下 Process Monitor 中的已经记录的数据,然后,我们在命令行中对一个项目敲下 msbuild 命令。

> msbuild

然后在 Process Monitor 里面观察事件。这次发现事件相当多,于是换个方式。

因为我们主要是验证 sdk.txt 文件,但同时希望看看是否还有其他文件。于是我们将 sdk.txt 文件相关的事件高亮。

点击 Filter -> Highlight...,然后选择 Path contains sdk.txt 时则 Include

打开 Highlight

高亮 sdk.txt 文件

这时,再看捕获到的事件,可以发现编译期间确实读取了这个文件。

MSBuild.exe 读取了 sdk.txt

此举虽不能成为此文件是全局配置的铁证,但至少说明这个文件与全局配置非常相关。

另外,继续在记录中翻找,还可以发现与此配置可能相关的两个 dll:

可能与此相关的 dll

验证结论

要验证此文件确实是全局配置其实也很简单,自行改一改配置,然后使用 MSBuild.exe 编译试试即可。

现在,将 sdk.txt 文件内容改为:

UsePreviews=False

编译一下使用了 .NET Core 3.0 新特性的项目(我使用了 Microsoft.NET.Sdk.WindowsDesktop,这是 3.0 才有的 SDK)。

不使用预览版编译

编译错误,提示 Microsoft.NET.Sdk.WindowsDesktop 这个 SDK 没有找到。

现在,将 sdk.txt 文件内容改为:

UsePreviews=True

编译相同的项目,发现可以正常编译通过了。

使用预览版编译

这可以证明,此文件正是决定是否使用预览版的决定性证据。

其他

但值得注意的是,打开 Visual Studio 2019 后,发现其设置界面并没有应用此文件最新的修改,这可以说 Visual Studio 2019 的配置是不止这一处。

反编译探索

通过反编译探索的方式感谢小伙伴 KodamaSakuno (神樹桜乃) 彻夜寻找。

相关的代码在 cli/VSSettings.cs at master · dotnet/cli 中,你可以前往查看。

VSSettings 的构造函数中,为字段 _settingsFilePath 赋值,拼接了 sdk.txt 文件的路径。

_settingsFilePath = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
    "Microsoft",
    "VisualStudio",
    version.Major + ".0_" + instanceId,
    "sdk.txt");

读取时,使用此路径下的 sdk.txt 文件读取了 UsePreviews 变量的值。

private void ReadFromDisk()
{
    using (var reader = new StreamReader(_settingsFilePath))
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            int indexOfEquals = line.IndexOf('=');
            if (indexOfEquals < 0 || indexOfEquals == (line.Length - 1))
            {
                continue;
            }

            string key = line.Substring(0, indexOfEquals).Trim();
            string value = line.Substring(indexOfEquals + 1).Trim();

            if (key.Equals("UsePreviews", StringComparison.OrdinalIgnoreCase)
                && bool.TryParse(value, out bool usePreviews))
            {
                _disallowPrerelease = !usePreviews;
                return;
            }
        }
    }

    // File does not have UsePreviews entry -> use default
    _disallowPrerelease = _disallowPrereleaseByDefault;
}

blog bulletin

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/find-out-the-dotnet-sdk-preview-config-file.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

如果你想持续阅读我的最新博客,请点击 RSS 订阅,或者前往 CSDN 关注我的主页

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com)