.NET 6 使用 MagicOnion MagicOnion開源地址:https://github.com/Cysharp/MagicOnion 什麼是MagicOnion? MagicOnion 是用於 .NET 平臺的現代 RPC 框架,它提供雙向實時通信(如SignalR和Socket.io ...
.NET 6 使用 MagicOnion
MagicOnion開源地址:https://github.com/Cysharp/MagicOnion
什麼是MagicOnion?
MagicOnion 是用於 .NET 平臺的現代 RPC 框架,它提供雙向實時通信(如SignalR和Socket.io)和 RPC 機制(如 WCF 和基於 Web 的 API)。
此框架基於gRPC,它是用於 HTTP/2 的快速緊湊的二進位網路傳輸。但是,與普通 gRPC 不同,它將 C# 介面視為協議架構,從而在沒有 C# 項目(協議緩衝區 IDL)的情況下實現無縫代碼共用。.proto
MagicOnion快速入門 (創建伺服器端項目)
首先,您需要從 Visual Studio 或 .NET CLI 工具中創建gRPC Service項目。MagicOnion Server 建立在 ASP.NET Core 和 gRPC 之上,因此伺服器項目必須是 ASP.NET Core 項目。
創建gRPC伺服器微軟文檔:在 ASP.NET Core 中創建 .NET Core gRPC 客戶端和伺服器 | Microsoft Learn
創建項目時,它包含 protos 文件夾,這個在 MagicOnion 中不需要所以可以刪除。
將 NuGet 包添加到項目。MagicOnion.Server
當然也可以用開發者 PowerShell 命令安裝命令如下:
dotnet add package MagicOnion.Server
因為我們用的是 .NET 6 框架沒有 Startup.cs 文件,所以我們在 Program.cs 中添加
builder.Services.AddMagicOnion();
app.UseEndpoints
調用方法重寫如下。
app.UseEndpoints(endpoints =>
{
endpoints.MapMagicOnionService();
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
});
});
完整的 Program.cs 文件如下:
using MyFirstMagicOnionServer.Services;
var builder = WebApplication.CreateBuilder(args);
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
// Add services to the container.
builder.Services.AddGrpc();
builder.Services.AddMagicOnion();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.MapGrpcService<GreeterService>();
app.UseRouting() // 添加 UseRouting
app.UseEndpoints(endpoints =>
{
endpoints.MapMagicOnionService();
app.MapGet("/", async context =>
{
await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
});
});
app.Run();
ps:這邊有個坑,運行之後會報一個錯誤:EndpointRoutingMiddleware matches endpoints setup by EndpointMiddleware and so must be added to the request execution pipeline before EndpointMiddleware. Please add EndpointRoutingMiddleware by calling 'IApplicationBuilder.UseRouting' inside the call to 'Configure(...)' in the application startup code.
意思就是說要在app.UseEndpoints()
方法前面加上app.UseRouting()
方法
在RPC服務端項目上使用MagicOnion
MagicOnion提供類似Web API的RPC服務和用於實時通信的StreamingHub。本節實現類似於 Web API 的 RPC 服務。添加要在伺服器和客戶端之間共用的介面(命名空間應與項目匹配)。
創建共用庫(共用庫,客戶端服務端都要有)
創建一個 Shared 文件夾 裡面再創建一個介面文件 IMyFirstService
using MagicOnion;
namespace MyFirstMagicOnionServer.Shared
{
// 將 .NET 介面定義為 Server/Client IDL.
// 這介面在伺服器和客戶端之間共用
public interface IMyFirstService : IService<IMyFirstService>
{
// 該返回的類型必須是 UnaryResult<T>
UnaryResult<int> SumAsync (int x,int y);
}
}
添加實現介面的類(服務端實現)
創建一個 Service 文件夾裡面再創建一個實現類 MyFirstMagicOnionServer
using MagicOnion;
using MagicOnion.Server;
using MyFirstMagicOnionServer.Shared;
namespace MyFirstMagicOnionServer.Services
{
public class MyFirstService : ServiceBase<IMyFirstService>, IMyFirstService
{
public async UnaryResult<int> SumAsync(int x, int y)
{
Console.WriteLine($"Received:{x}, {y}");
await Task.Run(() => true);
return x + y;
}
}
}
客戶端:在MagicOnion上調用服務
創建控制台應用程式項目並將 NuGet 包添加到該項目。MagicOnion.Client
與客戶端共用介面。以某種方式共用介面定義,例如文件鏈接、共用庫或複製和粘貼。IMyFirstService
我這邊採用複製粘貼的模式把 MagicOnion 服務端上的shared
文件夾複製到控制台程式(這邊記得修改IMyFirstService
的命名空間)
在客戶端代碼中,共用介面上的 Createclient 代理並透明地調用服務。MagicOnionClient
using Grpc.Net.Client;
using MagicOnion.Client;
using MyFirstMagicOnionClient.Shared;
// 引用 gRPC 的 channel 連接到伺服器。
var channel = GrpcChannel.ForAddress("http://localhost:33559"); // 服務端運行的介面地址
// 創建一個代理來透明的調用伺服器
IMyFirstService client = MagicOnionClient.Create<IMyFirstService>(channel);
// 使用代理調用服務端的方法
var result = await client.SumAsync(123, 456);
Console.WriteLine($"Result: {result}");
介紹 MagicOnion 的四個 NuGet 包
MagicOnion.Server
包來實現伺服器。您需要安裝此軟體包才能在伺服器上實現服務。MagicOnion.Client
包來實現客戶端。若要實現 WPF 和 Xamarin 等客戶端,需要安裝此包。MagicOnion.Abstractions
該包提供伺服器和客戶端常用的介面和屬性。若要創建在伺服器和客戶端之間共用的類庫項目,需要安裝此包。MagicOnion
包是元包,用於實現伺服器和客戶端的角色。 若要實現伺服器到伺服器的通信(如微服務),可以是伺服器也可以是客戶端,我們建議安裝此包。
WebApi 使用 MagicOnion
- 創建一個 WebApi 項目(名字自取)
- 和上面控制台伺服器一樣添加 Nuget 包
MagicOnion.Server
- 在 Program.cs 裡面添加:
builder.Services.AddGrpc();
builder.Services.AddMagicOnion();
app.UseRouting(); // 調用UseRouting()
app.UseEndpoints(endpoints =>
{
endpoints.MapMagicOnionService();
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
});
});
附帶完整的 Program.cs
using MagicOnion;
using MagicOnion.Server;
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();
#region 添加的 MagicOnion
builder.Services.AddGrpc();
builder.Services.AddMagicOnion();
#endregion
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseRouting(); // 調用UseRouting()
app.UseAuthorization();
// 添加的
app.UseEndpoints(endpoints =>
{
endpoints.MapMagicOnionService();
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
});
});
app.MapControllers();
app.Run();
- 創建介面和實現類
創建介面:和上面gRPC一樣 創建一個 Shared 文件夾,裡面創建 IMyFirstService 介面文件
using MagicOnion;
namespace MagicOnionWebApi.Shared
{
// 將 .NET 介面定義為 Server/Client IDL.
// 這介面在伺服器和客戶端之間共用
public interface IMyFirstService : IService<IMyFirstService>
{
// 該返回的類型必須是 UnaryResult<T>
UnaryResult<int> SumAsync (int x,int y);
}
}
實現介面:也和上面一樣創建一個 Service 文件夾裡面再創建一個實現類 MyFirstMagicOnionServer
public class MyFirstService : ServiceBase<IMyFirstService>, IMyFirstService
{
public async UnaryResult<int> SumAsync(int x, int y)
{
Console.WriteLine("服務端接受到請求");
Console.WriteLine($"Received:{x}, {y}");
await Task.Run(() => true);
return x + y;
}
}
- 客戶端調用:
用上面創建的 MagicOnion 客戶端項目改一下請求地址就好了:
// 修改服務端的介面地址
var channel = GrpcChannel.ForAddress("https://localhost:7109"); // 服務端運行的介面地址