亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用.NET?6開發TodoList應用引入數據存儲

發布時間:2021-12-23 13:32:55 來源:億速云 閱讀:142 作者:iii 欄目:開發技術

本篇內容主要講解“怎么使用.NET 6開發TodoList應用引入數據存儲”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么使用.NET 6開發TodoList應用引入數據存儲”吧!

需求

作為后端CRUD程序員(bushi,數據存儲是開發后端服務一個非常重要的組件。對我們的TodoList項目來說,自然也需要配置數據存儲。目前的需求很簡單:

  • 需要能持久化TodoList對象并對其進行操作;

  • 需要能持久化TodoItem對象并對其進行操作;

問題是,我們打算如何存儲數據?

存儲組件的選擇非常多:以MSSQL Server/Postgres/MySql/SQLite等為代表的關系型數據庫,以MongoDB/ElasticSearch等為代表的非關系型數據庫,除此之外,我們還可以在開發階段選擇內存數據庫,在云上部署的時候還可以選擇類似Azure Cosmos DB/AWS DynamoDB以及云上提供的多種關系型數據庫。

應用程序使用數據庫服務,一般都是借助成熟的第三方ORM框架,而在.NET后端服務開發的過程中,使用的最多的兩個ORM框架應該是:EntityFrameworkCore和Dapper,相比之下,EFCore的使用率更高一些。所以我們也選擇EFCore來進行演示。

目標

在這篇文章中,我們僅討論如何實現數據存儲基礎設施的引入,具體的實體定義和操作后面專門來說。

  • 使用MSSQL Server容器作為數據存儲組件(前提是電腦上需要安裝Docker環境,下載并安裝Docker Desktop即可);

這樣選擇的理由也很簡單,對于使用Mac的小伙伴來說,使用容器來啟動MSSQL Server可以避免因為非Windows平臺導致的示例無法運行的問題。

原理和思路

因為我們對開發環境和生產環境的配置有差異,那先來看看共性的部分:

  • 引入EFCore相關的nuget包并進行配置;

  • 添加DbContext對象并進行依賴注入;

  • 修改相關appsettings.{environment}.json文件;

  • 主程序配置。

  • 本地運行MSSQL Server容器并實現數據持久化;

同上一篇一樣,和具體的第三方對接的邏輯我們還是放到Infrastructure里面去,應用程序中只保留對外部服務的抽象操作。

實現

1. 引入Nuget包并進行配置

需要在Infrastructure項目中引入以下Nuget包:

Microsoft.EntityFrameworkCore.SqlServer

# 第二個包是用于使用PowerShell命令(Add-Migration/Update-Database/...)需要的,如果使用eftool,可以不安裝這個包。
Microsoft.EntityFrameworkCore.Tools

為了使用eftool,需要在Api項目中引入以下Nuget包:

Microsoft.EntityFrameworkCore.Design

2. 添加DBContext對象并進行配置

在這一步里,我們要添加的是一個具體的DBContext對象,這對于有經驗的開發者來說并不是很難的任務。但是在具體實現之前,我們可以花一點時間考慮一下現在的Clean Architecture結構:我們的目的是希望除了Infrastructure知道具體交互的第三方是什么,在Application以及Domain里都要屏蔽底層的具體實現。換言之就是需要在Infrastrcuture之外的項目中使用接口來做具體實現的抽象,那么我們在Application中新建一個Common/Interfaces文件夾用于存放應用程序定義的抽象接口IApplicationDbContext

namespace TodoList.Application.Common.Interfaces;

public interface IApplicationDbContext
{
    Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}

接下來在Infrastructure項目中新建Persistence文件夾用來存放和數據持久化相關的具體邏輯,我們在其中定義DbContext對象并實現剛才定義的接口。

using Microsoft.EntityFrameworkCore;
using TodoList.Application.Common.Interfaces;

namespace TodoList.Infrastructure.Persistence;

public class TodoListDbContext : DbContext, IApplicationDbContext
{
    public TodoListDbContext(DbContextOptions<TodoListDbContext> options) : base(options)
    {
    }
}

這里的處理方式可能會引起困惑,這個IApplicationDbContext存在的意義是什么。這里的疑問和關于要不要使用Repository模式有關,國外多位大佬討論過這個問題,即Repository是不是必須的。可以簡單理解大家達成的共識是:不是必須的,如果不是有某些特別的數據庫訪問邏輯,或者有足夠的理由需要使用Repository模式,那就保持架構上的簡潔,在Application層的多個CQRS Handlers中直接注入該IApplicationDbContext去訪問數據庫并進行操作。如果需要使用Repository模式,那在這里就沒有必要定義這個接口來使用了,Application中只需要定義IRepository<T>,在Infrastructure中實現的BaseRepository中訪問DbContext即可。

我們后面是需要使用Repository的,是因為希望演示最常用的開發模式,但是在這一篇中我保留IApplicationDbConetxt的原因是也希望展示一種不同的實現風格,后面我們還是會專注到Repository上的。

需要的對象添加好了,下一步是配置DbContext,我們還是遵循當前的架構風格,在Infrastructure項目中添加DependencyInjection.cs文件用于添加所有第三方的依賴:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using TodoList.Application.Common.Interfaces;
using TodoList.Infrastructure.Persistence;

namespace TodoList.Infrastructure;

public static class DependencyInjection
{
    public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddDbContext<TodoListDbContext>(options =>
            options.UseSqlServer(
                configuration.GetConnectionString("SqlServerConnection"),
                b => b.MigrationsAssembly(typeof(TodoListDbContext).Assembly.FullName)));

        services.AddScoped<IApplicationDbContext>(provider => provider.GetRequiredService<TodoListDbContext>());

        return services;
    }
}

3. 配置文件修改

我們對appsettings.Development.json文件進行配置:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "UseFileToLog": true,
  "ConnectionStrings": {
    "SqlServerConnection": "Server=localhost,1433;Database=TodoListDb;User Id=sa;Password=StrongPwd123;"
  }
}

這里需要說明的是如果是使用MSSQL Server默認端口1433的話,連接字符串里是可以不寫的,但是為了展示如果使用的不是默認端口應該如何配置,還是顯式寫在這里了供大家參考。

4. 主程序配置

Api項目中,我們只需要調用上面寫好的擴展方法,就可以完成配置。

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.ConfigureLog();

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// 添加基礎設施配置
builder.Services.AddInfrastructure(builder.Configuration);

// 省略以下...

5. 本地運行MSSQL Server容器及數據持久化

在保證本地Docker環境正常啟動之后,運行以下命令:

# 拉取mssql鏡像
$ docker pull mcr.microsoft.com/mssql/server:2019-latest
2019-latest: Pulling from mssql/server
7b1a6ab2e44d: Already exists 
4ffe416cf537: Pull complete 
fff1d174f64f: Pull complete 
3588fd79aff7: Pull complete 
c8203457909f: Pull complete 
Digest: sha256:a098c9ff6fbb8e1c9608ad7511fa42dba8d22e0d50b48302761717840ccc26af
Status: Downloaded newer image for mcr.microsoft.com/mssql/server:2019-latest
mcr.microsoft.com/mssql/server:2019-latest

# 創建持久化存儲
$ docker create -v /var/opt/mssql --name mssqldata  mcr.microsoft.com/mssql/server:2019-latest /bin/true
3c144419db7fba26398aa45f77891b00a3253c23e9a1d03e193a3cf523c66ce1

# 運行mssql容器,掛載持久化存儲卷
$ docker run -d --volumes-from mssqldata --name mssql -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=StrongPwd123' -p 1433:1433 mcr.microsoft.com/mssql/server:2019-latest
d99d774f70229f688d71fd13e90165f15abc492aacec48de287d348e047a055e

# 確認容器運行狀態
$ docker ps
CONTAINER ID   IMAGE                                        COMMAND                  CREATED          STATUS          PORTS                    NAMES
d99d774f7022   mcr.microsoft.com/mssql/server:2019-latest   "/opt/mssql/bin/perm…"   24 seconds ago   Up 22 seconds   0.0.0.0:1433->1433/tcp   mssql

驗證

為了驗證我們是否可以順利連接到數據庫,我們采用添加Migration并在程序啟動時自動進行數據庫的Migration方式進行:

首先安裝工具:

dotnet tool install --global dotnet-ef
# dotnet tool update --global dotnet-ef

# 生成Migration
$ dotnet ef migrations add SetupDb -p src/TodoList.Infrastructure/TodoList.Infrastructure.csproj -s src/TodoList.Api/TodoList.Api.csproj
Build started...
Build succeeded.
[17:29:15 INF] Entity Framework Core 6.0.1 initialized 'TodoListDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:6.0.1' with options: MigrationsAssembly=TodoList.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 
Done. To undo this action, use 'ef migrations remove'

為了在程序啟動時進行自動Migration,我們向Infrastructure項目中增加一個文件ApplicationStartupExtensions.cs并實現擴展方法:

using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using TodoList.Infrastructure.Persistence;

namespace TodoList.Infrastructure;

public static class ApplicationStartupExtensions
{
    public static void MigrateDatabase(this WebApplication app)
    {
        using var scope = app.Services.CreateScope();
        var services = scope.ServiceProvider;

        try
        {
            var context = services.GetRequiredService<TodoListDbContext>();
            context.Database.Migrate();
        }
        catch (Exception ex)
        {
            throw new Exception($"An error occurred migrating the DB: {ex.Message}");
        }
    }
}

并在Api項目的Program.cs中調用擴展方法:

// 省略以上...
app.MapControllers();

// 調用擴展方法
app.MigrateDatabase();

app.Run();

最后運行主程序:

$ dotnet run --project src/TodoList.Api
Building...
[17:32:32 INF] Entity Framework Core 6.0.1 initialized 'TodoListDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:6.0.1' with options: MigrationsAssembly=TodoList.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 
[17:32:32 INF] Executed DbCommand (22ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT 1
[17:32:32 INF] Executed DbCommand (19ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
[17:32:32 INF] Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT 1
[17:32:32 INF] Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
[17:32:33 INF] Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT [MigrationId], [ProductVersion]
FROM [__EFMigrationsHistory]
ORDER BY [MigrationId];
[17:32:33 INF] Applying migration '20211220092915_SetupDb'.
[17:32:33 INF] Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20211220092915_SetupDb', N'6.0.1');
[17:32:33 INF] Now listening on: https://localhost:7039
[17:32:33 INF] Now listening on: http://localhost:5050
[17:32:33 INF] Application started. Press Ctrl+C to shut down.
[17:32:33 INF] Hosting environment: Development
[17:32:33 INF] Content root path: /Users/yu.li1/Projects/asinta/blogs/cnblogs/TodoList/src/TodoList.Api/

使用數據庫工具連接容器數據庫,可以看到Migration已經成功地寫入數據庫表__EFMigrationsHistory了:

怎么使用.NET?6開發TodoList應用引入數據存儲

到此,相信大家對“怎么使用.NET 6開發TodoList應用引入數據存儲”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

平安县| 招远市| 正宁县| 民勤县| 延安市| 桂林市| 广丰县| 通渭县| 绥宁县| 贵德县| 扬州市| 贞丰县| 塘沽区| 无棣县| 炎陵县| 五指山市| 新郑市| 广平县| 竹溪县| 嘉禾县| 岫岩| 察哈| 石柱| 普洱| 桃园县| 福海县| 轮台县| 元谋县| 华坪县| 长汀县| 武清区| 巴南区| 乌海市| 铜川市| 望江县| 江城| 武冈市| 东乡| 龙泉市| 信宜市| 托里县|