Actors入门

先决条件

概述

本文档描述如何在客户端应用程序上创建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.Interfaces cd 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.</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 MyActorService cd 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 name
data); // 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 reminder
null, // User state passed to IRemindable.ReceiveReminderAsync()
TimeSpan.FromSeconds(), // Time to delay before invoking the reminder for the first time
TimeSpan.FromSeconds()); // 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 timer
this.OnTimerCallBack, // Timer callback
null, // User state passed to OnTimerCallback()
TimeSpan.FromSeconds(), // Time to delay before the async callback is first invoked
TimeSpan.FromSeconds()); // 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 = ;

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseActors(actorRuntime =>
{
// Register MyActor actor type
actorRuntime.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 MyActorClient cd 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 Service
var actorID = new ActorId(""); // 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(""); // Create Actor Proxy instance to invoke the methods defined in the interface
var proxy = ActorProxy.Create(actorID, actorType);
// Need to specify the method name and response type explicitly
var 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  dotnet MyActorService.dll

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

    INFO[0000] starting Dapr Runtime -- version  -- commit
    INFO[0000] log level set to: info
    INFO[0000] standalone mode configured
    INFO[0000] dapr id: myapp
    INFO[0000] loaded component statestore (state.redis)
    INFO[0000] application protocol: http. waiting on port 3000
    INFO[0000] application discovered on port 3000
    INFO[0000] application configuration loaded
    2019/08/27 14:42:06 redis: connecting to localhost:6379
    2019/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: 30s
    INFO[0000] actors: starting connection attempt to placement service at localhost:50005
    INFO[0000] http server is running on port 3500
    INFO[0000] gRPC server is running on port 50001
    INFO[0000] dapr initialized. Status: Running. Init Elapsed 19.699438ms
    INFO[0000] actors: established connection to placement service at localhost:50005
    INFO[0000] actors: placement order received: lock
    INFO[0000] actors: placement order received: update
    INFO[0000] actors: placement tables updated
    INFO[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微服务.netcore sdk入门的更多相关文章

  1. 微服务 + Docker + Kubernetes 入门实践 目录

    微服务 + Docker + Kubernetes 入门实践: 微服务概念 微服务的一些基本概念 环境准备 Ubuntu & Docker 本文主要讲解在 Ubuntu 上安装和配置 Dock ...

  2. Surging 微服务框架使用入门

    原文:Surging 微服务框架使用入门 前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正.  我对 surging 的看法 我目前所在的公司采用架构就是类似与Sur ...

  3. golang微服务框架go-micro 入门笔记2.4 go-micro service解读

    本章节阐述go-micro 服务发现原理 go-micro架构 下图来自go-micro官方 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go- ...

  4. golang微服务框架go-micro 入门笔记2.3 micro工具之消息接收和发布

    本章节阐述micro消息订阅和发布相关内容 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架go-mi ...

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

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

  6. 微服务和SpringCloud入门

    微服务和SpringCloud入门 微服务是什么 微服务的核心是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底去耦合,每个微服务提供单个业务功能的服务,一个服务做一件事情,从技术角度看就是一种 ...

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

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

  8. Dapr微服务应用开发系列0:概述

    题记:Dapr是什么,Dapr包含什么,为什么要用Dapr. Dapr是什么 Dapr(Distributed Application Runtime),是微软Azure内部创新孵化团队的一个开源项目 ...

  9. Dapr微服务应用开发系列3:服务调用构件块

    题记:这篇开始逐一深入介绍各个构件块,从服务调用开始 原理 所谓服务调用,就是通过这个构件块让你方便的通过HTTP或者gRPC协议同步调用其他服务的方法,这些方法也是通过HTTP或者gRPC来暴露的. ...

随机推荐

  1. nyoj 1112-求次数 (string, substr(begin, length), map, pair)

    1112-求次数 内存限制:64MB 时间限制:1000ms 特判: No 通过数:3 提交数:8 难度:2 题目描述: 题意很简单,给一个数n 以及一个字符串str,区间[i,i+n-1] 为一个新 ...

  2. Java描述设计模式(22):策略模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 每年双十一,各大电商平台会推出不同的满减策略,当用户的消费金额满一定额度后,会进行减去一定的优惠额度,从而来一波清仓甩卖,使用策 ...

  3. Django使用mysql数据的流程

    创建一个mysql数据库 1.打开终端(cmd): 输入: mysql -uroot -p 密码:*** 输入: create database 数据库名字; 2.在settings中进行配置 DAT ...

  4. Coding,命名是个技术活

    来吧 日常编码少不了的事情就是给代码命名,代码中命名的重要性在项目前期不会有太大感受,因为是边做边命名,代码天天见,自然会加深记忆.但到了后期上线后半年一年后,再回过头看的时候,我擦,这个变量是啥意思 ...

  5. 2019-10-28:渗透测试学习,sqlmap的使用,笔记

    sqlmap工具的使用sql注入工具,明小子,啊D,萝卜头,穿山甲,sqlmap等开源自动化注入利用工具,支持的数据库有12种,在/plugins中可以看到支持的数据库种类,在所有注入利用工具中是最好 ...

  6. VS Code 中文社区正式成立啦!VS Code Day 圆满落幕!

    背景简介 Visual Studio Code 是一款现代化轻量级代码编辑器,它免费.开源.跨平台.功能强大.本次 VS Code Day 是广大 VS Code 爱好者一起学习与交流的盛会,让我们对 ...

  7. css优先级之important

    css优先级之important

  8. Linux -- 进程间通信之管道

    管道是 Linux 里的一种文件类型,同时也是 Linux 系统下进程间通信的一种方式   创建一个管道文件有两种方式:  Shell 下命令 mkfifo + filename,即创建一个有名管道 ...

  9. 【Android - 控件】之MD - Snackbar的使用

    Snackbar 是 Android 5.0 新特性——Material Design 中的一个控件,用来代替 Toast ,Snackbar与Toast的主要区别是:Snackbar可以滑动退出,也 ...

  10. Djangoday1 入门及第一个apphelloworld

    1 Django基础指令新建一个django project新建app创建数据库表,更新数据库表或字段使用开发服务器清空数据库创建超级管理员导出数据 导入数据Django 项目环境终端数据库命令行更多 ...