SignalR.Orleans
奥尔良是用于构建可靠,可扩展分布式应用程序的跨平台框架。分布式应用程序定义为应用程序的应用程序,而不是一个过程,通常是使用点对点通信超出硬件边界的。奥尔良从单个本地服务器缩放到云中的数百到数千个分布式,高度可用的应用程序。请参阅GitHub上的Orleans源代码
ASP.NET Core Signalr是一个开源库,可以简化为应用程序添加实时Web功能。实时Web功能使服务器端代码可以立即将内容推向客户端。
SignalR.Orleans是一个赋予您两个能力的软件包:
- 将您的Orleans群集作为SignalR的背板。了解有关在多个服务器上扩展信号的信息。
正如您将在上面的链接中看到的那样,您可以将背板选择多种选择。如果您已经使用了奥尔良,那么您可能需要使用奥尔良作为背板来减少应用程序使用的依赖次数,并减少调用外部服务时所需的网络啤酒花(和延迟)的数量。
- 将来自Orleans谷物的消息发送给Signalr客户端。
如果您的应用程序的SignalR组件与Orleans共同主持(同一服务器,同一过程和
Microsoft.AspNetCore.SignalR.IHubContext可以注入Orleans的增益),则您已经具有此功能而无需安装此软件包。
但是,如果您的应用程序的SignalR组件与谷物“远程”,则此软件包将通过注入
SignalR.Orleans .Core.HubContext来使谷物一种向SignalR端发送消息的方式。
TODO:应独立提供这两种能力。不幸的是,在此阶段,仅当能力#1也使用时才能提供能力#2。
安装
安装是通过Nuget执行的。
具有7.xx版本的软件包与Orleans v7.xx及更高版本兼容。如果您仍在使用较早版本的Orleans,则需要使用较早版本的软件包。
软件包管理器:
PS> install-package SignalR.Orleans
.NET CLI:
#dotnet添加软件包SignalR.Orleans
Paket:
#paket添加SignalR.Orleans
版本7.0.0文档
向下滚动以查看早期版本的文档。
这是一个完整的入门示例,其中包含带有Signalr和Orleans的ASPNETCORE应用程序。
using Microsoft . AspNetCore . SignalR ; using Orleans . Hosting ; using SignalR . Orleans ; // Create a host that can cohost aspnetcore AND orleans together in a single process. var builder = WebApplication . CreateBuilder ( args ) ; builder . Host . UseOrleans ( siloBuilder => { siloBuilder . UseLocalhostClustering ( ) ; siloBuilder . UseSignalR ( ) ; // Adds ability #1 and #2 to Orleans. siloBuilder . RegisterHub < MyHub > ( ) ; // Required for each hub type if the backplane ability #1 is being used. } ) ; builder . Services . AddSignalR ( ) // Adds SignalR hubs to the web application . AddOrleans ( ) ; // Tells the SignalR hubs in the web application to use Orleans as a backplane (ability #1) var app = builder . Build ( ) ; app . MapHub < MyHub > ( "/myhub" ) ; await app . RunAsync ( ) ; // A SignalR Hub. https://learn.m*icr*osof*t.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-7.0 class MyHub : Hub { }
筒仓配置 - 谷物存储
SignalR.Orleans backplane(能力#1)使用引擎盖下的谷物,该晶粒使用存储来跟踪每个Signalr客户端的连接位置以及其所属的组。默认使用的存储是MemoryStorage 。
使用给定的存储名称常数来配置正确的存储提供商。
// **************************************************************************
// Use memory storage ONLY when your app is not clustered, otherwise you'll
// need to use proper external storage providers
// **************************************************************************
// Customize the storage used by the SignalR Orleans backplane grains.
siloBuilder . AddSomeOtherGrainStorage ( SignalROrleansConstants . SIGNALR_ORLEANS_STORAGE_PROVIDER ) ;
// THEN
siloBuilder . UseSignalR ( ) ;筒仓配置 - 流类型和流存储
SignalR.Orleans使用引擎盖下方的流来提供背板(能力#1)。默认流类型是MemoryStream 。给定的Orleans实例中的所有流都必须使用相同的存储提供商,名为PubSubStore ,当前默认为MemoryStorage 。
// FIRST customize the storage used by ALL stream providers in the entire Orleans host:
// Remember, memory storage won't work if you're using a cluster.
siloBuilder . AddSomeOtherGrainStorage ( "PubSubStore" ) ;
// THEN customize the type of stream used for the backplane, using the correct stream provider name
siloBuilder . AddPersistentStreams ( SignalROrleansConstants . SIGNALR_ORLEANS_STREAM_PROVIDER , adapterFactory , configureStream ) ;
// THEN
siloBuilder . UseSignalR ( ) ; 从奥尔良谷物发送消息
如果Signalr应用程序是如上所述的同置,则不需要此包即可从奥尔良谷物发送消息。只需将IHubContext注入谷物的构造函数,然后调用其发送消息的方法。在这里阅读更多有关它的信息。
但是,如果SignalR应用程序没有共同主治,并且使用Orleans作为背板,则可以使用此软件包使用Orleans中的背板流作为导管将消息发送给SignalR客户端(功能#2)。
class SampleGrain : Grain , ISampleGrain { private readonly SignalR . Orleans . Core . HubContext < MyHub > _hubContext ; public SampleGrain ( SignalR . Orleans . Core . HubContext < MyHub > hubContext ) { _hubContext = hubContext ; } public async Task SendMessageToClients ( ) { // Create an invocation message var msg = new InvocationMessage ( "method" , new object ? [ ] { 1 , 2 , 3 } ) . ToImmutable ( ) ; // Send a message to a single client await _hubContext . Client ( "someConnectionId" ) . Send ( msg ) ; // Send a message to a group await _hubContext . Group ( "someGroupName" ) . Send ( msg ) ; // Send a message to all connections made by a particular authenticated user await _hubContext . Group ( "someUserId" ) . Send ( msg ) ; // TODO: We have not implemented ability to send a message to ALL clients yet. } }
配置IClusterClient
如果您的SignalR应用程序与Orleans共同主持,它将自动从服务提供商中获取IClusterClient ,并连接到Orleans背板。
但是,如果没有共同主治,则必须给它一个IClusterClient即可使用:
using Microsoft . AspNetCore . SignalR ; using Orleans . Hosting ; using SignalR . Orleans ; // Create a web application that will connect to a remote Orleans cluster var builder = WebApplication . CreateBuilder ( args ) ; builder . Services // Adds an IClusterClient to the service provider. . AddOrleansClient ( clientBuilder => { // Tell the client how to connect to Orleans (you'll need to customize this for yourself) clientBuilder . UseLocalhostClustering ( ) ; // Tells the client how to connect to the SignalR.Orleans backplane. clientBuilder . UseSignalR ( configure : null ) ; } ) . AddSignalR ( ) // Adds SignalR hubs to the web application . AddOrleans ( ) ; // Tells SignalR to use Orleans as a backplane (ability #1) var app = builder . Build ( ) ; app . MapHub < MyHub > ( "/myhub" ) ; await app . RunAsync ( ) ; // A SignalR Hub. https://learn.m*icr*osof*t.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-7.0 class MyHub : Hub { }
这是版本> = 7.0.0的文档结束。以下是以前版本的较旧文档。
较早的版本文档
配置筒仓
我们需要使用以下内容配置Orleans筒仓:
- 在
ISiloHostBuilder上使用.UseSignalR()。 - 确保致电
RegisterHub其中() THub是要添加到倒数的集线器的类型。
例子
var silo = new SiloHostBuilder ( )
. UseSignalR ( )
. RegisterHub < MyHub > ( ) // You need to call this per `Hub` type.
. AddMemoryGrainStorage ( "PubSubStore" ) // You can use any other storage provider as long as you have one registered as "PubSubStore".
. Build ( ) ;
await silo . StartAsync ( ) ;配置筒仓存储提供商和谷物持久性
可选配置以覆盖两个提供商的默认实现,默认情况下将其设置为Memory 。
例子
. UseSignalR ( cfg =>
{
cfg . Configure ( ( builder , config ) =>
{
builder
. AddMemoryGrainStorage ( config . PubSubProvider )
. AddMemoryGrainStorage ( config . StorageProvider ) ;
} ) ;
} )
. RegisterHub < MyHub > ( ) 客户
现在,您的SignalR应用程序需要使用Orleans客户端连接到Orleans群集:
- 在
IClientBuilder上使用.UseSignalR()。
例子
var client = new ClientBuilder ( )
. UseSignalR ( )
// optional: .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IClientGrain).Assembly).WithReferences())
. Build ( ) ;
await client . Connect ( ) ;您的Startup.cs中的某个地方:
- 将
IClusterClient(在上面的示例中创建)中添加到IServiceCollection中。 - 在
IServiceCollection上使用.AddSignalR()(这是Microsoft.AspNetCore.SignalRNuget软件包的一部分)。 - 在
.AddSignalR()AddOrleans()()。
例子
public void ConfigureServices ( IServiceCollection services )
{
.. .
services
. AddSingleton < IClusterClient > ( client )
. AddSignalR ( )
. AddOrleans ( ) ;
.. .
}伟大的!现在,您已经配置了SignalR,并且Orleans Signalr Backplane内置了Orleans!
特征
集线器上下文
HubContext使您能够与来自Orleans Grains(集线器之外)的客户进行通信。
示例用法:接收服务器从消息经纪人,Web挂钩等中推送通知。理想情况下首先更新谷物状态,然后将Signalr消息推向客户端。
例子
public class UserNotificationGrain : Grain < UserNotificationState > , IUserNotificationGrain
{
private HubContext < IUserNotificationHub > _hubContext ;
public override async Task OnActivateAsync ( )
{
_hubContext = GrainFactory . GetHub < IUserNotificationHub > ( ) ;
// some code...
await _hubContext . User ( this . GetPrimaryKeyString ( ) ) . Send ( "Broadcast" , State . UserNotification ) ;
}
}完整的例子
协调ASPNETCORE网站和奥尔良
using Microsoft . AspNetCore . Builder ; using Microsoft . AspNetCore . Hosting ; using Microsoft . AspNetCore . ResponseCompression ; using Microsoft . Extensions . DependencyInjection ; using Microsoft . Extensions . Hosting ; using Orleans ; using Orleans . Hosting ; // Cohosting aspnetcore website and Orleans with signalR var host = Host . CreateDefaultBuilder ( args ) // Add the webhost with SignalR configured. . ConfigureWebHostDefaults ( webBuilder => { webBuilder . ConfigureServices ( ( webBuilderContext , services ) => { // Add response compression used by the SignalR hubs. services . AddResponseCompression ( opts => { opts . MimeTypes = ResponseCompressionDefaults . MimeTypes . Concat ( new [ ] { "application/octet-stream" } ) ; } ) ; // Adds SignalR hubs to the aspnetcore website services . AddSignalR ( options => { } ) . AddOrleans ( ) ; // Tells SignalR to use Orleans as the backplane. } ) ; webBuilder . Configure ( ( ctx , app ) => { // Adds response compression for use by the SignalR hubs app . UseResponseCompression ( ) ; // Map SignalR hub endpoints app . UseEndpoints ( endpoints => { endpoints . MapHub < MyHubType1 > ( "/hub1" ) ; // use your own hub types endpoints . MapHub < MyHubType2 > ( "/hub2" ) ; // use your own hub types // ... etc } ) ; } ) ; } ) // Add Orleans with SignalR configured . UseOrleans ( ( context , siloBuilder ) => { siloBuilder . UseSignalR ( signalRConfig => { // Optional. signalRConfig . UseFireAndForgetDelivery = true ; signalRConfig . Configure ( ( siloBuilder , signalRConstants ) => { // ************************************************************************** // Use memory storage ONLY when your app is not clustered, otherwise you'll // need to use proper external storage providers // ************************************************************************** siloBuilder . AddMemoryGrainStorage ( signalRConstants . StorageProvider ) ; // This wouldn't be be necessary if you already added "PubSubStore" elsewhere. siloBuilder . AddMemoryGrainStorage ( signalRConstants . PubSubProvider /*Same as "PubSubStore"*/ ) ; } ) ; } ) // Allows Orleans grains to inject IHubContext. RegisterHub < MyHubType1 > ( ) . RegisterHub < MyHubType2 > ( ) ; // ... etc } ) . UseConsoleLifetime ( ) . Build ( ) ; await host . StartAsync ( ) ; await host . WaitForShutdownAsync ( default ) ;
贡献
PR和反馈非常欢迎!
通过命令行克隆项目: