Asp.net core Webapi 如何執行定時任務?

来源:https://www.cnblogs.com/JackyGz/archive/2023/12/26/17928776.html
-Advertisement-
Play Games

什麼是Json Schema ? Json schema是一種聲明式語言,它可以用來標識Json的結構,數據類型和數據的具體限制,它提供了描述期望Json結構的標準化方法。 利用Json Schema, 你可以定義Json結構的各種規則,以便確定Json數據在各個子系統中交互傳輸時保持相容和一致的格 ...


image

前言

在電腦系統中,定時執行一些後臺任務是很常見的場景,比如定時發送郵件、備份數據等等。

那麼,.NET 技術如何通過編程靈活地實現項目里複雜的自定義任務呢?

如果是 Windows 生態,通常來說,可以有這些方式:

  1. 編寫一個程式,通過 Windows 內置的任務計劃來定時執行。
  2. 編寫一個程式,通過 Windows 內置的 Services 來定時執行。
  3. 編寫一個定時迴圈執行任務的程式,在 Windows 系統啟動時配置為自動執行。
    ……

但是,如果是一個中小型的 Web 應用系統,這些方法方式就顯得不太合適。Asp.net core Webapi 有沒有辦法執行定時任務呢?答案是有的,Asp.net core Webapi 可以通過常駐後臺的托管服務來執行定時任務。

本文是 Asp.net core Webapi 運行一個常駐後臺並從資料庫中導出數據的托管服務的例子,寫出來供大家指點,在討論過程中共同提高水平。

Step By Step 實現步驟

  1. 創建一個 asp.net core webapi 項目
  2. 從 Nuget 安裝以下包

    Microsoft.AspNetCore.Identity.EntityFrameworkCore
    Microsoft.EntityFrameworkCore.Relational
    Microsoft.EntityFrameworkCore.SqlServer
    Microsoft.EntityFrameworkCore.Tools

  3. 打開 appsettings.json 並添加資料庫連接字元串,如:
    {
      "Logging": {
    	"LogLevel": {
    	  "Default": "Information",
    	  "Microsoft.AspNetCore": "Warning"
    	}
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
    	"Default": "Server=(localdb)\\mssqllocaldb;Database=IdentityTestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
      }
    }
    
  4. 添加一個繼承於 IdentityUser 的 User 類
    using Microsoft.AspNetCore.Identity;
    
    public class User: IdentityUser<long>
    {
    	public DateTime CreationTime { get; set; }
    	public string? NickName { get; set; }
    }	
    
  5. 添加一個繼承於 IdentityRole 的 Role 類
    using Microsoft.AspNetCore.Identity;
    
    public class Role: IdentityRole<long>
    {
    
    }
    
  6. 創建資料庫上下文
    using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore;
    
    public class TestDbContext: IdentityDbContext<User, Role, long>
    {
    	public TestDbContext(DbContextOptions<TestDbContext> options):base(options)
    	{
    
    	}
    
    	protected override void OnModelCreating(ModelBuilder builder)
    	{
    		base.OnModelCreating(builder);
    		builder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    	}
    }	
    
  7. 創建一個 ExplortStatisticBgService 類並繼承 BackgroundService,這是托管服務類
    using Microsoft.EntityFrameworkCore;
    using System.Text;
    
    public class ExplortStatisticBgService : BackgroundService
    {
    	private readonly TestDbContext ctx;
    	private readonly ILogger<ExplortStatisticBgService> logger;
    	private readonly IServiceScope serviceScope;
    
    	/// <summary>
    	/// 在構造方法註入IServiceScopeFactory服務,
    	/// 用來創建IServiceScope對象,
    	/// 這樣就可以通過IServiceScope來創建短生命周期的服務了
    	/// </summary>
    	/// <param name="scopeFactory"></param>
    	public ExplortStatisticBgService(IServiceScopeFactory scopeFactory)
    	{
    		this.serviceScope = scopeFactory.CreateScope();
    		var sp = serviceScope.ServiceProvider;
    		this.ctx = sp.GetRequiredService<TestDbContext>();
    		this.logger = sp.GetRequiredService<ILogger<ExplortStatisticBgService>>();  
    	}
    
    	protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    	{
    		// 用 while 迴圈實現服務常駐
    		while (!stoppingToken.IsCancellationRequested)
    		{
    			// 用 try...catch 捕捉異常記錄錯誤信息並避免方法退出
    			try
    			{
    				// 這裡實現每隔5秒從資料庫中導出數據
    				// 更複雜的配置可以用第三方開源的框架
    				await DoExecuteAsync();
    				await Task.Delay(5000);
    			}
    			catch (Exception ex)
    			{
    				logger.LogError(ex, "獲取用戶統計數據失敗");
    				await Task.Delay(1000);
    			}
    		}
    	}
    
    	private async Task DoExecuteAsync()
    	{
    		var items = ctx.Users.AsNoTracking().GroupBy(u => u.CreationTime.Date)
    			.Select(e => new 
    			{ 
    				Date = e.Key,
    				Count = e.Count()
    			});
    		StringBuilder sb = new StringBuilder(1024);
    		sb.AppendLine($"Date: {DateTime.Now}");
    		foreach (var item in items)
    		{
    			sb.Append(item.Date).AppendLine($": {item.Count}");
    		}
    		await File.WriteAllTextAsync("d:/1.txt", sb.ToString());
    		logger.LogInformation($"導出完成");
    	}
    
    	/// <summary>
    	/// IServiceScope 需要釋放
    	/// 所以重寫 Dispose 方法
    	/// </summary>
    	public override void Dispose()
    	{
    		base.Dispose();
    		serviceScope.Dispose();
    	}
    }	
    
  8. 打開 Program.cs,註入托管服務等,看代碼的註釋
    using Microsoft.AspNetCore.Identity;
    using Microsoft.EntityFrameworkCore;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    
    builder.Services.AddControllers();
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
    
    IServiceCollection services = builder.Services;
    
    // 註冊托管服務
    services.AddHostedService<ExplortStatisticBgService>();
    
    // 註入資料庫上下文
    services.AddDbContext<TestDbContext>(options => {
    	string connStr = builder.Configuration.GetConnectionString("Default")!;
    	options.UseSqlServer(connStr);
    });
    
    // 數據保護服務註入
    // ----數據保護提供了一個簡單、基於非對稱加密改進的加密API用於確保Web應用敏感數據的安全存儲
    // ----不需要開發人員自行生成密鑰,它會根據當前應用的運行環境,生成該應用獨有的一個私鑰
    services.AddDataProtection();
    
    // 註入 Identity 框架的一些重要的基礎配置
    // 如果沒有這個,下麵的註入 UserManager 等服務會有問題,程式無法編譯
    services.AddIdentityCore<User>(options =>
    {
    	options.Password.RequireDigit = false;
    	options.Password.RequireLowercase = false;
    	options.Password.RequireNonAlphanumeric = false;
    	options.Password.RequireUppercase = false;
    	options.Password.RequiredLength = 6;
    	options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
    	options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
    });
    
    // 註入 UserManager、RoleManager 等Identity 框架服務
    var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), services);
    idBuilder.AddEntityFrameworkStores<TestDbContext>()
    	.AddDefaultTokenProviders()
    	.AddRoleManager<RoleManager<Role>>()
    	.AddUserManager<UserManager<User>>();
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
    	app.UseSwagger();
    	app.UseSwaggerUI();
    }
    
    app.UseHttpsRedirection();
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();
    ``
    
  9. Ctrl+F5 運行項目,不做任何操作,托管程式會自動導出數據

擴展

托管服務在後臺運行,通過它可以實現在很多事情,比如:

  1. 監控消息隊列,當有數據進入消息隊列就處理。
  2. 再如每隔10s把A資料庫中的數據同步到B資料庫中
  3. ...... 等等

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1 public class code1 { 2 public static void main(String[]args) { 3 int[][] x = new int[6][6]; 4 for (int i = 0; i < x.length; i++) { 5 x[i][0] = 1; 6 ...
  • 這一章講述了RESTful API的基本概念和設計原則。通過比較傳統方式和RESTful方式操作資源的URL定義,能明顯看出RESTful的簡潔和意圖明確。RESTful的API設計使用不同的HTTP方法來操作資源,比如GET用於查詢、POST用於新增、PUT用於更新全部欄位、PATCH用於更新部分... ...
  • 隨著科技的快速發展和人們對個人命運的關註,越來越多的人開始尋找各類方法來預測自己的未來走向。而其中,八字預測是一種古老而又傳統的方法,通過計算生辰八字,從五行八字中揭示出個人的命運走勢。在這個過程中,挖數據平臺提供了一款免費算命的API介面,為用戶提供了便捷的命運預測服務。 首先,我們來瞭解一下什麼 ...
  • Qt 是一個跨平臺C++圖形界面開發庫,利用Qt可以快速開發跨平臺窗體應用程式,在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實現圖形化開發極大的方便了開發效率,本章將重點介紹`QSqlDatabase`資料庫模塊的常用方法及靈活運用。Qt SQL模塊是Qt框架的一部分,它提供了一組類和函... ...
  • 目錄修整 目前的系列目錄(後面會根據實際情況變動): 在windows11上編譯python 將python註入到其他進程並運行 註入Python並使用ctypes主動調用進程內的函數和讀取記憶體結構體 調用彙編引擎實戰發送文本和圖片消息(支持32位和64位微信) 允許Python載入運行py腳本且支 ...
  • 嶺回歸(Ridge Regression)是一種用於處理共線性數據的線性回歸改進方法。和上一篇用基於最小二乘法的線性回歸相比,它通過放棄最小二乘的無偏性,以損失部分信息、降低精度為代價來獲得更實際和可靠性更強的回歸繫數。 1. 概述 嶺回歸的模型對於存在大量相關特征(這些特征之間存在很高的相關性)的 ...
  • 之前有和大家分享過 支付寶非同步通知如何使用的相關內容,但是有些時候吧,就是收不到非同步通知,也不知道是什麼原因導致的。 今天來幫大家彙總下在「收不到非同步通知」的情況下,如何排查問題出現在哪裡。 ...
  • 在C/C++中使用WMI(Windows Management Instrumentation)介面查詢系統信息是一種強大的方法。下麵是一個簡單的例子,演示如何使用WMI查詢系統信息,包括安裝的軟體信息、磁碟信息、網路適配器信息、操作系統信息等。請註意,這裡使用的是COM介面,因此需要在代碼中進行C ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...