Linux 上的 .NET:比看起來簡單

已發表: 2022-08-16

在 Linux 上開發 .NET 解決方案一直具有挑戰性,因為 Microsoft 的 Visual Studio 需要 Windows 才能工作。 在完成了幾個 .NET 項目之後,我決定在 Linux 上測試 .NET 的開發極限。 這個簡單的教程側重於一個帶有 SQL Server 的 ASP.NET MVC 應用程序,以展示在我首選的操作系統上進行 .NET 開發是多麼優雅和有效。

開發環境

首先,我們必須確保使用 Microsoft 的標準指南安裝與我們的特定 Linux 風格相關的 .NET 工具和 SDK。

我首選的開發環境包括一個窗口集成開發環境 (IDE)、一個強大的數據庫管理和查詢工具、數據庫本身以及用於構建和部署的工具。 我使用以下工具來實現可靠的功能並實現美妙的編碼體驗:

  • IDE:Visual Studio 代碼
  • 數據庫管理和查詢工具:DBeaver
  • 數據庫:Microsoft SQL Server(Linux 安裝)
  • 構建工具:.NET SDK 命令行界面 (CLI)
  • 虛擬機和容器:Docker

在繼續我們的示例應用程序之前,請確保已正確安裝這些工具。

項目腳手架

在這個示例應用程序中,我們將通過一系列假設鞋店庫存管理系統的用例來強調 ASP.NET 的開發和功能。 與任何新的 .NET 應用程序一樣,我們需要創建一個解決方案,然後向其中添加一個項目。 我們可以利用 .NET SDK CLI 工具來構建我們的新解決方案:

 mkdir Shoestore && cd Shoestore dotnet new sln

接下來,為簡單起見,創建一個包含顯式主類的 ASP.NET 項目,因為 ASP.NET 開發人員最熟悉此項目結構。 讓我們使用 MVC 模式創建我們的項目:

 mkdir Shoestore.mvc && cd Shoestore.mvc dotnet new mvc --use-program-main=true

接下來,將項目添加到解決方案中:

 # Go to the root of the solution cd .. dotnet sln add Shoestore.mvc/

我們現在有一個默認解決方案及其包含的 ASP.NET 項目。 在繼續之前,請確保一切都已構建:

 cd Shoestore.mvc/ dotnet restore dotnet build

良好的開發實踐鼓勵將關鍵服務和應用程序運行時放入 Docker 容器中,以改進部署和可移植性。 因此,讓我們創建一個簡單的 Docker 容器來支持我們的應用程序。

應用程序可移植性

Docker 鏡像通常引用另一個父 Docker 鏡像作為基本要求(如操作系統和基本解決方案(包括數據庫))的公認起點。 遵循此 Docker 最佳實踐,創建 Dockerfile 和 Docker Compose 文件以在引用 Microsoft 發布的父映像時進行正確的服務配置。 我們將使用 Docker 階段來保持我們的鏡像小。 階段允許我們在構建應用程序時使用 .NET SDK,以便僅在應用程序運行時才需要 ASP.NET 運行時。

使用以下內容創建Shoestore.mvc Dockerfile:

 # Shoestore\Shoestore.mvc\Dockerfile # Build stage FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /shoestore COPY Shoestore.mvc/*.csproj ./ # Restore project packages RUN dotnet restore COPY Shoestore.mvc/* ./ # Create a release build RUN dotnet build -c Release -o /app/build # Run the application and make it available on port 80 FROM mcr.microsoft.com/dotnet/aspnet:6.0 WORKDIR /app EXPOSE 80 # Assets and views COPY Shoestore.mvc/Views ./Views COPY Shoestore.mvc/wwwroot ./wwwroot COPY --from=build /app/build ./ ENTRYPOINT [ "dotnet", "Shoestore.mvc.dll" ]

接下來,我們將在解決方案的根目錄中創建docker-compose.yml文件。 最初,它將僅包含對我們應用程序服務的.Dockerfile的引用:

 # Shoestore/docker-compose.yml version: "3.9" services: web: build: context: . dockerfile: Shoestore.mvc/Dockerfile ports: - "8080:80"

讓我們還使用 .dockerignore 文件配置我們的環境,以確保僅將構建工件複製到我們的映像中。

現在我們的應用程序服務已經存根,並且它的執行環境準備好運行,我們需要創建我們的數據庫服務並將其連接到我們的 Docker 配置。

數據庫服務

將 Microsoft SQL Server 添加到我們的 Docker 配置中很簡單,尤其是因為我們使用的是 Microsoft 提供的 Docker 映像而不更改它。 將以下配置塊添加到docker-compose.yml文件的底部以配置數據庫:

 db: image: "mcr.microsoft.com/mssql/server" environment: SA_PASSWORD: "custom_password_123" ACCEPT_EULA: "Y" ports: - "1433:1433"

在這裡, ACCEPT_EULA防止安裝停止,我們的ports設置允許默認 SQL Server 端口通過而不進行轉換。 這樣,我們的 Compose 文件就包含了我們的應用程序服務和數據庫。

在自定義應用程序代碼之前,讓我們驗證一下我們的 Docker 環境是否正常工作:

 # From the root of the solution docker compose up --build

假設在啟動過程中沒有出現錯誤,我們不完整的示例應用程序應該可以通過本地地址http://localhost:8080的 Web 瀏覽器訪問。

代碼生成工具

現在我們開始關注有趣的部分:自定義應用程序代碼並確保應用程序數據保留在 Microsoft SQL Server 數據庫中。 我們將使用實體框架 (EF) 和 .NET SDK 工具將應用程序連接到數據庫,並為應用程序的模型、視圖、控制器和 EF 所需的配置搭建基架。

在我們可以指定我們需要的工具之前,我們必須創建一個tool-manifest文件:

 # From the root of the solution dotnet new tool-manifest

使用以下簡單命令將 EF 和 SDK 工具添加到此文件:

 dotnet tool install dotnet-ef dotnet tool install dotnet-aspnet-codegenerator

要驗證這些工具的正確安裝,請運行dotnet ef 。 如果出現獨角獸,則它們已正確安裝。 接下來,運行dotnet aspnet-codegenerator來測試 ASP.NET 工具; 輸出應該是一個通用的 CLI 使用塊。

現在我們可以使用這些工具來創建我們的應用程序。

MVC:模型

構建我們的應用程序的第一個任務是創建模型。 由於此模型稍後將添加到數據庫中,因此我們將在項目中包含 MS SQL Server 和 EF 包:

 cd Shoestore.mvc/ dotnet add package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.EntityFrameworkCore.Tools dotnet restore

接下來,創建一個 EF 數據庫上下文對象,該對象確定將哪些模型添加到數據庫中,並允許我們的代碼輕鬆訪問和查詢數據庫中的數據。

創建一個Data目錄來存放特定於 EF 的代碼,並創建包含以下內容的Data/ApplicationDBContext.cs文件:

 // Shoestore/Shoestore.mvc/Data/ApplicationDBContext.cs using Microsoft.EntityFrameworkCore; namespace Shoestore.mvc.Data; public class ApplicationDBContext : DbContext { public ApplicationDBContext(DbContextOptions<ApplicationDBContext> options):base(options){} }

接下來,配置數據庫連接字符串,它必須與我們在Dockerfile中配置的憑據匹配。 將Shoestore/Shoestore.mvc/appsettings.json的內容設置為以下內容:

 { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "Shoestore": "Server=db;Database=master;User=sa;Password=custom_password_123;" } }

配置好數據庫連接字符串並編碼數據庫上下文後,我們就可以編寫應用程序的Main函數了。 我們將包括數據庫異常處理以簡化系統調試。 此外,由於生成代碼中的 .NET 錯誤會導致 Docker 容器錯誤地為我們的視圖提供服務,因此我們需要將特定代碼添加到我們的視圖服務配置中。 這將在我們的 Docker 映像中顯式設置文件路徑到我們的視圖位置:

 using Microsoft.EntityFrameworkCore; using Shoestore.mvc.Data; namespace Shoestore.mvc; // ... public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Associate our EF database context and configure it with our connection string var connectionString = builder.Configuration.GetConnectionString("Shoestore"); builder.Services.AddDbContext<ApplicationDBContext>( options => options.UseSqlServer(connectionString)); // Middleware to catch unhandled exceptions and display a stack trace builder.Services.AddDatabaseDeveloperPageExceptionFilter(); // Add services to the container. // ASP.NET has a known issue where the final built app doesn't know where the view // files are (in the Docker container). // The fix is to specifically add view locations. builder.Services .AddControllersWithViews() .AddRazorOptions(options => { options.ViewLocationFormats.Add("/{1}/{0}.cshtml"); options.ViewLocationFormats.Add("/Shared/{0}.cshtml"); });

跳到同一文件中的IsDevelopment if語句,以便在系統處於開發模式時將數據庫遷移端點添加到我們的系統。 使用以下代碼添加else語句:

 // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { // Leave the contents of the if block alone. These are hidden for clarity. } else { app.UseMigrationsEndPoint(); }

接下來,運行快速測試以確保新包和源代碼編輯正確編譯:

 // Go to mvc directory cd Shoestore.mvc dotnet restore dotnet build

現在,讓我們通過創建Shoestore.mvc\Models\Shoe.cs文件來使用我們的必填字段填充模型:

 namespace Shoestore.mvc.Models; public class Shoe { public int ID { get; set; } public string? Name { get; set; } public int? Price { get; set; } public DateTime CreatedDate { get; set; } }

EF 根據關聯模型、其上下文文件以及我們應用程序中的任何 EF 代碼生成 SQL。 然後根據需要翻譯 SQL 結果並返回給我們的代碼。 如果我們將Shoe模型添加到數據庫上下文中,EF 將知道如何在 MS SQL Server 和我們的應用程序之間進行轉換。 讓我們在數據庫上下文文件中執行此操作, Shoestore/Shoestore.mvc/Data/ApplicationDBContext.cs

 using Microsoft.EntityFrameworkCore; using Shoestore.mvc.Models; namespace Shoestore.mvc.Data; public class ApplicationDBContext : DbContext { public ApplicationDBContext(DbContextOptions<ApplicationDBContext> options) : base(options) { } private DbSet<Shoe>? _shoe { get; set; } public DbSet<Shoe> Shoe { set => _shoe = value; get => _shoe ?? throw new InvalidOperationException("Uninitialized property" + nameof(Shoe)); } }

最後,我們將使用數據庫遷移文件將模型導入數據庫。 EF 工具根據數據庫上下文及其關聯模型(即Shoe )創建特定於 MS SQL Server 的遷移文件:

 cd Shoestore.mvc/ dotnet ef migrations add InitialCreate

讓我們推遲運行遷移,直到我們有一個控制器和視圖到位。

MVC:控制器和視圖

我們將使用 ASP.NET 代碼生成工具創建我們的控制器。 這個工具非常強大,但需要特定的幫助類。 對基本控制器結構及其 EF 集成使用Design風格的包。 讓我們添加這些包:

 cd Shoestore.mvc\ dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design && \ dotnet add package Microsoft.EntityFrameworkCore.Design && \ dotnet restore

現在,創建我們的默認控制器就像調用以下命令一樣簡單:

 cd Shoestore.mvc\ dotnet dotnet-aspnet-codegenerator controller \ -name ShoesController \ -m Shoe \ -dc ApplicationDBContext \ --relativeFolderPath Controllers \ --useDefaultLayout \ --referenceScriptLibraries

當代碼生成器創建我們的控制器時,它也會為該控制器創建一個簡單的視圖。 隨著我們的 MVC 基礎完成,我們已準備好讓一切運行起來。

遷移和應用測試

EF 遷移通常是一件簡單的事情,但是當涉及到 Docker 時,過程變得更加複雜。 在我們系列的下一篇文章中,我們將探索使這些遷移在我們的 Docker 解決方案中工作的奇妙曲折路徑,但現在,我們只希望我們的遷移運行。

所有配置和遷移文件都包含在我們的存儲庫中。 讓我們將整個項目克隆到我們的​​本地機器並執行遷移:

 git clone https://github.com/theZetrax/dot-net-on-linux.git cd ./dot-net-on-linux docker composer up

docker composer操作構建我們的應用程序,運行遷移,並使用 .NET 運行時啟動我們的 ASP.NET 應用程序。 要訪問正在運行的解決方案,請訪問http://localhost:8080/Shoes

儘管我們的應用程序界面很簡單,但它展示了從視圖到數據庫的所有層級的功能。

Linux 上的 .NET 可以正常工作

有關我們解決方案的概述,請參閱完整的存儲庫。 下一篇文章將詳細介紹我們的遷移,以及使我們的 Docker 鏡像更精簡的提示和技巧。

Linux 上的 .NET 不僅僅是一個白日夢:它是一種可行的語言、運行時和操作系統的組合。 許多在 Visual Studio 上長大的開發人員可能沒有充分使用 .NET CLI 的經驗,但這些工具既有效又強大。

進一步閱讀 Toptal 工程博客:

  • 使用 ASP.NET Core 構建 ASP.NET Web API
  • Microsoft Stack 仍然是可行選擇的 8 個原因
  • 如何通過緩存提高 Web Farm 中的 ASP.NET 應用程序性能
  • .NET 開發人員的 Elasticsearch 教程
  • 什麼是 Kubernetes? 容器化和部署指南

Toptal 工程博客對 Henok Tsegaye 對本文中提供的代碼示例的審閱表示感謝。