Orleans8.2入门测试

微软官方文档:快速入门:使用 ASP.NET Core 生成第一个 Orleans 应用 - .NET | Microsoft Learn

项目及引入的nuget库:

1、接口项目;2、接口实现项目;3、silo项目;4、客户端项目

其中Microsoft.Orleans.Streaming,为测试流功能额外添加。 

//IHello.cs代码
using System.Reflection;namespace GrainInterfaces
{/// <summary>/// Grain接口/// 从IGrainWithStringKey继承可以使用字符串作为Grain的唯一标识,便于理解/// 从IGrainObserver继承为了支持订阅方式双向通信/// </summary>public interface IHello : IGrainWithStringKey, IGrainObserver{/// <summary>/// 默认测试接口/// </summary>/// <param name="greeting"></param>/// <returns></returns>ValueTask<string> SayHello(string greeting);/// <summary>/// 传递复杂对象测试/// </summary>/// <param name="param"></param>/// <returns></returns>ValueTask<ResultA> GetResultA(ParamA param);#region 用订阅方式实现双向通信Task NotifyOtherGrain(string grainID, string message);/// <summary>/// 客户端订阅Grain上的通知消息/// 需要额外的一个IGrainObserver类型对象IChat支持/// </summary>/// <param name="observer"></param>/// <returns></returns>Task Subscribe(IChat observer);/// <summary>/// 解除订阅/// </summary>/// <param name="observer"></param>/// <returns></returns>Task Unsubscribe(IChat observer);/// <summary>/// Grains直接通信,只要有Grains的id,就可以很方便的从客户端或其他grains中拿到grains的引用/// </summary>/// <param name="sender">目标grains的id</param>/// <param name="message">要转发的消息</param>/// <returns></returns>Task ReceiveBrotherMessage(string sender, string message);#endregion}#region 订阅方式支持类定义/// <summary>/// Grain类不允许出现属性,为了方便客户端订阅,额外定义一个带Action委托的接口让Chat对象实现/// </summary>public interface IChatNotify{/// <summary>/// 收到服务端通知触发事件,客户端指定处理事件/// </summary>Action<string> ReceiveAct { get; set; }}/// <summary>/// 消息订阅支持接口/// </summary>[Alias("GrainInterfaces.IChat")]public interface IChat : IGrainObserver{/// <summary>/// 定义订阅模式消息接收函数/// 注意IChat在客户端实例化,此函数在客户端执行/// </summary>/// <param name="message"></param>/// <returns></returns>[Alias("ReceiveMessage")]Task ReceiveMessage(string message);}/// <summary>/// 消息订阅类实现(在客户端实例化)/// </summary>public class Chat : IChat, IChatNotify{public Action<string> ReceiveAct { get; set; } = null;public Task ReceiveMessage(string message){var log = $"===={message}   {Assembly.GetEntryAssembly()?.FullName}";Console.WriteLine(log);ReceiveAct?.Invoke(message);return Task.CompletedTask;}}#endregion/// <summary>/// 定义复杂函数参数类型/// 注解GenerateSerializer:告诉Orleans使用其默认的序列化反序列化方式/// </summary>[GenerateSerializer]public class ParamA{[Id(0)]public int ID { get; set; }[Id(1)]public int DataLen { get; set; }[Id(2)]public required string Name { get; set; }}/// <summary>/// 定义复杂函数返回类型/// 注解GenerateSerializer:告诉Orleans使用其默认的序列化反序列化方式/// </summary>[GenerateSerializer]public class ResultA{[Id(0)]public int ID { get; set; }[Id(1)]public required string Name { get; set; }[Id(2)]public required byte[] Data { get; set; }}/// <summary>/// 测试用全局数据定义/// </summary>public static class GlobalValueDefinition{public const string StreamProviderName = "StreamProvider";public const string GrainStorageName = "PubSubStore";public const string ImplicitStreamSubscriptionName = "RANDOMDATA";}
}
//HelloGrains.cs
using GrainInterfaces;
using Microsoft.Extensions.Logging;
using Orleans;
using Orleans.Streams;
using Orleans.Utilities;
using System.Net.NetworkInformation;namespace Grains
{/// <summary>/// Hello Grain定义/// [ImplicitStreamSubscription(GlobalValueDefinition.ImplicitStreamSubscriptionName)]/// 这个注解告诉Orleans使用隐式订阅流(简化测试)/// </summary>[ImplicitStreamSubscription(GlobalValueDefinition.ImplicitStreamSubscriptionName)]public class HelloGrains :Grain, IHello{private readonly ILogger _logger;private readonly ObserverManager<IChat> _subManager;public HelloGrains(ILogger<HelloGrains> logger){_logger = logger;_subManager = new ObserverManager<IChat>(TimeSpan.FromMinutes(5), logger);Console.WriteLine($"====={GrainContext.GrainId}");}private IAsyncStream<string> _demoStream;public override Task OnActivateAsync(CancellationToken cancellationToken){#region 流的支持CreateStreamSubscribe().GetAwaiter().GetResult();#endregionreturn base.OnActivateAsync(cancellationToken);}private async Task CreateStreamSubscribe(){var guid = this.GetPrimaryKeyString();var streamProvider = this.GetStreamProvider(GlobalValueDefinition.StreamProviderName);var streamId = StreamId.Create(GlobalValueDefinition.ImplicitStreamSubscriptionName, guid);_demoStream = streamProvider.GetStream<string>(streamId);await _demoStream.SubscribeAsync<string>(async (data, token) => { Console.WriteLine($"*****Hello {data}");await Task.CompletedTask;});}#region 订阅支持public Task Subscribe(IChat observer) {_subManager.Subscribe(observer, observer);return Task.CompletedTask;}public Task Unsubscribe(IChat observer) { _subManager.Unsubscribe(observer); return Task.CompletedTask; }//向订阅者发送消息public Task SendUpdateMessage(string message){_subManager.Notify(s=>s.ReceiveMessage(message));return Task.CompletedTask;}#endregionpublic ValueTask<string> SayHello(string greeting){var response = $"Client {GrainContext.GrainId} said:{greeting}, so HelloGrain says: Hello";_logger.LogInformation(response);SendUpdateMessage("SendUpdateMessage:" + response);return ValueTask.FromResult(response);}public ValueTask<ResultA> GetResultA(ParamA param){_logger.LogInformation($"Invoke GetResultA({param.ID}  {param.Name})");var res = new ResultA{ID = param.ID + 1,Name = param.Name,Data = new byte[param.DataLen],};return ValueTask.FromResult(res);}public Task NotifyOtherGrain(string otherGrainID, string message){var otherGrainHello = GrainFactory.GetGrain<IHello>(otherGrainID);otherGrainHello.ReceiveBrotherMessage(this.GetPrimaryKeyString(), message);return Task.CompletedTask;}public Task ReceiveBrotherMessage(string sender, string message){SendUpdateMessage($"GetBrotherMessage({sender},{message})");return Task.CompletedTask;}}
}
//Silo服务启动源码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Orleans.Configuration;
using Orleans.Serialization;
using System.Net;
using GrainInterfaces;namespace Silo
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private async void button1_Click(object sender, EventArgs e){//本地集群方式部署var primarySiloEndPoint = new IPEndPoint(IPAddress.Parse(textBox_IPAddr.Text), 11_111);var silo = new HostBuilder().UseOrleans(builder =>{builder.UseDevelopmentClustering(primarySiloEndPoint).Configure<ClusterOptions>(options =>{options.ClusterId = "cluster001";options.ServiceId = "service001";}).ConfigureEndpoints(siloPort: 11_111, gatewayPort: 30_001).ConfigureLogging(logging => logging.AddConsole()).AddMemoryStreams(GlobalValueDefinition.StreamProviderName) //unget引入 Microsoft.Orleans.Streaming.AddMemoryGrainStorage(GlobalValueDefinition.GrainStorageName);}).Build();await silo.RunAsync();}//#region 本地测试模式IHostBuilder builder = Host.CreateDefaultBuilder(args).UseOrleans(silo =>{silo.UseLocalhostClustering(11111, 30001, serviceId: "service001", clusterId: "cluster001").ConfigureLogging(logging => logging.AddConsole());}).UseConsoleLifetime();using IHost host = builder.Build();await host.RunAsync();//#endregion}
}
//客户端代码
using GrainInterfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Orleans.Configuration;
using Orleans.Serialization.WireProtocol;
using Orleans.Streams;
using System.Net;
using System.Security.AccessControl;namespace WinFormsApp1
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private IClusterClient client = null;private IHost host = null;private IHello friend1;private IHello friend2;private IChat chat;private async void button1_Click(object sender, EventArgs e){#region 开发者模式连接//IHostBuilder builder = Host.CreateDefaultBuilder()//    .UseOrleansClient(client =>//    {//        client.UseLocalhostClustering(30001, "service001", "cluster001");//    })//    .ConfigureLogging(logging => logging.AddConsole())//    .UseConsoleLifetime();//host = builder.Build();//await host.StartAsync();//client = host.Services.GetRequiredService<IClusterClient>();#endregionvar PRIMARY_SILO_IP_ADDRESS = IPAddress.Parse(textBox_IPAddr.Text);//var PRIMARY_SILO_IP_ADDRESS_1 = IPAddress.Parse("192.168.100.101");#region 专用服务器群集模式连接var gateways = new IPEndPoint[] {new IPEndPoint(PRIMARY_SILO_IP_ADDRESS, 30_001)};host = Host.CreateDefaultBuilder().UseOrleansClient(clientBuilder =>clientBuilder.UseStaticClustering(gateways).Configure<ClusterOptions>(options =>{options.ClusterId = "cluster001";options.ServiceId = "service001";})#region Stream测试.AddMemoryStreams(GlobalValueDefinition.StreamProviderName)#endregion).Build();await host.StartAsync();client = host.Services.GetRequiredService<IClusterClient>();#endregion#region 订阅friend1 = client.GetGrain<IHello>("user1");friend2 = client.GetGrain<IHello>("user2");Chat c = new Chat();(c as IChatNotify).ReceiveAct += ShowLog;chat = client.CreateObjectReference<IChat>(c);await friend1.Subscribe(chat);#endregion#region StreamTestawait CreateStreamSubscribe();#endregion}private IAsyncStream<string> _demoStream;private async Task CreateStreamSubscribe(){var clientStreamName = "clientStream001";var streamProvider = client.GetStreamProvider(GlobalValueDefinition.StreamProviderName);var streamId = StreamId.Create(GlobalValueDefinition.ImplicitStreamSubscriptionName, clientStreamName);_demoStream = streamProvider.GetStream<string>(streamId);//流的内容可为容易可序列化类实例await _demoStream.SubscribeAsync<string>(async (data, token) =>{ShowLog($"*****Hello {data}");await Task.CompletedTask;});}private async void button2_Click(object sender, EventArgs e){await host.StopAsync();}private async void button3_Click(object sender, EventArgs e){string response = await friend1.SayHello("Hi friend!");ShowLog($"{friend1.GetPrimaryKeyString()}  {response}");}private void ShowLog(string log){Invoke(new Action(() =>{textBox1.AppendText($"{log}\r\n");}));}private async void button4_Click(object sender, EventArgs e){string response = await friend2.SayHello("Hi friend!");ShowLog($"{friend2.GetPrimaryKeyString()}  {response}");}private async void button5_Click(object sender, EventArgs e){IHello friend = client.GetGrain<IHello>("user1");var dateLen = Convert.ToInt32(textBox_DataLen.Text);var result = await friend.GetResultA(new ParamA { ID = 1, Name = "henreash", DataLen = dateLen });ShowLog($"GetResultA({result.ID} {result.Name}  {result.Data.Length})");}private void button6_Click(object sender, EventArgs e){friend2.NotifyOtherGrain(friend1.GetPrimaryKeyString(), "让user2转告user1");}private async void button7_Click(object sender, EventArgs e){await _demoStream.OnNextAsync("Send test stream message!");}}
}

结论:Orleans部署不需要额外的平台,编译后的进程直接启动;通过配置即可做集群扩展.grain和grain间,grain和客户端间很方便实现双向tcp通信.关闭silo服务,客户端访问失败,启动soli服务后客户端可继续访问.

服务器增加Dashboard

silo引入nuget库OleansDashboard(8.2.0),配置增加如下内容

可方便查看silo服务器的性能数据 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/463170.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电赛入门之软件stm32keil+cubemx

hal库可以帮我们一键生成许多基本配置&#xff0c;就不需要自己写了&#xff0c;用多了hal库就会发现原来用基本库的时候都过的什么苦日子&#xff08;笑 下面我们以f103c8t6&#xff0c;也就是经典的最小核心板来演示 一、配置工程 首先来新建一个工程 这里我们配置rcc和sys&…

第三十章 章节练习商品列表组件封装

目录 一、需求说明 二、技术要点 三、完整代码 3.1. main.js 3.2. App.vue 3.3. MyTable.vue 3.4. MyTag.vue 一、需求说明 1. my-tag 标签组件封装 (1) 双击显示输入框&#xff0c;输入框获取焦点 (2) 失去焦点&#xff0c;隐藏输入框 (3) 回显标签信息 (4) 内…

vue 快速入门

文章目录 一、插值表达式 {{}}二、Vue 指令2.1 v-text 和 v-html&#xff1a;2.2 v-if 和 v-show&#xff1a;2.3 v-on&#xff1a;2.4 v-bind 和 v-model&#xff1a;2.5 v-for&#xff1a; 三、生命周期四、Vue 组件库 Element五、Vue 路由 本文章适用于后端人员&#xff0c;…

数据建模圣经|数据模型资源手册卷2,探索数据库逻辑模型设计

在企业信息系统体系结构中&#xff0c;数据处于核心地位。数据模型是信息系统开发和应用的基本指南&#xff0c;在逻辑模型层面为数据在数据库中的存储提供蓝图&#xff0c;以及对宏观世界的抽象设计。 简介 《The Data Model Resource Book, Revised Edition, Volume2》&#…

形态学操作篇 原理公式代码齐活

一、腐蚀 腐蚀操作的核心原理是利用一个结构元素在图像上进行扫描&#xff0c;判断结构元素所覆盖的区域与前景像素的关系。如果结构元素完全被包含在前景像素区域内&#xff0c;那么结构元素中心对应的像素位置在腐蚀后的图像中被标记为前景像素&#xff1b;如果结构元素不完…

Unity引擎材质球残留贴图引用的处理

大家好&#xff0c;我是阿赵。   这次来分享一下Unity引擎材质球残留贴图引用的处理 一、 问题 在使用Unity调整美术效果的时候&#xff0c;我们很经常会有这样的操作&#xff0c;比如&#xff1a; 1、 同一个材质球切换不同的Shader、 比如我现在有2个Shader&#xff0c;…

Flarum:简洁而强大的开源论坛软件

Flarum简介 Flarum是一款开源论坛软件&#xff0c;以其简洁、快速和易用性而闻名。它继承了esoTalk和FluxBB的优良传统&#xff0c;旨在提供一个不复杂、不臃肿的论坛体验。Flarum的核心优势在于&#xff1a; 快速、简单&#xff1a; Flarum使用PHP构建&#xff0c;易于部署&…

数据结构-图

1. 感性的认识图 图是是数据结构中最复杂的一种。图的概念特别特别的多&#xff0c;相关的算法问题也很多。如果我们一开始就讲复杂的概念&#xff0c;可能很多同学都学不下去&#xff0c;太深奥&#xff0c;太枯燥。我们不妨先感性的认识图。 图看起来就像下图这样&#xff1…

普林斯顿微积分读本PDF(英文版原版)

普林斯顿微积分读本PDF英文版: https://caiyun.139.com/m/i?005Chb93yVHtQ 对于大多数学生来说&#xff0c;微积分或许是他们曾经上过的倍感迷茫且最受挫折的一门课程了. 而《普林斯顿微积分读本》 不仅让学生能有效地学习微积分&#xff0c;更重要的是提供了战胜微积分的必备…

Netty学习——NIO基础与IO模型

导学 Socket和NIO的区别 Socket和NIO是Java中用于网络编程的两个不同的API&#xff0c;具有不同的设计理念和用途。以下是它们的主要区别&#xff1a; 1. 定义 Socket: Socket是Java中用于实现网络通信的传统API&#xff0c;通常被称为Java I/O&#xff08;输入/输出&#…

Cesium基础-(Entity)-(ellipse)

里边包含Vue、React框架代码详细步骤、以及代码详细解释 6、ellipse 圆与椭圆 EllipseGeometry(椭圆几何体)是 Cesium 中用于在三维空间中创建椭圆形状的类。这种椭圆形状可以位于地球表面(或其他椭球体)上,也可以在地球表面上方或下方的一定高度。EllipseGeometry 允许你…

014:无人机遥控器操作

摘要&#xff1a;本文详细介绍了无人机遥控器及其相关操作。首先&#xff0c;解释了油门、升降舵、方向舵和副翼的概念、功能及操作方式&#xff0c;这些是控制无人机飞行姿态的关键部件。其次&#xff0c;介绍了美国手、日本手和中国手三种不同的操作模式&#xff0c;阐述了遥…

Java—— CompletableFuture

CompletableFuture 1、概述1.1、Future接口1.2、CompletionStage接口 2、CompletableFuture结构2.1、字段和常量2.2、内部类 3、CompletableFuture原理3.1、设计思想3.2、获取任务结果的实现不带参数的Get方法实现带超时参数的Get方法实现立即返回结果的GetNow方法实现 3.3、开…

uniapp使用uni.createInnerAudioContext()播放指定音频并且切换

uniapp使用uni.createInnerAudioContext()播放指定音频并且切换 因为做的小程序或者h5需要视频讲解或者音乐组件的 默认展示播放按钮&#xff0c;当点击播放的时候 显示暂停音乐这样的一个效果。 在unipp中我们直接只用uni.createInnerAudioContext()代替audio&#xff0c;使用…

《TCP/IP网络编程》学习笔记 | Chapter 2:套接字类型与协议设置

《TCP/IP网络编程》学习笔记 | Chapter 2&#xff1a;套接字类型与协议设置 《TCP/IP网络编程》学习笔记 | Chapter 2&#xff1a;套接字类型与协议设置套接字协议及其数据传输特性协议&#xff08;Protocol&#xff09;创建套接字协议族&#xff08;Protocol Family&#xff0…

小林渗透入门:burpsuite+proxifier抓取小程序流量

目录 前提&#xff1a; 代理&#xff1a; proxifier&#xff1a; 步骤&#xff1a; bp证书安装 bp设置代理端口&#xff1a; proxifier设置规则&#xff1a; proxifier应用规则&#xff1a; 结果&#xff1a; 前提&#xff1a; 在介绍这两个工具具体实现方法之前&#xff0…

举重场景哑铃图像分割系统:全面改进提升

举重场景哑铃图像分割系统源码&#xff06;数据集分享 [yolov8-seg-GhostHGNetV2&#xff06;yolov8-seg-EfficientHead等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AA…

【机器学习】连续属性离散化与sklearn.preprocessing.KBinsDiscretizer

1. KBinsDiscretizer的定义 KBinsDiscretizer是 scikit-learn 库中的一个类&#xff0c;用于将连续数据离散化成区间&#xff08;bins&#xff09;。这个类通过将特征值分配到 k 个等宽的区间&#xff08;bins&#xff09;来实现离散化&#xff0c;并且可以配置不同的编码方式…

OpenGL入门002——顶点着色器和片段着色器

文章目录 一些概念坐标转换阶段顶点着色器片段着色器VBOVAO 实战简介main.cppCMakeLists.txt最终效果 一些概念 坐标转换阶段 概述&#xff1a; 模型空间、世界空间、视图空间和裁剪空间是对象在3D场景中经历的不同坐标变换阶段。每个空间对应渲染管道的一个步骤&#xff0c;…

使用 Elastic、OpenLLMetry 和 OpenTelemetry 跟踪 LangChain 应用程序

作者&#xff1a;来自 Elastic Bahubali Shetti Langchain 应用程序的使用正在增长。构建基于 RAG 的应用程序、简单的 AI 助手等的能力正在成为常态。观察这些应用程序更加困难。考虑到现有的各种选项&#xff0c;本博客展示了如何将 OpenTelemetry 检测与 OpenLLMetry 结合使…