第 1 部分:将 Contoso Expenses 应用迁移到 .NET Core 3

这是教程的第一部分,演示如何现代化名为 Contoso Expenses 的示例 WPF 桌面应用。 有关下载示例应用的教程、先决条件和说明的概述,请参阅 教程:现代化 WPF 应用

本教程的这一部分将整个 Contoso Expenses 应用从 .NET Framework 4.7.2 迁移到 .NET Core 3。 在开始本教程的这一部分之前,请确保在 Visual Studio 2019 中 打开并生成 ContosoExpenses 示例

注释

有关将 WPF 应用程序从 .NET Framework 迁移到 .NET Core 3 的详细信息,请参阅 此博客系列

将 ContosoExpenses 项目迁移到 .NET Core 3

在本部分中,你将 Contoso Expenses 应用中的 ContosoExpenses 项目迁移到 .NET Core 3。 为此,需要创建一个新的项目文件,该文件包含与现有 ContosoExpenses 项目相同的文件,但面向 .NET Core 3 而不是 .NET Framework 4.7.2。 这使您能够维护一个包含 .NET Framework 和 .NET Core 版本的统一解决方案。

  1. 验证 ContosoExpenses 项目当前是否面向 .NET Framework 4.7.2。 在解决方案资源管理器中,右键单击 ContosoExpenses 项目,选择 属性,并确认 应用程序 选项卡上的 目标框架 属性设置为 .NET Framework 4.7.2。

    为项目 制作的 .NET Framework 版本 4.7.2

  2. 在 Windows 资源管理器中,导航到 C:\WinAppsModernizationWorkshop\Lab\Exercise1\01-Start\ContosoExpenses 文件夹,并创建名为 ContosoExpenses.Core.csproj 的新文本文件。

  3. 右键单击该文件,选择 打开,然后在所选的文本编辑器(如记事本、Visual Studio Code 或 Visual Studio)中打开该文件。

  4. 将以下文本复制到该文件并保存。

    <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
    
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>netcoreapp3.0</TargetFramework>
        <UseWPF>true</UseWPF>
     </PropertyGroup>
    
    </Project>
    
  5. 关闭该文件并返回到 Visual Studio 中的 ContosoExpenses 解决方案。

  6. 右键单击 ContosoExpenses 解决方案,然后选择 “添加 -> 现有项目”。 选择刚在C:\WinAppsModernizationWorkshop\Lab\Exercise1\01-Start\ContosoExpenses文件夹中创建的 ContosoExpenses.Core.csproj 文件,将其添加到解决方案。

ContosoExpenses.Core.csproj 包含以下元素:

  • Project 元素指定 Microsoft.NET.Sdk.WindowsDesktop 的 SDK 版本。 这指的是适用于 Windows 桌面的 .NET 应用程序,它包括 WPF 和 Windows 窗体应用的组件。
  • PropertyGroup 元素包含子元素,这些子元素指示项目输出是可执行文件(而不是 DLL),面向 .NET Core 3 并使用 WPF。 对于 Windows Forms 应用程序,应使用 UseWinForms 元素,而不是 UseWPF 元素。

注释

使用 .NET Core 3.0 引入的 .csproj 格式时,与 .csproj 相同的文件夹中的所有文件都被视为项目的一部分。 因此,无需指定项目中包含的每个文件。 仅需指定要为其定义自定义生成操作或要排除的文件。

将 ContosoExpenses.Data 项目迁移到 .NET Standard

ContosoExpenses 解决方案包括一个 ContosoExpenses.Data 类库,该库中含有用于服务的模型和接口,并以 .NET 4.7.2 为目标。 只要 .NET Core 3.0 应用不使用 .NET Core 中不可用的 API,就可以使用 .NET Framework 库。 但是,最佳现代化路径是将库移动到 .NET Standard。 确保您的库得到 .NET Core 3.0 应用的充分支持。 此外,还可以与其他平台(如 Web)重复使用库(通过 ASP.NET Core)。

ContosoExpenses.Data 项目迁移到 .NET Standard:

  1. 在 Visual Studio 中,右键单击 ContosoExpenses.Data 项目,然后选择 “卸载项目”。 再次右键单击项目,然后选择 “编辑 ContosoExpenses.Data.csproj”。

  2. 删除项目文件的整个内容。

  3. 复制并粘贴以下 XML 并保存文件。

    <Project Sdk="Microsoft.NET.Sdk">
    
      <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
      </PropertyGroup>
    
    </Project>
    
  4. 右键单击 ContosoExpenses.Data 项目,然后选择重新加载项目

配置 NuGet 包和依赖项

在前面的部分迁移 ContosoExpenses.CoreContosoExpenses.Data 项目时,你从项目中删除了 NuGet 包引用。 在本部分中,你将将这些引用添加回去。

若要为 ContosoExpenses.Data 项目配置 NuGet 包,请执行以下作:

  1. ContosoExpenses.Data 项目中,展开 依赖项 节点。 请注意,缺少 NuGet 部分。

    NuGet 包

    如果在 解决方案资源管理器中打开 Packages.config 在使用完整 .NET Framework 时,会找到使用该项目的 NuGet 包的“旧”引用。

    依赖项和包

    下面是 Packages.config 文件的内容。 你会注意到,所有的 NuGet 包都针对完整的 .NET Framework 4.7.2。

    <?xml version="1.0" encoding="utf-8"?>
    <packages>
      <package id="Bogus" version="26.0.2" targetFramework="net472" />
      <package id="LiteDB" version="4.1.4" targetFramework="net472" />
    </packages>
    
  2. ContosoExpenses.Data 项目中,删除 Packages.config 文件。

  3. ContosoExpenses.Data 项目中,右键单击 “依赖项 ”节点,然后选择“ 管理 NuGet 包”。

管理 NuGet 软件包...

  1. NuGet 包管理器 窗口中,单击 浏览。 搜索 Bogus 包并安装最新的稳定版本。

    虚假的 NuGet 包

  2. 搜索 LiteDB 包并安装最新的稳定版本。

    LiteDB NuGet 包

    你可能想知道这些 NuGet 包列表的存储位置,因为项目不再具有 packages.config 文件。 引用的 NuGet 包直接存储在 .csproj 文件中。 可以通过在文本编辑器中查看 ContosoExpenses.Data.csproj 项目文件的内容来检查此项。 你将在文件末尾找到以下行:

    <ItemGroup>
       <PackageReference Include="Bogus" Version="26.0.2" />
       <PackageReference Include="LiteDB" Version="4.1.4" />
    </ItemGroup>
    

    注释

    你可能还会发现,您在为这个 .NET Core 3 项目安装的包与用于 .NET Framework 4.7.2 项目的包相同。 NuGet 包支持多目标。 库作者可以在同一包中包含不同版本的库,这些版本针对不同的体系结构和平台进行编译。 这些包支持完整的 .NET Framework 以及与 .NET Core 3 项目兼容的 .NET Standard 2.0。 有关 .NET Framework、.NET Core 和 .NET Standard 的差异的详细信息,请参阅 .NET Standard

若要为 ContosoExpenses.Core 项目配置 NuGet 包,请执行以下作:

  1. ContosoExpenses.Core 项目中,打开 packages.config 文件。 请注意,它当前包含面向 .NET Framework 4.7.2 的以下引用。

    <?xml version="1.0" encoding="utf-8"?>
    <packages>
      <package id="CommonServiceLocator" version="2.0.2" targetFramework="net472" />
      <package id="MvvmLightLibs" version="5.4.1.1" targetFramework="net472" />
      <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net472" />
      <package id="Unity" version="5.10.2" targetFramework="net472" />
    </packages>
    

    在以下步骤中,你将处理 MvvmLightLibsUnity 包的 .NET Standard 版本。 另外两个是安装这两个库时 NuGet 自动下载的依赖项。

  2. ContosoExpenses.Core 项目中,删除 Packages.config 文件。

  3. 右键单击 ContosoExpenses.Core 项目,然后选择 管理 NuGet 包

  4. NuGet 包管理器 窗口中,单击 浏览。 搜索 Unity 包并安装最新的稳定版本。

    Unity 包

  5. 搜索 MvvmLightLibsStd10 包并安装最新的稳定版本。 这是 .NET Standard 版本的 MvvmLightLibs 包。 对于此包,作者选择将库的 .NET Standard 版本打包到与 .NET Framework 版本不同的包中。

    MvvmLightsLibs 包

  6. ContosoExpenses.Core 项目中,右键单击 “依赖项 ”节点,然后选择“ 添加引用”。

  7. 在“项目 > 解决方案”类别中,选择 ContosoExpenses.Data,然后单击 “确定”

    添加引用

禁用自动生成的程序集属性

在迁移过程中,如果尝试生成 ContosoExpenses.Core 项目,将看到一些错误。

.NET Core 3 生成新错误

之所以发生此问题,是因为 .NET Core 3.0 中引入的新 .csproj 格式将程序集信息存储在项目文件中,而不是 AssemblyInfo.cs 文件。 若要修复这些错误,请禁用此行为,让项目继续使用 AssemblyInfo.cs 文件。

  1. 在 Visual Studio 中,右键单击 ContosoExpenses.Core 项目,然后选择 “卸载项目”。 再次右键单击项目,然后选择 “编辑 ContosoExpenses.Core.csproj”。

  2. PropertyGroup 节中添加以下元素并保存文件。

    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    

    添加此元素后, PropertyGroup 部分现在应如下所示:

    <PropertyGroup>
      <OutputType>WinExe</OutputType>
      <TargetFramework>netcoreapp3.0</TargetFramework>
      <UseWPF>true</UseWPF>
      <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    </PropertyGroup>
    
  3. 右键单击 ContosoExpenses.Core 项目,然后选择 重载项目

  4. 右键单击 ContosoExpenses.Data 项目,然后选择 卸载项目。 再次右键单击项目,然后选择 “编辑 ContosoExpenses.Data.csproj”。

  5. PropertyGroup 节中添加相同的条目并保存文件。

    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    

    添加此元素后, PropertyGroup 部分现在应如下所示:

    <PropertyGroup>
      <TargetFramework>netstandard2.0</TargetFramework>
      <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    </PropertyGroup>
    
  6. 右键单击 ContosoExpenses.Data 项目,然后选择重新加载项目

添加 Windows 兼容性包

如果现在尝试编译 ContosoExpenses.CoreContosoExpenses.Data 项目,你将看到以前的错误现已修复,但 ContosoExpenses.Data 库中仍有一些类似错误。

Services\RegistryService.cs(9,26,9,34): error CS0103: The name 'Registry' does not exist in the current context Services\RegistryService.cs(12,26,12,34): error CS0103: The name 'Registry' does not exist in the current context Services\RegistryService.cs(12,97,12,123): error CS0103: The name 'RegistryKeyPermissionCheck' does not exist in the current context

这些错误是将 ContosoExpenses.Data 项目从 .NET Framework 库(特定于 Windows)转换为 .NET Standard 库的结果,该库可以在 Linux、Android、iOS 等多个平台上运行。 ContosoExpenses.Data 项目包含一个名为 RegistryService 的类,该类与注册表交互(仅限 Windows 的概念)。

若要解决这些错误,请安装 Windows 兼容性 NuGet 包。 此包支持在 .NET Standard 库中使用许多特定于 Windows 的 API。 使用此包后,库将不再是跨平台的,但它仍将面向 .NET Standard。

  1. 右键单击 ContosoExpenses.Data 项目。

  2. 选择 管理 NuGet 包

  3. NuGet 包管理器 窗口中,单击 浏览。 搜索 Microsoft.Windows.Compatibility 包并安装最新的稳定版本。

    安装 NuGet 包

  4. 现在再次尝试编译项目,方法是右键单击 ContosoExpenses.Data 项目,然后选择“生成”

这次构建过程将会顺利完成,不会出错。

测试和调试迁移

成功生成项目后,即可运行并测试应用,以查看是否存在任何运行时错误。

  1. 右键单击 ContosoExpenses.Core 项目,然后选择“ 设置为启动项目”。

  2. 按 F5 在调试器中启动 ContosoExpenses.Core 项目。 你会看到类似下面这样的异常。

    Visual Studio 中显示的异常

    之所以引发此异常,是因为在迁移开始时从 .csproj 文件中删除内容时,删除了有关映像文件的 生成作 的信息。 以下步骤修复了此问题。

  3. 停止调试器。

  4. 右键单击 ContosoExpenses.Core 项目,然后选择 卸载项目。 再次右键单击项目,然后选择 “编辑 ContosoExpenses.Core.csproj”。

  5. 在结束 Project 元素之前,添加以下条目:

    <ItemGroup>
      <Content Include="Images/*">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
    
  6. 右键单击 ContosoExpenses.Core 项目,然后选择 重载项目

  7. 若要将Contoso.ico分配给应用,请右键单击 ContosoExpenses.Core 项目,然后选择 “属性”。 在打开的页面中,单击 “图标 ”下的下拉列表,然后选择 Images\contoso.ico

    项目属性 中的 Contoso 图标

  8. 单击“ 保存”。

  9. 按 F5 在调试器中启动 ContosoExpenses.Core 项目。 确认应用现在运行。

后续步骤

在本教程中,你已成功将 Contoso Expenses 应用迁移到 .NET Core 3。 现已准备好 第 2 部分:使用 XAML 岛添加 UWP InkCanvas 控件。

注释

如果你有高分辨率屏幕,你可能会注意到应用看起来很小。 在本教程的下一步中,你将解决此问题。