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

  • 205
  • 0
  • 2026-01-08

很多人聽過 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 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 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(
               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(
                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 的確是一個好選擇,中間傳遞資料小了,還原速度也可以更快速

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

--

本文原文首發於個人部落格:Server 與 Client 全程走 MessagePack:一個 .NET 10 Web API 的實作紀錄

--

---

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