2026-01-07

[C#] Server 與 Client 全程走 MessagePack:一個 .NET 10 Web API 的實作紀錄

很多人聽過 MessagePack,但真正用在 Web API 上的機會其實不多,尤其是完整從 Client 到 Server 都走 binary 傳輸的情境

這篇文章用 .NET 10 示範一個最小可行的案例,實作一個只接受 MessagePack 的 Web API,並搭配一個 Client 呼叫範例

讓整個傳輸流程從頭到尾都清楚可以快速複製貼上了解 


1. 我測試環境是 .NET 10 ,一樣沒有內建,請先到 nuget 下面去下載 https://www.nuget.org/packages/messagepack

2. 建立模型,記得 Server and Client 的模型要一模一樣,包括 Key(index) 不然會出錯,這點要特別注意

在設計實務上,建議使用另一個專統一描述模型不要用兩邊各自為政的資料模型,這樣比較安全,也不用重複撰寫

[MessagePackObject] public sealed class User { [Key(0)] public int Id { get; set; } [Key(1)] public string Name { get; set; } = ""; [Key(2)] public List<User> Friends { get; set; } = new(); [Key(3)] public int Age { get; set; } [Key(4)] public string Alias { get; set; } = ""; [Key(5)] public decimal Salary { get; set; } [Key(6)] public DateTime Birth { get; set; } }

3. Server side 的程式碼,這邊我直接開一個 Web API 專案然後直接加上一個 Controller ,這樣你也不用去調整其他設定

如果你是自己開一個空白的專案,記得在 Program.cs 要加入    app.MapControllers(); 

這邊我很常忘記,我提醒自己一下,這邊我就修改進來的MessagePack 還原成物件,並且修改一些資料

C# Code 

[ApiController] [Route("api/user")] public class UserController : ControllerBase { [HttpPost("edit")] public async Task<IActionResult> EditUser() { // 1. 讀取 request body binary data using var ms = new MemoryStream(); await Request.Body.CopyToAsync(ms); var requestBytes = ms.ToArray(); // 2. MessagePack 反序列化 var user = MessagePackSerializer.Deserialize<User>( requestBytes, MessagePackSerializerOptions.Standard ); // 3. 模擬處理 user.Name = user.Name + " --Server 改過了"; user.Age += 1; // 4. 序列化回傳 var responseBytes = MessagePackSerializer.Serialize( user, MessagePackSerializerOptions.Standard ); return File( responseBytes, "application/x-msgpack" ); } }


4. 接下來是 Client 呼叫的部分,這邊的部分我就製作一個 User 資料序列化成 MessagePack 後就傳給 Server 

並且拿到回應後用 JSON  印出看看是不是得到預期答案

var handler = new HttpClientHandler { ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }; var client = new HttpClient(handler); var user = new User { Id = 1, Name = "許當麻測試", Age = 42, Birth=new DateTime(1981,1,1), Alias="測試" }; // 1. Serialize to MessagePack byte[] requestBytes = MessagePackSerializer.Serialize( user, MessagePackSerializerOptions.Standard ); // 2. 建立 HttpContent var content = new ByteArrayContent(requestBytes); content.Headers.ContentType = new MediaTypeHeaderValue("application/x-msgpack"); // 3. 呼叫 Server var response = await client.PostAsync( "http://localhost:5260/api/user/edit", content ); response.EnsureSuccessStatusCode(); // 4. 讀取 binary response var responseBytes = await response.Content.ReadAsByteArrayAsync(); // 5. Deserialize var responseUser = MessagePackSerializer.Deserialize<User>( responseBytes, MessagePackSerializerOptions.Standard ); Console.WriteLine( "Result:" + JsonConvert.SerializeObject(responseUser) );


執行結果:

Result:{"Id":1,"Name":"許當麻測試 --Server 改過了","Friends":[],"Age":43,"Alias":"測試","Salary":0.0,"Birth":"1981-01-01T00:00:00Z"}

來個結論,如果你是對外的專案當然就是以 JSON 為主,如果你是在 server 跟 server 之間的溝通

都是在自己可以控制的範圍,MessagePack 的確是一個好選擇,中間傳遞資料小了,還原速度也可以更快速

我個人在兩台自己的機器溝通的時候的確是採用這方案, 畢竟都是自己專案的機器一切都是好說話。



--

The bug existed in all possible states. Until I ran the code.

如果這篇文章有幫助到您幫我分享一下,讓我有寫下去的動力...