ASP.NET Core SignalR 系列(二)- 中心(服務端)

来源:https://www.cnblogs.com/xyh9039/archive/2023/07/08/17536693.html
-Advertisement-
Play Games

本章將和大家分享 ASP.NET Core SignalR 中的中心(服務端)。 本文大部分內容摘自微軟官網:https://learn.microsoft.com/zh-cn/aspnet/core/signalr/hubs?view=aspnetcore-7.0 廢話不多說,我們直接來看一個De ...


本章將和大家分享 ASP.NET Core SignalR 中的中心(服務端)。

本文大部分內容摘自微軟官網:https://learn.microsoft.com/zh-cn/aspnet/core/signalr/hubs?view=aspnetcore-7.0

廢話不多說,我們直接來看一個Demo,Demo的目錄結構如下所示:

本Demo的Web項目為ASP.NET Core Web 應用程式(目標框架為.NET 7.0) MVC項目。

1、創建和使用中心

通過聲明繼承自 Hub 的類來創建中心。將方法添加到 public 類,使其可從客戶端調用:

using Microsoft.AspNetCore.SignalR;

namespace SignalRChat.Hubs
{
    /// <summary>
    /// Hub 類管理連接、組和消息
    /// </summary>
    public class ChatHub : Hub
    {
        /// <summary>
        /// 可通過已連接客戶端調用 SendMessage,以向所有客戶端發送消息
        /// </summary>
        public async Task SendMessage(string user, string message)
        {
            //Clients.All 向所有的客戶端發送消息(服務端調用客戶端)
            //ReceiveMessage 是客戶端監聽的方法
            await Clients.All.SendAsync("ReceiveMessage", user, message);

            /*
                // 常用方法
                // 給所有人發送消息
                await Clients.All.SendAsync("ReceiveMessage", data);

                // 給組裡所有人發消息
                await Clients.Group("Users").SendAsync("ReceiveMessage", data);

                // 給調用方法的那個人發消息
                await Clients.Caller.SendAsync("ReceiveMessage", data);

                // 給除了調用方法的以外所有人發消息
                await Clients.Others.SendAsync("ReceiveMessage", data);

                // 給指定connectionId的人發消息
                await Clients.User(connectionId).SendAsync("ReceiveMessage", data);

                // 給指定connectionId的人發消息
                await Clients.Client(connectionId).SendAsync("ReceiveMessage", data);

                // 給指定connectionId的人發消息,同時指定多個connectionId
                await Clients.Clients(IReadOnlyList<> connectionIds).SendAsync("ReceiveMessage", data);
            */
        }
    }
}

中心是暫時性的:

不要將狀態存儲在中心類的屬性中。每個中心方法調用都在新的中心實例上執行。

請勿通過依賴項註入直接實例化中心。若要從應用程式中的其他位置向客戶端發送消息,請使用 IHubContext 。

調用依賴於保持活動狀態的中心的非同步方法時請使用 await。例如,如果在沒有 await 的情況下進行調用,則 Clients.All.SendAsync(...) 這類方法會失敗,並且中心方法會在 SendAsync 完成之前完成。

2、配置 SignalR 中心 

註冊中心所需的 SignalR 服務 以及 配置SignalR終結點,修改 Program.cs 文件的代碼,如下所示:

using SignalRChat.Hubs;

namespace SignalRChat
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            //服務註冊(往容器中添加服務)
            // Add services to the container.
            builder.Services.AddControllersWithViews();
            builder.Services.AddSignalR(); //註冊中心所需的 SignalR 服務

            var app = builder.Build();

            //配置Http請求處理管道
            // Configure the HTTP request pipeline.
            if (!app.Environment.IsDevelopment())
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            //配置MVC路由
            app.MapControllerRoute(
                name: "areas",
                pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
            app.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");

            //配置SignalR終結點
            app.MapHub<ChatHub>("/chatHub"); //中心
            app.MapHub<StronglyTypedChatHub>("/stronglyTypedChatHub"); //強類型中心

            app.Run();
        }
    }
}

3、上下文對象

類 Hub 包含一個 Context 屬性,該屬性包含以下屬性以及有關連接的信息:

屬性 說明
ConnectionId 獲取連接的唯一 ID(由 SignalR 分配)。每個連接都有一個連接 ID。
UserIdentifier 獲取用戶標識符。 預設情況下,SignalR 使用與連接關聯的 ClaimsPrincipal 中的 ClaimTypes.NameIdentifier 作為用戶標識符。
User 獲取與當前用戶關聯的 ClaimsPrincipal。
Items 獲取可用於在此連接範圍內共用數據的鍵/值集合。數據可以存儲在此集合中,會在不同的中心方法調用間為連接持久保存。
Features 獲取連接上可用的功能的集合。目前,在大多數情況下不需要此集合,因此未對其進行詳細記錄。
ConnectionAborted 獲取一個 CancellationToken,它會在連接中止時發出通知。

Hub.Context 還包含以下方法:

方法 說明
GetHttpContext 獲取 Http 請求的上下文對象,如果不是 Http 請求,則返回 null 。
Abort 中止連接。

4、客戶端對象

類 Hub 包含一個 Clients 屬性,該屬性包含以下屬性,用於伺服器和客戶端之間的通信:

屬性 說明
 All  對所有連接的客戶端調用方法
 Caller  對調用了中心方法的客戶端調用方法
 Others  對所有連接的客戶端調用方法(調用了方法的客戶端除外)

Hub.Clients 還包含以下方法:

方法 說明
AllExcept 對所有連接的客戶端調用方法(指定連接除外)
Client 對連接的一個特定客戶端調用方法
Clients 對連接的多個特定客戶端調用方法
Group 對指定組中的所有連接調用方法
GroupExcept 對指定組中的所有連接調用方法(指定連接除外)
Groups 對多個連接組調用方法
OthersInGroup 對一個連接組調用方法(不包括調用了中心方法的客戶端)
User 對與一個特定用戶關聯的所有連接調用方法
Users 對與多個指定用戶關聯的所有連接調用方法

以上表中的每個屬性或方法都返回具有 SendAsync 方法的對象。 方法 SendAsync 接收要調用的客戶端方法的名稱和任何參數。

5、向客戶端發送消息

若要對特定客戶端發出調用,請使用 Clients 對象的屬性。 在以下示例中,有三種中心方法:

using Microsoft.AspNetCore.SignalR;

namespace SignalRChat.Hubs
{
    /// <summary>
    /// Hub 類管理連接、組和消息
    /// </summary>
    public class ChatHub : Hub
    {
        /// <summary>
        /// 可通過已連接客戶端調用 SendMessage,以向所有客戶端發送消息
        /// </summary>
        public async Task SendMessage(string user, string message)
        {
            //Clients.All 向所有的客戶端發送消息(服務端調用客戶端)
            //ReceiveMessage 是客戶端監聽的方法
            await Clients.All.SendAsync("ReceiveMessage", user, message); //將消息發送到所有連接的客戶端

            /*
                // 常用方法
                // 給所有人發送消息
                await Clients.All.SendAsync("ReceiveMessage", data);

                // 給組裡所有人發消息
                await Clients.Group("Users").SendAsync("ReceiveMessage", data);

                // 給調用方法的那個人發消息
                await Clients.Caller.SendAsync("ReceiveMessage", data);

                // 給除了調用方法的以外所有人發消息
                await Clients.Others.SendAsync("ReceiveMessage", data);

                // 給指定connectionId的人發消息
                await Clients.User(connectionId).SendAsync("ReceiveMessage", data);

                // 給指定connectionId的人發消息
                await Clients.Client(connectionId).SendAsync("ReceiveMessage", data);

                // 給指定connectionId的人發消息,同時指定多個connectionId
                await Clients.Clients(IReadOnlyList<> connectionIds).SendAsync("ReceiveMessage", data);
            */
        }

        public async Task SendMessageToCaller(string user, string message)
            => await Clients.Caller.SendAsync("ReceiveMessage", user, message); //將消息發送回調用方

        public async Task SendMessageToGroup(string user, string message)
            => await Clients.Group("SignalR Users").SendAsync("ReceiveMessage", user, message); //將消息發送給 SignalR Users 組中的所有客戶端
    }
}

6、強類型中心

使用 SendAsync 的缺點是它依賴於字元串來指定要調用的客戶端方法。 如果客戶端中的方法名稱拼寫錯誤或缺失,則這會使代碼可能出現運行時錯誤。

使用 SendAsync 的另一種方法是使用 Hub<T>強類型Hub類。 在以下示例中 ChatHub ,客戶端方法已提取到名為 的 IChatClient介面中:

namespace SignalRChat.Hubs
{
    public interface IChatClient
    {
        /// <summary>
        /// 客戶端方法
        /// </summary>
        Task ReceiveMessage(string user, string message);
    }
}

此介面可用於將前面的 ChatHub 示例重構為強類型:

using Microsoft.AspNetCore.SignalR;

namespace SignalRChat.Hubs
{
    /// <summary>
    /// 強類型中心
    /// 中心是暫時性的:不要將狀態存儲在中心類的屬性中。每個中心方法調用都在新的中心實例上執行。
    /// </summary>
    public class StronglyTypedChatHub : Hub<IChatClient>
    {
        [HubMethodName("SendMessage")] //更改中心方法的名稱
        public async Task SendMessage(string user, string message)
            => await Clients.All.ReceiveMessage(user, message); //將消息發送到所有連接的客戶端

        public async Task SendMessageToCaller(string user, string message)
            => await Clients.Caller.ReceiveMessage(user, message); //將消息發送回調用方

        public async Task SendMessageToGroup(string user, string message)
            => await Clients.Group("SignalR Users").ReceiveMessage(user, message); //將消息發送給 SignalR Users 組中的所有客戶端
    }
}

使用 Hub<IChatClient> 可以對客戶端方法進行編譯時檢查。 這可以防止使用字元串導致的問題,因為 Hub<T> 只能提供對 介面中定義的方法的訪問。 使用強類型 Hub<T> 會禁止使用 SendAsync。

備註:Async尾碼不會從方法名稱中去除。 除非使用 .on('MyMethodAsync')定義客戶端方法,否則不要使用 MyMethodAsync 作為名稱。

7、更改中心方法的名稱

預設情況下,伺服器中心方法名稱是 .NET 方法的名稱。若要更改特定方法的此預設行為,請使用 HubMethodName 特性。調用方法時,客戶端應使用此名稱而不是 .NET 方法名稱:

[HubMethodName("SendMessageToUser")]
public async Task DirectMessage(string user, string message)
    => await Clients.User(user).SendAsync("ReceiveMessage", user, message);

8、將服務註入中心

中心構造函數可以接受 DI 中的服務作為參數,這些參數可以存儲在類的屬性中,以便在中心方法中使用。

為不同的中心方法註入多個服務或作為編寫代碼的替代方法時,中心方法也可以接受 DI 中的服務。 預設情況下,如果可能,將從 DI 檢查和解析中心方法參數。

services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();

// ...

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message, IDatabaseService dbService)
    {
        var userName = dbService.GetUserName(user);
        return Clients.All.SendAsync("ReceiveMessage", userName, message);
    }
}

如果不需要從服務隱式解析參數,請使用 DisableImplicitFromServicesParameters 禁用它。 若要在中心方法中顯式指定從 DI 解析的參數,請使用 DisableImplicitFromServicesParameters 選項,並使用 [FromServices] 屬性或自定義屬性,該屬性在應從 DI 解析的中心方法參數上實現 IFromServiceMetadata 。

services.AddSingleton<IDatabaseService, DatabaseServiceImpl>();
services.AddSignalR(options =>
{
    options.DisableImplicitFromServicesParameters = true;
});

// ...

public class ChatHub : Hub
{
    public Task SendMessage(string user, string message,
        [FromServices] IDatabaseService dbService)
    {
        var userName = dbService.GetUserName(user);
        return Clients.All.SendAsync("ReceiveMessage", userName, message);
    }
}

9、為連接處理事件

SignalR 中心 API 提供 OnConnectedAsync 和 OnDisconnectedAsync 虛方法來管理和跟蹤連接。

/// <summary>
/// 在客戶端連接到中心時執行操作
/// </summary>
/// <returns></returns>
public override async Task OnConnectedAsync()
{
    await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
    await base.OnConnectedAsync();
}

/// <summary>
/// 在客戶端斷開連接時執行操作
/// </summary>
/// <param name="exception"></param>
/// <returns></returns>
public override async Task OnDisconnectedAsync(Exception? exception)
{
    await base.OnDisconnectedAsync(exception);
}

其中如果客戶端有意斷開連接(例如通過調用 connection.stop()),則 exception 參數為 null。但是,如果客戶端由於錯誤(例如網路故障)而斷開連接,則 exception 參數包含描述故障的異常。

RemoveFromGroupAsync 無需在 OnDisconnectedAsync 中調用,系統會自動處理它。

10、從中心外部發送消息

SignalR 中心是用於向連接到 SignalR 伺服器的客戶端發送消息的核心抽象。 你也可以使用 IHubContext 服務從應用中的其他位置發送消息。

備註:IHubContext 用於將通知發送到客戶端,而非用於調用 Hub 上的方法。

1)獲取 IHubContext 實例

在 ASP.NET Core SignalR 中,你可以通過依賴項註入來訪問 IHubContext 實例。 你可以將 IHubContext 實例註入控制器、中間件或其他 DI 服務。 使用該實例向客戶端發送消息。

2)在控制器中註入 IHubContext 實例

通過將 IHubContext 實例添加到構造函數,可以將其註入控制器:

public class HomeController : Controller
{
    private readonly IHubContext<NotificationHub> _hubContext;

    public HomeController(IHubContext<NotificationHub> hubContext)
    {
        _hubContext = hubContext;
    }
}

獲權訪問 IHubContext 實例後,就像在中心本身一樣調用客戶端方法:

public async Task<IActionResult> Index()
{
    await _hubContext.Clients.All.SendAsync("Notify", $"Home page loaded at: {DateTime.Now}");
    return View();
}

3)在中間件中獲取 IHubContext 實例

訪問中間件管道中的 IHubContext,如下所示:

app.Use(async (context, next) =>
{
    var hubContext = context.RequestServices
                            .GetRequiredService<IHubContext<ChatHub>>();
    //...
    
    if (next != null)
    {
        await next.Invoke();
    }
});

備註:當從 Hub 類外部調用客戶端方法時,沒有與該調用關聯的調用方。 因此,無法訪問 ConnectionId、Caller 和 Others 屬性。

4)從 IHost 獲取 IHubContext 實例

從 Web 主機訪問 IHubContext 對於與 ASP.NET Core 之外的區域集成很有用,例如,使用第三方依賴項註入框架:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();
        var hubContext = host.Services.GetService(typeof(IHubContext<ChatHub>));
        host.Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder => {
                webBuilder.UseStartup<Startup>();
            });
}

5)註入強類型 HubContext

若要註入強類型 HubContext,請確保中心繼承自 Hub<T>。 使用 IHubContext<THub, T> 介面而不是 IHubContext<THub> 進行註入。

public class ChatController : Controller
{
    public IHubContext<ChatHub, IChatClient> _strongChatHubContext { get; }

    public ChatController(IHubContext<ChatHub, IChatClient> chatHubContext)
    {
        _strongChatHubContext = chatHubContext;
    }

    public async Task SendMessage(string user, string message)
    {
        await _strongChatHubContext.Clients.All.ReceiveMessage(user, message);
    }
}

6)在泛型代碼中使用 IHubContext

註入的 IHubContext<THub> 實例可以強制轉換為 IHubContext,而無需指定泛型 Hub 類型。

class MyHub : Hub
{ }

class MyOtherHub : Hub
{ }

app.Use(async (context, next) =>
{
    var myHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyHub>>();
    var myOtherHubContext = context.RequestServices
                            .GetRequiredService<IHubContext<MyOtherHub>>();
    await CommonHubContextMethod((IHubContext)myHubContext);
    await CommonHubContextMethod((IHubContext)myOtherHubContext);

    await next.Invoke();
}

async Task CommonHubContextMethod(IHubContext context)
{
    await context.Clients.All.SendAsync("clientMethod", new Args());
}

此操作在以下情況下十分有用:

  • 編寫不引用應用正在使用的特定 Hub 類型的庫。
  • 編寫可應用於多個不同 Hub 實現的泛型代碼。

11、管理 SignalR 中的用戶和組

SignalR 允許將消息發送到與特定用戶關聯的所有連接,以及指定的連接組。

1)SignalR 中的用戶

SignalR 中的單個用戶可以與一個應用建立多個連接。 例如,用戶可以在桌面和手機上進行連接。 每台設備都有一個單獨的 SignalR 連接,但它們都與同一個用戶關聯。 如果向用戶發送消息,則與該用戶關聯的所有連接都會收到消息。 可以通過中心內的 Context.UserIdentifier 屬性訪問連接的用戶標識符。

預設情況下,SignalR 使用與連接關聯的 ClaimsPrincipal 中的 ClaimTypes.NameIdentifier 作為用戶標識符。 若要自定義此行為,請參閱使用聲明自定義標識處理。

通過將用戶標識符傳遞給中心方法中的 User 函數,向特定用戶發送消息,如以下示例所示:

public Task SendPrivateMessage(string user, string message)
{
    return Clients.User(user).SendAsync("ReceiveMessage", message);
}

備註:用戶標識符區分大小寫。

2)SignalR 中的組

組是與名稱關聯的連接集合。你可以將消息發送到組中的所有連接。建議通過組發送到一個或多個連接,因為組由應用程式管理。一個連接可以是多個組的成員。組非常適合聊天應用程式之類的應用,其中每個聊天室都可以表示為一個組。可通過 AddToGroupAsync 和 RemoveFromGroupAsync 方法在組中添加或刪除連接。

public async Task AddToGroup(string groupName)
{
    await Groups.AddToGroupAsync(Context.ConnectionId, groupName);

    await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has joined the group {groupName}.");
}

public async Task RemoveFromGroup(string groupName)
{
    await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);

    await Clients.Group(groupName).SendAsync("Send", $"{Context.ConnectionId} has left the group {groupName}.");
}

重新連接時不會保留組成員身份。重新建立連接後,需要重新加入組。無法計算組的成員數,因為如果將應用程式擴展到多台伺服器,則無法獲取此信息。

若要在使用組時保護對資源的訪問,請使用 ASP.NET Core 中的身份驗證和授權功能。如果僅當憑據對組有效時才將用戶添加到該組,則發送到該組的消息將僅發送給授權用戶。但是,組不是一項安全功能。身份驗證聲明具有組不具備的功能,例如到期和撤銷。如果撤銷用戶對組的訪問許可權,應用必須從組中顯式刪除該用戶。

備註:組名稱區分大小寫。

12、SignalR API 設計註意事項

使用自定義對象參數確保向後相容性

將新的參數添加到 SignalR 客戶端或伺服器上的中心方法是一項重大更改。這意味著,較舊的客戶端/伺服器在嘗試調用沒有適當數量參數的方法時會出錯。但是,向自定義對象參數添加屬性不是一項中斷性變更。這可用於設計相容的 API,以適應客戶端或伺服器上的更改。

使用自定義對象作為參數可提供更大的靈活性,如下所示:

public class TotalLengthRequest
{
    public string Param1 { get; set; }
    public string Param2 { get; set; }
}

public async Task GetTotalLength(TotalLengthRequest req)
{
    var length = req.Param1.Length;
    if (req.Param2 != null)
    {
        length += req.Param2.Length;
    }
    return length;
}

當舊客戶端發送單個參數時,額外的 Param2 屬性將保留為 null。 你可以通過檢查 Param2 是否為 null 來檢測舊客戶端發送的消息並應用預設值。 新客戶端可以發送這兩個參數。

connection.invoke("GetTotalLength", { param1: "value1", param2: "value2" });

此技術同樣適用於客戶端上定義的方法。 你可以從伺服器端發送自定義對象:

public async Task Broadcast(string message)
{
    await Clients.All.SendAsync("ReceiveMessage", new
    {
        Sender = Context.User.Identity.Name,
        Message = message
    });
}

舊客戶端不需要 Sender 值,因此會忽略它。 新客戶端可以通過更新為讀取新屬性來接受它:

connection.on("ReceiveMessage", (req) => {
    let message = req.message;
    if (req.sender) {
        message = req.sender + ": " + message;
    }
    appendMessageToChatWindow(message);
});

在這種情況下,新客戶端也可以容忍不提供 Sender 值的舊伺服器。由於舊伺服器不提供 Sender 值,因此客戶端在訪問它之前會檢查它是否存在。

 

Demo源碼:

鏈接:https://pan.baidu.com/s/1AbGaPRfv2vAskHRAnOlvYA 
提取碼:456q

此文由博主精心撰寫轉載請保留此原文鏈接:https://www.cnblogs.com/xyh9039/p/17536693.html

版權聲明:如有雷同純屬巧合,如有侵權請及時聯繫本人修改,謝謝!!!


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

-Advertisement-
Play Games
更多相關文章
  • 上一篇隨筆談了談單鏈表是什麼東西,然後進行了初始化,這篇隨筆就開始對其進行操作了,首先是增,刪,改,查的增。 增,顧名思義就是要增加新的元素,單鏈表是鏈式的,那就要考慮怎麼去加新元素,有三種,從頭部添加,從尾部添加,從中間添加。先說說從尾部添加,這個比較好理解,直接在尾部放一個結點然後連起來就好了。 ...
  • [toc] # 一、停用詞介紹 您好,我是[@馬哥python說](https://www.zhihu.com/people/13273183132) ,一名10年程式猿。 在自然語言處理(NLP)研究中,停用詞stopwords是指在文本中頻繁出現但通常沒有太多有意義的詞語。這些詞語往往是一些常見 ...
  • [toc] # 作用 - 在請求Authorize Filter後執行, 可以做緩存處理 - ResourceFilter 在控制器實例化之前執行 - ResourceFilter 可以在全局, Controller, Action 都可以設置, 並且都會執行(一個ResourceFilter可以重 ...
  • # 個人博客-發送郵件優化🧐 # 前言 之前的發送郵件就弄了個方法,比如回覆評論會給評論的人發送郵件,留言回覆也是,而且2者的代碼有很多一樣的地方,比較冗餘。然後也是抽空優化一下,思路也是比較常用的工廠+策略模式,然後評論回覆和留言回覆的模板是不一樣的,所以需要創建模板類和方法。。。 內容比較多, ...
  • [TOC] ___ #作用 - 在請求AuthorizeFilter -> ResourceFilter -> ActionFilter, 可以記錄Action的日誌 - ActionFilter 在控制器實例化之後執行 - ResourceFilter 可以在全局, Controller, Act ...
  • # 引言 上一篇中[.Net 編譯器平臺 Roslyn](https://niuery.com/post/67),介紹了Roslyn的各項功能,包括公開API,使用語法,使用語義,使用工作區等功能。 那麼回到上一篇中提到的問題,實現類似這樣的功能(以下代碼為偽代碼): ```csharp strin ...
  • ## - 結論 先上結論,答案是yes,C#中數組確實具有out參數的特性。 ## - 疑問 最近開發一個上位機的功能,有段代碼看得我一直很迷糊,我的認識,函數的執行結果,要麼在函數中通過return返回,要麼通過out或ref參數返回。這段代碼中明顯沒有通過return獲取返回值,輸入參數倒是看起 ...
  • # Unity中的RegisterPlugins:深入解析與實用案例 在Unity游戲開發中,我們經常需要使用第三方插件來實現一些特定的功能。為了讓這些插件能夠在Unity中正常工作,我們需要對它們進行註冊。本文將詳細介紹Unity中的`RegisterPlugins`方法,並通過三個實用案例來展示 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...