dapr微服务.net sdk入门
Actors入門
先決條件
.Net Core SDK 3.0
Dapr CLI
Dapr DotNet SDK
概述
本文檔描述如何在客戶端應用程序上創建Actor(MyActor)并調用其方法.
MyActor --- MyActor.Interfaces|+- MyActorService|+- MyActorClient接口項目(\MyActor\MyActor.Interfaces)。此項目包含參與者的接口定義。Actor接口可以在任何名稱的項目中定義。接口定義了actor實現和調用actor的客戶機共享的actor契約。因為客戶機項目可能依賴于它,所以通常在與actor實現分離的程序集中定義它是有意義的.
actor服務項目(\MyActor\MyActor service)。這個項目實現了ASP.Net核心web服務,該服務將承載參與者。它包含actor MyActor.cs的實現。actor實現是從基類型actor派生并實現MyActor.interfaces項目中定義的接口的類。actor類還必須實現一個構造函數,該構造函數接受ActorService實例和ActorId,并將它們傳遞給基本actor類.
actor客戶端項目(\MyActor\MyActor client)此項目包含actor客戶端的實現,該客戶端調用actor接口中定義的MyActor方法.
第1步 -?創建Actor接口
Actor接口定義Actor實現和調用Actor的客戶機共享的Actor契約.
Actor接口定義如下:
Actor接口必須繼承?Dapr.Actors.IActor?接口
Actor方法的返回類型必須是Task或Task<object>
Actor方法最多可以有一個參數
創建項目和添加依賴
# Create Actor Interfaces dotnet new classlib -o MyActor.Interfacescd MyActor.Interfaces# Add Dapr.Actors nuget package dotnet add package Dapr.Actors升級項目到 .NET Core 3.0
更新csproj文件中的netcore到 .NET Core 3.0
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>netcoreapp3.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="Dapr.Actors" Version="0.1.0-preview01" /></ItemGroup> </Project>實現 IMyActor?接口
定義 IMyActor?接口和 MyData?數據對象.
using Dapr.Actors; using System.Threading.Tasks;namespace MyActor.Interfaces {public interface IMyActor : IActor{Task<string> SetDataAsync(MyData data);Task<MyData> GetDataAsync();Task RegisterReminder();Task UnregisterReminder();Task RegisterTimer();Task UnregisterTimer();}public class MyData{public string PropertyA { get; set; }public string PropertyB { get; set; }public override string ToString(){var propAValue = this.PropertyA == null ? "null" : this.PropertyA;var propBValue = this.PropertyB == null ? "null" : this.PropertyB;return $"PropertyA: {propAValue}, PropertyB: {propBValue}";}} }第2步 -?創建Actor服務
Dapr使用ASP.NET web服務托管Actor服務.?本節將實現?IMyActor?接口以及注冊Actor到Dapr運行時.
創建項目及添加依賴
# Create ASP.Net Web service to host Dapr actor dotnet new webapi -o MyActorServicecd MyActorService# Add Dapr.Actors nuget package dotnet add package Dapr.Actors# Add Dapr.Actors.AspNetCore nuget package dotnet add package Dapr.Actors.AspNetCore# Add Actor Interface reference dotnet add reference ../MyActor.Interfaces/MyActor.Interfaces.csproj添加Actor實現
實現IMyActor接口并從Dapr.Actors.Actor類派生。下面的示例還演示了如何使用Actor提醒。對于Actor來說,使用提醒,它必須來源于IRemindable。如果不打算使用提醒功能,可以跳過實現下面代碼中顯示的IRemindable和提醒特定方法.
using Dapr.Actors; using Dapr.Actors.Runtime; using MyActor.Interfaces; using System; using System.Threading.Tasks;namespace MyActorService {internal class MyActor : Actor, IMyActor, IRemindable{/// <summary>/// Initializes a new instance of MyActor/// </summary>/// <param name="actorService">The Dapr.Actors.Runtime.ActorService that will host this actor instance.</param>/// <param name="actorId">The Dapr.Actors.ActorId for this actor instance.</param>public MyActor(ActorService actorService, ActorId actorId): base(actorService, actorId){}/// <summary>/// This method is called whenever an actor is activated./// An actor is activated the first time any of its methods are invoked./// </summary>protected override Task OnActivateAsync(){// Provides opportunity to perform some optional setup.Console.WriteLine($"Activating actor id: {this.Id}");return Task.CompletedTask;}/// <summary>/// This method is called whenever an actor is deactivated after a period of inactivity./// </summary>protected override Task OnDeactivateAsync(){// Provides Opporunity to perform optional cleanup.Console.WriteLine($"Deactivating actor id: {this.Id}");return Task.CompletedTask;}/// <summary>/// Set MyData into actor's private state store/// </summary>/// <param name="data">the user-defined MyData which will be stored into state store as "my_data" state</param>public async Task<string> SetDataAsync(MyData data){// Data is saved to configured state store implicitly after each method execution by Actor's runtime.// Data can also be saved explicitly by calling this.StateManager.SaveStateAsync();// State to be saved must be DataContract serialziable.await this.StateManager.SetStateAsync<MyData>("my_data", // state namedata); // data saved for the named state "my_data"return "Success";}/// <summary>/// Get MyData from actor's private state store/// </summary>/// <return>the user-defined MyData which is stored into state store as "my_data" state</return>public Task<MyData> GetDataAsync(){// Gets state from the state store.return this.StateManager.GetStateAsync<MyData>("my_data");}/// <summary>/// Register MyReminder reminder with the actor/// </summary>public async Task RegisterReminder(){await this.RegisterReminderAsync("MyReminder", // The name of the remindernull, // User state passed to IRemindable.ReceiveReminderAsync()TimeSpan.FromSeconds(5), // Time to delay before invoking the reminder for the first timeTimeSpan.FromSeconds(5)); // Time interval between reminder invocations after the first invocation}/// <summary>/// Unregister MyReminder reminder with the actor/// </summary>public Task UnregisterReminder(){Console.WriteLine("Unregistering MyReminder...");return this.UnregisterReminderAsync("MyReminder");}// <summary>// Implement IRemindeable.ReceiveReminderAsync() which is call back invoked when an actor reminder is triggered.// </summary>public Task ReceiveReminderAsync(string reminderName, byte[] state, TimeSpan dueTime, TimeSpan period){Console.WriteLine("ReceiveReminderAsync is called!");return Task.CompletedTask;}/// <summary>/// Register MyTimer timer with the actor/// </summary>public Task RegisterTimer(){return this.RegisterTimerAsync("MyTimer", // The name of the timerthis.OnTimerCallBack, // Timer callbacknull, // User state passed to OnTimerCallback()TimeSpan.FromSeconds(5), // Time to delay before the async callback is first invokedTimeSpan.FromSeconds(5)); // Time interval between invocations of the async callback}/// <summary>/// Unregister MyTimer timer with the actor/// </summary>public Task UnregisterTimer(){Console.WriteLine("Unregistering MyTimer...");return this.UnregisterTimerAsync("MyTimer");}/// <summary>/// Timer callback once timer is expired/// </summary>private Task OnTimerCallBack(object data){Console.WriteLine("OnTimerCallBack is called!");return Task.CompletedTask;}} }使用顯式actor類型名
默認情況下,客戶端看到的actor的“類型”是從actor實現類的名稱派生的。如果需要,可以通過將actor attribute屬性附加到actor實現類來指定顯式類型名.
[Actor(TypeName = "MyCustomActorTypeName")] internal class MyActor : Actor, IMyActor {// ... }注冊 Actor?到 Dapr?運行時
將?MyActor?注冊到 actor?runtime并設置本地主機端口(https://localhost:3000) , Dapr runtime可以通過該端口調用actor.
private const int AppChannelHttpPort = 3000;public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().UseActors(actorRuntime =>{// Register MyActor actor typeactorRuntime.RegisterActor<MyActor>();}).UseUrls($"http://localhost:{AppChannelHttpPort}/");更新Startup.cs
public class Startup{...public void ConfigureServices(IServiceCollection services){services.AddRouting();}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}else{app.UseHsts();}}}第3步 -?添加客戶端
創建一個簡單的控制臺應用程序來調用actor服務。Dapr SDK提供Actor代理客戶端來調用Actor接口中定義的Actor方法.
創建項目并添加依賴
# Create Actor's Client dotnet new console -o MyActorClientcd MyActorClient# Add Dapr.Actors nuget package dotnet add package Dapr.Actors# Add Actor Interface reference dotnet add reference ../MyActor.Interfaces/MyActor.Interfaces.csproj使用Actor遠程服務調用Actor方法
我們建議使用本地代理到actor實例,因為ActorProxy.Create<IMyActor>(actorID,actorType)返回強類型actor實例來設置遠程過程調用.
namespace MyActorClient {using Dapr.Actors;using Dapr.Actors.Client;using MyActor.Interfaces;using System;using System.Threading.Tasks;...static async Task InvokeActorMethodWithRemotingAsync(){var actorType = "MyActor"; // Registered Actor Type in Actor Servicevar actorID = new ActorId("1");// Create the local proxy by using the same interface that the service implements// By using this proxy, you can call strongly typed methods on the interface using Remoting.var proxy = ActorProxy.Create<IMyActor>(actorID, actorType);var response = await proxy.SetDataAsync(new MyData(){PropertyA = "ValueA",PropertyB = "ValueB",});Console.WriteLine(response);var savedData = await proxy.GetDataAsync();Console.WriteLine(savedData);}... }非遠程方式調用 Actor?方法
如果Actor方法最多接受一個參數,則可以調用Actor方法而無需遠程處理(直接通過http或使用ActorProxy中提供的helper方法)。Actor運行時將從客戶端反序列化傳入的請求體,并將其用作方法參數來調用Actor方法。當進行非遠程處理調用時,Actor方法參數和返回類型被序列化,反序列化為JSON.
ActorProxy.Create(actorID, actorType)?返回?ActorProxy?實例并允許使用原始http客戶端調用IMyActor中定義的方法.
namespace MyActorClient {using Dapr.Actors;using Dapr.Actors.Client;using MyActor.Interfaces;using System;using System.Threading.Tasks;...static async Task InvokeActorMethodWithoutRemotingAsync(){var actorType = "MyActor";var actorID = new ActorId("1");// Create Actor Proxy instance to invoke the methods defined in the interfacevar proxy = ActorProxy.Create(actorID, actorType);// Need to specify the method name and response type explicitlyvar response = await proxy.InvokeAsync<string>("SetMyDataAsync", new MyData(){PropertyA = "ValueA",PropertyB = "ValueB",});Console.WriteLine(response);var savedData = await proxy.InvokeAsync<MyData>("GetMyDataAsync");Console.WriteLine(savedData);}... }運行Actor
為了驗證及調試 actor?服務及客戶端,?我們首先需要通過Dapr CLI運行actor服務.
Run Dapr Runtime via Dapr cli
$ dapr run --app-id myapp --app-port 3000 dotnet MyActorService.dll在通過Dapr運行時執行MyActorService之后,確保在端口3000上發現應用程序并成功建立actor連接.
運行 MyActorClient
如果MyActorClient成功調用托管在MyActorService中的actor,它將在控制臺輸出.
如果指定不同的Dapr運行時http端口(默認端口:3500),則需要在運行客戶端之前設置Dapr_http_port環境變量.
Success PropertyA: ValueA, PropertyB: ValueB?
原文參考翻譯:https://github.com/dapr/dotnet-sdk/blob/master/docs/get-started-dapr-actor.md
總結
以上是生活随笔為你收集整理的dapr微服务.net sdk入门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET Core 微服务学习与实践系列
- 下一篇: TPL Dataflow组件应对高并发,