教程1—— 创建一个极小的Orleans应用程序
本教程提供了有关创建基本功能的Orleans应用程序的分步说明。它被设计为自包含且极尽简约,具有以下特征:
- 它仅依赖于NuGet包
- 它已在使用Orleans 2.2.0的Visual Studio 2017中进行了测试
- 它不依赖于外部存储
请记住,这只是一个教程,缺少适当的错误处理和其他对生产环境有用的好东西。但是,它应该有助于读者真实地了解Orleans的结构,并将重点放在与他们最相关的部分上。
项目设置
在本教程中,我们将创建4个项目:
- 包含grain接口的库
- 包含grain类的库
- 一个控制台应用程序,作为Silo的宿主
- 一个控制台应用程序,作为Client的宿主
完成本教程后,完整的解决方案应如下所示:
在Visual Studio中创建结构
注意:您可以在C#中使用每个项目的默认项目类型。您将使用为每个项目指定的代码(如下),替换默认代码。您可能还需要添加using
语句。
- 首先在新解决方案中创建一个控制台应用程序(.NET Core)项目。将此项目命名为
Silo
,并将解决方案命名为OrleansHelloWorld
。 - 添加另一个控制台应用程序(.NET Core)项目并命名为
Client
。 - 添加类库(.NET Standard)并命名为
GrainInterfaces
。 - 添加另一个类库(.NET Standard)并命名为
Grains
。
删除默认源文件
- 从Grains中删除Class1.cs
- 从GrainInterfaces中删除Class1.cs
添加引用
Grains
参考GrainInterfaces
。Silo
参考GrainInterfaces
和Grains
。Client
参考GrainInterfaces
。
添加Orleans NuGet包
- 对于Silo项目,添加
Microsoft.Orleans.Server
NuGet包。 - 在Client项目中,添加
Microsoft.Orleans.Client
NuGet包。 - 对GrainInterfaces和Grains项目,添加
Microsoft.Orleans.Core.Abstractions
包和Microsoft.Orleans.CodeGenerator.MSBuild
包。 - 在Grains项目中,添加
Microsoft.Extensions.Logging.Abstractions
用于记录的包。 - 对于Client和Silo项目,添加
Microsoft.Extensions.Logging.Console
,以便他们可以在其控制台窗口中打印日志。
Microsoft.Orleans.Server和
Microsoft.Orleans.Client
是元数据包,它们会在Silo和Client端,带来您最有可能需要的依赖。
Microsoft.Orleans.Core.Abstractions
到处都需要。它包括在Microsoft.Orleans.Server
和Microsoft.Orleans.Client
。
Microsoft.Orleans.CodeGenerator.MSBuild
自动生成调用grain越过机器边界所需的代码。所以在GrainInterfaces
和Grains
项目中需要它它。
定义grain interface
在GrainInterfaces项目中,添加一个IHello.cs
代码文件并在其中定义以下IHello接口:
using System.Threading.Tasks;
namespace OrleansBasics
{
public interface IHello : Orleans.IGrainWithIntegerKey
{
Task<string> SayHello(string greeting);
}
}
定义grain类
在Grains项目中,添加一个HelloGrain.cs
代码文件,并在其中定义以下类:
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace OrleansBasics
{
public class HelloGrain : Orleans.Grain, IHello
{
private readonly ILogger logger;
public HelloGrain(ILogger<HelloGrain> logger)
{
this.logger = logger;
}
Task<string> IHello.SayHello(string greeting)
{
logger.LogInformation($"\n SayHello message received: greeting = '{greeting}'");
return Task.FromResult($"\n Client said: '{greeting}', so HelloGrain says: Hello!");
}
}
}
创建Silo - Program.cs
在这一步中,我们添加代码来初始化将承载和运行我们的grain的服务器 —— 一个silo。我们将在这里使用开发集群提供程序,以便我们可以在本地运行所有内容,而不依赖于外部存储系统。您可以在Orleans文档的“ 本地开发配置”页面中找到更多关于这一点的信息。我们将运行一个包含单个silo的集群。
将以下代码添加到Silo项目的Program.cs中:
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Orleans;
using Orleans.Configuration;
using Orleans.Hosting;
namespace OrleansBasics
{
public class Program
{
public static int Main(string[] args)
{
return RunMainAsync().Result;
}
private static async Task<int> RunMainAsync()
{
try
{
var host = await StartSilo();
Console.WriteLine("\n\n Press Enter to terminate...\n\n");
Console.ReadLine();
await host.StopAsync();
return 0;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return 1;
}
}
private static async Task<ISiloHost> StartSilo()
{
// define the cluster configuration
var builder = new SiloHostBuilder()
.UseLocalhostClustering()
.Configure<ClusterOptions>(options =>
{
options.ClusterId = "dev";
options.ServiceId = "OrleansBasics";
})
.ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(HelloGrain).Assembly).WithReferences())
.ConfigureLogging(logging => logging.AddConsole());
var host = builder.Build();
await host.StartAsync();
return host;
}
}
}
创建Client - Program.cs
最后,我们需要配置一个Client来与我们的grain进行通信,将它连接到集群(其中有一个silo),然后调用grain。请注意,集群配置必须与我们用于silo的配置相匹配。在Orleans文档的Clusters and Clients部分中有关于客户端的更多信息。
using Microsoft.Extensions.Logging;
using Orleans;
using Orleans.Configuration;
using System;
using System.Threading.Tasks;
namespace OrleansBasics
{
public class Program
{
static int Main(string[] args)
{
return RunMainAsync().Result;
}
private static async Task<int> RunMainAsync()
{
try
{
using (var client = await ConnectClient())
{
await DoClientWork(client);
Console.ReadKey();
}
return 0;
}
catch (Exception e)
{
Console.WriteLine($"\nException while trying to run client: {e.Message}");
Console.WriteLine("Make sure the silo the client is trying to connect to is running.");
Console.WriteLine("\nPress any key to exit.");
Console.ReadKey();
return 1;
}
}
private static async Task<IClusterClient> ConnectClient()
{
IClusterClient client;
client = new ClientBuilder()
.UseLocalhostClustering()
.Configure<ClusterOptions>(options =>
{
options.ClusterId = "dev";
options.ServiceId = "OrleansBasics";
})
.ConfigureLogging(logging => logging.AddConsole())
.Build();
await client.Connect();
Console.WriteLine("Client successfully connected to silo host \n");
return client;
}
private static async Task DoClientWork(IClusterClient client)
{
// example of calling grains from the initialized client
var friend = client.GetGrain<IHello>(0);
var response = await friend.SayHello("Good morning, HelloGrain!");
Console.WriteLine("\n\n{0}\n\n", response);
}
}
}
运行该应用程序
构建解决方案并运行Silo。在收到Silo正在运行的确认消息后(“按Enter键终止...”),运行客户端。成功看起来像这样: