Orleans[NET Core 3.1] 学习笔记(四)( 2 )获取Grain的方式

简介

在这一节,我们将介绍如何在SiloClient中获取Grain及调用Grain

Grain获取方式

从Grain内部获取:

//根据特定的Key值创建或获取指定的Grain
IStudent student = GrainFactory.GetGrain<IStudent>(studentID);

从Client获取:

IStudent player = client.GetGrain<IStudent>(studentID);

应用

我们在项目中新增一个教室的概念,学生入学需要到教室先报个到才能分配到学号

1.修改 IStudent ,新增两个接口

        [...]
        /// <summary>
        /// 设置个人信息
        /// </summary>
        /// <param name="studentId">学号</param>
        /// <param name="studentName">姓名</param>
        /// <returns></returns>
        Task SetStudentInfo(int studentId, string studentName);

        /// <summary>
        /// 接收消息
        /// </summary>
        /// <param name="code">消息code类型</param>
        /// <param name="senderId">消息发送人id</param>
        /// <param name="message">消息内容</param>
        /// <returns></returns>
        Task ReceiveMessages(string code, object senderId, string message);
        [...]

2.修改 Student

        /// <summary> 学号 </summary>
        private int Id;
        /// <summary> 姓名 </summary>
        private string Name;

        [...]

        public Task SetStudentInfo(int studentId, string studentName)
        {
            Id = studentId;
            Name = studentName;
            return Task.CompletedTask;
        }

        public Task ReceiveMessages(string code, object senderId, string message)
        {
            switch (code)
            {
                case "加入新同学":
                    {
                        ConsoleHelper.WriteSuccessLine($"【{Name}】:欢迎新同学");
                        break;
                    }
                case "同学发言":
                    {
                        ConsoleHelper.WriteSuccessLine($"【{Name}】听到了学号为【{senderId}】的同学说的【{message}】");
                        break;
                    }
                default:
                    {
                        ConsoleHelper.WriteSuccessLine($"【{Name}】:我听不懂你们在说啥");
                        break;
                    }
            }
            return Task.CompletedTask;
        }
        [...]

3.在 IGrains 中新增 IClassroom

namespace IGrains
{
    /// <summary>
    /// 教室
    /// </summary>
    public interface IClassroom : Orleans.IGrainWithIntegerKey
    {
        /// <summary>
        /// 报名登记并拿到学号
        /// </summary>
        /// <param name="name">姓名</param>
        /// <returns></returns>
        Task<int> Enroll(string name);

        /// <summary>
        /// 学生入座
        /// </summary>
        /// <param name="student"></param>
        /// <returns></returns>
        Task<bool> Seated(IStudent student);

        /// <summary>
        /// 发言
        /// </summary>
        /// <param name="student">当前的学生</param>
        /// <param name="message">发言内容</param>
        /// <returns></returns>
        Task<bool> Speech(IStudent student, string message);
    }
}

4.在 Grains 中新增 Classroom

using IGrains;
using Orleans;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Grains
{
    /// <summary>
    /// 教室
    /// </summary>
    public class Classroom : Orleans.Grain, IClassroom
    {
        /// <summary> 教室内的学生 </summary>
        private List<IStudent> Students = new List<IStudent>();

        /// <summary>
        /// 报名登记并拿到学号
        /// </summary>
        /// <param name="name">姓名</param>
        /// <returns></returns>
        public async Task<int> Enroll(string name)
        {
            int studentID = Students.Count() + 1;
            var aaa = this.GetPrimaryKeyLong();
            IStudent student = GrainFactory.GetGrain<IStudent>(studentID);
            await student.SetStudentInfo(studentID, name);//等待一下
            Students.Add(student);
            return studentID;
        }

        /// <summary>
        /// 学生入座
        /// </summary>
        /// <param name="student"></param>
        /// <returns></returns>
        public Task<bool> Seated(IStudent student)
        {
            if (!Students.Contains(student))
            {
                return Task.FromResult(false);//没登记的学生不给坐
            }
            foreach (var item in Students)
            {
                if (item.GetPrimaryKeyLong() != student.GetPrimaryKeyLong())
                {
                    item.ReceiveMessages("加入新同学", this.GetPrimaryKeyLong(), $"学号{student.GetPrimaryKeyLong()}的童靴加入了我们,大家欢迎");//不等待
                }
            }
            return Task.FromResult(true);
        }

        /// <summary>
        /// 发言
        /// </summary>
        /// <param name="student">当前的学生</param>
        /// <param name="message">发言内容</param>
        public Task<bool> Speech(IStudent student, string message)
        {
            if (!Students.Contains(student))
            {
                return Task.FromResult(false);//没登记的学生闭嘴
            }
            foreach (var item in Students)
            {
                if (item.GetPrimaryKeyLong() != student.GetPrimaryKeyLong())
                {
                    item.ReceiveMessages("同学发言", (int)student.GetPrimaryKeyLong(), message);//不等待
                }
            }
            return Task.FromResult(true);
        }
    }
}

5.新增新的Orleans客户端项目,创建 asp.net core mvc 项目 Client_WebMVCApp

使用NuGet引用 Microsoft.Orleans.Client(3.0.2)

新增 OrleansService

namespace Client_WebMVCApp.Services
{
    public class OrleansService : IOrleansService
    {
        private readonly IClusterClient clusterClient;

        public OrleansService()
        {
            clusterClient = ConnectClient().Result;
        }

        public T GetGrain<T>(long integerKey) where T : IGrainWithIntegerKey
        {
            return clusterClient.GetGrain<T>(integerKey);
        }

        /// <summary>
        /// 使用本地配置连接服务
        /// </summary>
        /// <returns></returns>
        private async Task<IClusterClient> ConnectClient()
        {
            IClusterClient client;
            client = new ClientBuilder()
                .UseLocalhostClustering()           //配置客户端以连接到本地主机上的筒仓。
                .Configure<ClusterOptions>(options =>
                {
                    options.ClusterId = "dev";
                    options.ServiceId = "MyHost";
                })
                .Build();
            await client.Connect();
            return client;
        }
    }
}

然后修改 Startup ,把Orleans配置上去

        [...]
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews(); 
            services.AddTransient<OrleansService>();//注册一下Orleans
        }
        [...]

再修改 HomeController ,咱们来把上面注入的 OrleansService 使用起来

        [...]
        private readonly OrleansService _orleansService;
        private readonly IClassroom _classroom;

        public HomeController(ILogger<HomeController> logger, OrleansService orleansService)
        {
            _logger = logger;
            _orleansService = orleansService;
            _classroom = _orleansService.GetGrain<IClassroom>(0);
        }

        /// <summary>
        /// 报名拿学号
        /// </summary>
        /// <param name="name">学生姓名</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetStudentId(string name)
        {
            var studentId = await _classroom.Enroll(name);
            IStudent student = _orleansService.GetGrain<IStudent>(studentId);
            _classroom.Seated(student);//落座,不等待它
            //return Json(new { Success = true, Data = studentId, Message = "获取成功!" });
            return new JsonResult(new { Success = true, Data = studentId, Message = "获取成功!" });
        }
        [...]

6.运行起来

我们先把 Silo_ConsoleApp 跑起来

然后把 Client_WebMVCApp 跑起来,注意,这里我的端口用的是 4003,按照顺序请求如下接口:

http://localhost:4003/home/getstudentid?name=张三

http://localhost:4003/home/getstudentid?name=李四

http://localhost:4003/home/getstudentid?name=王二麻

我们能看到 Silo_ConsoleApp.exe 打印如下日志:

好了,大功告成。

张三、李四、王二麻三个人排着队报名入座,李四坐下的时候张三欢迎他,王二麻坐下的时候张三李四一起欢迎他,ojbk,完美

本文代码范例

GitHub仓库

便捷路由

目录Orleans[NET Core 3.1] 学习笔记(一).NET环境下的分布式应用程序

上一节Orleans[NET Core 3.1] 学习笔记(四)( 1 )创建项目

下一节Orleans[NET Core 3.1] 学习笔记(四)( 3 )监控Orleans Silo的方式 OrleansDashboard

posted @ 2020-01-16 16:03  爱上猫的红烧鱼  阅读(1796)  评论(4编辑  收藏  举报