dapr微服务.net sdk入门
Actors入門(mén)
先決條件
.Net Core SDK 3.0
Dapr CLI
Dapr DotNet SDK
概述
本文檔描述如何在客戶(hù)端應(yīng)用程序上創(chuàng)建Actor(MyActor)并調(diào)用其方法.
MyActor --- MyActor.Interfaces|+- MyActorService|+- MyActorClient接口項(xiàng)目(\MyActor\MyActor.Interfaces)。此項(xiàng)目包含參與者的接口定義。Actor接口可以在任何名稱(chēng)的項(xiàng)目中定義。接口定義了actor實(shí)現(xiàn)和調(diào)用actor的客戶(hù)機(jī)共享的actor契約。因?yàn)榭蛻?hù)機(jī)項(xiàng)目可能依賴(lài)于它,所以通常在與actor實(shí)現(xiàn)分離的程序集中定義它是有意義的.
actor服務(wù)項(xiàng)目(\MyActor\MyActor service)。這個(gè)項(xiàng)目實(shí)現(xiàn)了ASP.Net核心web服務(wù),該服務(wù)將承載參與者。它包含actor MyActor.cs的實(shí)現(xiàn)。actor實(shí)現(xiàn)是從基類(lèi)型actor派生并實(shí)現(xiàn)MyActor.interfaces項(xiàng)目中定義的接口的類(lèi)。actor類(lèi)還必須實(shí)現(xiàn)一個(gè)構(gòu)造函數(shù),該構(gòu)造函數(shù)接受ActorService實(shí)例和ActorId,并將它們傳遞給基本actor類(lèi).
actor客戶(hù)端項(xiàng)目(\MyActor\MyActor client)此項(xiàng)目包含actor客戶(hù)端的實(shí)現(xiàn),該客戶(hù)端調(diào)用actor接口中定義的MyActor方法.
第1步 -?創(chuàng)建Actor接口
Actor接口定義Actor實(shí)現(xiàn)和調(diào)用Actor的客戶(hù)機(jī)共享的Actor契約.
Actor接口定義如下:
Actor接口必須繼承?Dapr.Actors.IActor?接口
Actor方法的返回類(lèi)型必須是Task或Task<object>
Actor方法最多可以有一個(gè)參數(shù)
創(chuàng)建項(xiàng)目和添加依賴(lài)
# Create Actor Interfaces dotnet new classlib -o MyActor.Interfacescd MyActor.Interfaces# Add Dapr.Actors nuget package dotnet add package Dapr.Actors升級(jí)項(xiàng)目到 .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>實(shí)現(xiàn) IMyActor?接口
定義 IMyActor?接口和 MyData?數(shù)據(jù)對(duì)象.
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步 -?創(chuàng)建Actor服務(wù)
Dapr使用ASP.NET web服務(wù)托管Actor服務(wù).?本節(jié)將實(shí)現(xiàn)?IMyActor?接口以及注冊(cè)Actor到Dapr運(yùn)行時(shí).
創(chuàng)建項(xiàng)目及添加依賴(lài)
# 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實(shí)現(xiàn)
實(shí)現(xiàn)IMyActor接口并從Dapr.Actors.Actor類(lèi)派生。下面的示例還演示了如何使用Actor提醒。對(duì)于A(yíng)ctor來(lái)說(shuō),使用提醒,它必須來(lái)源于IRemindable。如果不打算使用提醒功能,可以跳過(guò)實(shí)現(xiàn)下面代碼中顯示的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類(lèi)型名
默認(rèn)情況下,客戶(hù)端看到的actor的“類(lèi)型”是從actor實(shí)現(xiàn)類(lèi)的名稱(chēng)派生的。如果需要,可以通過(guò)將actor attribute屬性附加到actor實(shí)現(xiàn)類(lèi)來(lái)指定顯式類(lèi)型名.
[Actor(TypeName = "MyCustomActorTypeName")] internal class MyActor : Actor, IMyActor {// ... }注冊(cè) Actor?到 Dapr?運(yùn)行時(shí)
將?MyActor?注冊(cè)到 actor?runtime并設(shè)置本地主機(jī)端口(https://localhost:3000) , Dapr runtime可以通過(guò)該端口調(diào)用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步 -?添加客戶(hù)端
創(chuàng)建一個(gè)簡(jiǎn)單的控制臺(tái)應(yīng)用程序來(lái)調(diào)用actor服務(wù)。Dapr SDK提供Actor代理客戶(hù)端來(lái)調(diào)用Actor接口中定義的Actor方法.
創(chuàng)建項(xiàng)目并添加依賴(lài)
# 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遠(yuǎn)程服務(wù)調(diào)用Actor方法
我們建議使用本地代理到actor實(shí)例,因?yàn)锳ctorProxy.Create<IMyActor>(actorID,actorType)返回強(qiáng)類(lèi)型actor實(shí)例來(lái)設(shè)置遠(yuǎn)程過(guò)程調(diào)用.
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);}... }非遠(yuǎn)程方式調(diào)用 Actor?方法
如果Actor方法最多接受一個(gè)參數(shù),則可以調(diào)用Actor方法而無(wú)需遠(yuǎn)程處理(直接通過(guò)http或使用ActorProxy中提供的helper方法)。Actor運(yùn)行時(shí)將從客戶(hù)端反序列化傳入的請(qǐng)求體,并將其用作方法參數(shù)來(lái)調(diào)用Actor方法。當(dāng)進(jìn)行非遠(yuǎn)程處理調(diào)用時(shí),Actor方法參數(shù)和返回類(lèi)型被序列化,反序列化為JSON.
ActorProxy.Create(actorID, actorType)?返回?ActorProxy?實(shí)例并允許使用原始http客戶(hù)端調(diào)用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);}... }運(yùn)行Actor
為了驗(yàn)證及調(diào)試 actor?服務(wù)及客戶(hù)端,?我們首先需要通過(guò)Dapr CLI運(yùn)行actor服務(wù).
Run Dapr Runtime via Dapr cli
$ dapr run --app-id myapp --app-port 3000 dotnet MyActorService.dll在通過(guò)Dapr運(yùn)行時(shí)執(zhí)行MyActorService之后,確保在端口3000上發(fā)現(xiàn)應(yīng)用程序并成功建立actor連接.
運(yùn)行 MyActorClient
如果MyActorClient成功調(diào)用托管在MyActorService中的actor,它將在控制臺(tái)輸出.
如果指定不同的Dapr運(yùn)行時(shí)http端口(默認(rèn)端口:3500),則需要在運(yùn)行客戶(hù)端之前設(shè)置Dapr_http_port環(huán)境變量.
Success PropertyA: ValueA, PropertyB: ValueB?
原文參考翻譯:https://github.com/dapr/dotnet-sdk/blob/master/docs/get-started-dapr-actor.md
總結(jié)
以上是生活随笔為你收集整理的dapr微服务.net sdk入门的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: .NET Core 微服务学习与实践系列
- 下一篇: TPL Dataflow组件应对高并发,