Grain實作的非同步RPC方法要被呼叫,分為三種情況:
Orleans Client端
呼叫GetGrain<T>()
方法,取得Grain的RPC參考實體,再呼叫Grain的非同步RPC方法。
await client.Connect();
var grainProxy = client.GetGrain<IMyGrain>(a_identity_value);
await grainProxy.MyMethod();
GrainFactory
屬性,透過此屬性取得其他Grain的RPC參考實體,就可呼叫Grain的非同步RPC方法。
// inside a grain
var grainProxy = GrainFactory.GetGrain<IMyGrain>(a_identity_value);
await grainProxy.MyMethod();
IGrainFactory
介面的實體,才有辦法呼叫其定義的GetGrain<T>()
方法取得RPC參考實體進行呼叫;在跟ASP.NET Core使用『Co-Hosting』的方式跑Silo時(也就是在ASP.NET Core的HostBuilder配置時呼叫UseOrleans()
擴充方法),Orleans框架有註冊IGrainFactory
服務進ASP.NET Core的依賴注入(Dependency Injection, DI)機制,因此,我們可藉由ASP.NET Core的DI機制取得IGrainFactory
服務實體,接下來就如同上述方式來呼叫Grain的非同步RPC方法:
// After hostBuilder.Build() and .Run() or StartAsync() in Program.cs
var grainFactory = host.Services.GetRequiredService<IGrainFactory>();
// Or inside a ASP.NET Core controller
var grainFactory = HttpContext.RequestServices.GetService<IGrainFactory>();
// Then we can get grain RPC proxy and call grain RPC method
var grainProxy = grainFactory.GetGrain<IMyGrain>(a_identity_value);
await grainProxy.MyMethod();
要對Grain的RPC方法進行單元測試,Orleans框架有提供一個 Microsoft.Orleans.TestingHost Nuget套件,裡面的TestCluster
類別,用來模擬單一個Silo的環境,可在單元測試專案中,透過TestCluster
類別的GrainFactory
屬性取得Grain的RPC參考實體,進行呼叫Grain的非同步RPC方法。
以下為對我們前天的Grain實作專案 RpcDemo.Grains.Greeting 中的 HelloGrain
進行單元測試範例:
dotnet new xunit --no-restore --name GreetingGrain.Tests
dotnet add .\GreetingGrain.Tests\GreetingGrain.Tests.csproj package Microsoft.Orleans.TestingHost
dotnet add .\GreetingGrain.Tests\GreetingGrain.Tests.csproj reference ..\src\Grains\RpcDemo.Grains.Greeting\RpcDemo.Grains.Greeting.csproj
dotnet sln add .\tests\GreetingGrain.Tests\GreetingGrain.Tests.csproj --solution-folder tests
using Orleans.TestingHost;
using RpcDemo.Interfaces.Hello;
namespace GreetingGrain.Tests;
public class HelloGrainTest
{
[Fact]
public async Task TestSimpleSayHello()
{
//Arrange
var builder = new TestClusterBuilder();
builder.AddSiloBuilderConfigurator<TestSiloConfigurator>();
var cluster = builder.Build();
await cluster.DeployAsync();
//Act
var helloGrain = cluster.GrainFactory.GetGrain<IHelloGrain>(0);
var greeting = await helloGrain.SayHello("world");
//Assert
Assert.Equal("Hello world!", greeting);
}
}
TestCluster
需要用 TestClusterBuilder
來建置,而該種Builder在Silo方面的配置程式碼寫法,Orleans的設計是透過實作 ISiloConfigurator
介面的自訂類別(Class)來進行,所以下一個步驟就是建立該類別。using Orleans.Hosting;
using Orleans.TestingHost;
namespace GreetingGrain.Tests;
public class TestSiloConfigurator : ISiloConfigurator
{
public void Configure(ISiloBuilder siloBuilder)
{
//Do silo configuration here
}
}
由於目前要測試的Grain RpcDemo.Grains.Greeting.HelloGrain 沒有使用Grain State, Streaming, Reminder等Orleans提供的框架功能,因此現在沒有需要特別的配置設定要做,此類別的SiloBuilder實際配置程式碼 void Configure(ISiloBuilder siloBuilder)
的實作就先留空。執行單元測試的方法有兩種:
dotnet test
{
"dotnet-test-explorer.testProjectPath": "tests/**/*Tests.@(csproj|vbproj|fsproj)"
}
整個完成的範例程式GitHub專案在:https://github.com/windperson/OrleansRpcDemo/tree/day08
明天會繼續介紹Orleans的Grain使用 .NET Core/.NET 5+ 內建的依賴注入外部服務的方法,以及對應的單元測試專案撰寫技巧。