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服务.

  1. Run Dapr Runtime via Dapr cli

    $ dapr run --app-id myapp --app-port 3000 dotnet MyActorService.dll

    在通过Dapr运行时执行MyActorService之后,确保在端口3000上发现应用程序并成功建立actor连接.

  1. INFO[0000] starting Dapr Runtime -- version  -- commitINFO[0000] log level set to: infoINFO[0000] standalone mode configuredINFO[0000] dapr id: myappINFO[0000] loaded component statestore (state.redis)INFO[0000] application protocol: http. waiting on port 3000INFO[0000] application discovered on port 3000INFO[0000] application configuration loaded2019/08/27 14:42:06 redis: connecting to localhost:63792019/08/27 14:42:06 redis: connected to localhost:6379 (localAddr: [::1]:53155, remAddr: [::1]:6379)INFO[0000] actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30sINFO[0000] actors: starting connection attempt to placement service at localhost:50005INFO[0000] http server is running on port 3500INFO[0000] gRPC server is running on port 50001INFO[0000] dapr initialized. Status: Running. Init Elapsed 19.699438msINFO[0000] actors: established connection to placement service at localhost:50005INFO[0000] actors: placement order received: lockINFO[0000] actors: placement order received: updateINFO[0000] actors: placement tables updatedINFO[0000] actors: placement order received: unlock...
  2. 运行 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入门相关推荐

  1. Dapr微服务应用开发系列5:发布订阅构建块

    题记:这篇介绍发布订阅构建块,这是对事件驱动架构设计的一种实现落地. 注:对于"Building Blocks"这个词组的翻译,我之前使用了"构件块",现在和官 ...

  2. Dapr微服务应用开发系列4:状态管理构件块

    Dapr微服务应用开发系列0:概述 Dapr微服务应用开发系列1:环境配置 Dapr微服务应用开发系列2:Hello World与SDK初接触 Dapr微服务应用开发系列3:服务调用构件块 题记:这篇 ...

  3. go web框架_golang微服务框架go-micro 入门笔记2.2 micro工具之微应用利器micro web

    micro web micro 功能非常强大,本文将详细阐述micro web 命令行的功能 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go- ...

  4. 微服务应用开发入门④服务网关

    简述 相信通过微服务应用开发入门①web端架构演进的阅读,大家已经知道服务网关是干嘛的: 一般来说服务网关会做以下几件事情: 路由:路由是API网关很核心的模块功能,此模块实现根据请求,锁定目标微服务 ...

  5. 微服务架构从入门到精通(一)微服务介绍

    本系列文章包括微服务介绍.微服务架构.DevOps.APM等方面,尽量抓重点.不罗嗦,讲解微服务整个生态圈的技术性知识.期望各位同仁能快速的对微服务架构有个了解,加入到微服务最佳实践中来. 一.架构的 ...

  6. 微服务架构从入门到精通(二)微服务生态体系

    本篇承接上一篇文章<微服务架构从入门到精通(一)微服务介绍>讲起,主要是介绍微服务架构的技术生态体系,让大家对微服务架构整个生态圈有个大体的了解.10来多年的从业经验来看,学习技术一般都是 ...

  7. 【Kubernetes 企业项目实战】07、最新一代微服务网格 Istio 入门到企业实战(下)

    目录 一.istio 核心资源解读 1.1 Gateway 总结: 1.2 VirtualService 1.2.1 VirtualService 主要由以下部分组成 1.2.2 virtualser ...

  8. 微服务和VUE入门教程(26): 微服务之turbine

    微服务和VUE入门教程(26): 微服务之turbine 微服务和VUE入门教程(0): 着手搭建项目 微服务和VUE入门教程(1): 搭建前端登录界面 微服务和VUE入门教程(2): 注册中心 微服 ...

  9. Dapr微服务应用开发系列2:Hello World与SDK初接触

    题记:上篇介绍了Dapr的环境配置,这次我们来动手尝试一下Dapr应用的开发 Hello World Dapr应用的Hello World其实和其他的Hello World一样简单: 首先用你喜欢的语 ...

最新文章

  1. python 矩阵中的冒号 逗号
  2. webform开发经验(一):Asp.Net获取Checkbox选中的值
  3. EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器启用https服务申请免费证书...
  4. MySQL 也替换了master、slave
  5. 产品入门首月成长报告 | PMcaff-干货
  6. android底部导航栏软件,三步搞定android应用底部导航栏
  7. gitlab详细安装过程,错误解决方案
  8. 从零开始刷Leetcode——数组(1.26)
  9. java中的基本算法
  10. OPPO A57刷机 A57刷机包下载 纯净包 A57T忘记密码 帐号解锁 刷机教程 精简Rom刷机包
  11. 从零开始学习音视频编程技术(十三) 录屏软件开发之屏幕录像
  12. mac 装java eclipse_Mac安装Eclipse教程
  13. android 快速unity,关于android:Unity平台-快速集成华为性能管理服务
  14. c语言根二的连分数,纯循环连分数 与 二次方程的根
  15. 先手获胜逻辑题_宣布障碍塔挑战赛的获胜者和开源版本
  16. 利用python实现PSM
  17. Q7:难道不想手工搞个环境?
  18. C# 后台 背景图片拼接图片与文字,文字图片生成与背景图片合成
  19. 【数据库】数据库索引
  20. 汇总解决idea出现import包时报错Java:程序包xxxx不存在,但包确实存在的问题

热门文章

  1. 【原创】mysql数据库异常:data truncate for column “*” at row *;data too long *。原因,及解决。...
  2. 八、结构模式之组合(Composite)模式
  3. LiveJournal发展历程
  4. HTML标题h,HTML H标题标签
  5. Teams的manifest文件开始支持多语言
  6. 我为什么卸载了今日头条
  7. Centos6.5使用ELK(Elasticsearch + Logstash + Kibana) 搭建日志集中分析平台实践
  8. php 利用http上传协议(表单提交上传图片 )
  9. hdu 4049 Tourism Planning [ 状压dp ]
  10. Mahout的taste推荐系统里的几种Recommender分析