mirror of https://github.com/abpframework/abp.git
30 changed files with 465 additions and 76 deletions
@ -0,0 +1,227 @@ |
|||||
|
# SignalR Integration |
||||
|
|
||||
|
> It is already possible to follow [the standard Microsoft tutorial](https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr) to add [SignalR](https://docs.microsoft.com/en-us/aspnet/core/signalr/introduction) to your application. However, ABP provides a SignalR integration packages that simplify the integration and usage. |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
### Server Side |
||||
|
|
||||
|
It is suggested to use the [ABP CLI](CLI.md) to install this package. |
||||
|
|
||||
|
#### Using the ABP CLI |
||||
|
|
||||
|
Open a command line window in the folder of your project (.csproj file) and type the following command: |
||||
|
|
||||
|
```bash |
||||
|
abp add-package Volo.Abp.AspNetCore.SignalR |
||||
|
``` |
||||
|
|
||||
|
> You typically want to add this package to the web or API layer of your application, depending on your architecture. |
||||
|
|
||||
|
#### Manual Installation |
||||
|
|
||||
|
If you want to manually install; |
||||
|
|
||||
|
1. Add the [Volo.Abp.AspNetCore.SignalR](https://www.nuget.org/packages/Volo.Abp.AspNetCore.SignalR) NuGet package to your project: |
||||
|
|
||||
|
``` |
||||
|
Install-Package Volo.Abp.BackgroundJobs.HangFire |
||||
|
``` |
||||
|
|
||||
|
Or use the Visual Studio NuGet package management UI to install it. |
||||
|
|
||||
|
2. Add the `AbpAspNetCoreSignalRModule` to the dependency list of your module: |
||||
|
|
||||
|
```csharp |
||||
|
[DependsOn( |
||||
|
//...other dependencies |
||||
|
typeof(AbpAspNetCoreSignalRModule) //Add the new module dependency |
||||
|
)] |
||||
|
public class YourModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
> You don't need to use the `services.AddSignalR()` and the `app.UseEndpoints(...)`, it's done by the `AbpAspNetCoreSignalRModule`. |
||||
|
|
||||
|
### Client Side |
||||
|
|
||||
|
Client side installation depends on your UI framework / client type. |
||||
|
|
||||
|
#### ASP.NET Core MVC / Razor Pages UI |
||||
|
|
||||
|
Run the following command in the root folder of your web project: |
||||
|
|
||||
|
````bash |
||||
|
yarn add @abp/signalr |
||||
|
```` |
||||
|
|
||||
|
> This requires to [install yarn](https://yarnpkg.com/) if you haven't install before. |
||||
|
|
||||
|
This will add the `@abp/signalr` to the dependencies in the `package.json` of your project: |
||||
|
|
||||
|
````json |
||||
|
{ |
||||
|
... |
||||
|
"dependencies": { |
||||
|
... |
||||
|
"@abp/signalr": "~2.7.0" |
||||
|
} |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
Run the `gulp` in the root folder of your web project: |
||||
|
|
||||
|
````bash |
||||
|
gulp |
||||
|
```` |
||||
|
|
||||
|
This will copy the SignalR JavaScript files into your project: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
Finally, add the following code to your page/view to include the `signalr.js` file |
||||
|
|
||||
|
````xml |
||||
|
@section scripts { |
||||
|
<abp-script type="typeof(SignalRBrowserScriptContributor)" /> |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
It requires to add `@using Volo.Abp.AspNetCore.Mvc.UI.Packages.SignalR` to your page/view. |
||||
|
|
||||
|
> You could add the `signalr.js` file in a standard way. But using the `SignalRBrowserScriptContributor` has additional benefits. See the [Client Side Package Management](UI/AspNetCore/Client-Side-Package-Management.md) and [Bundling & Minification](UI/AspNetCore/Bundling-Minification.md) documents for details. |
||||
|
|
||||
|
That's all. you can use the [SignalR JavaScript API](https://docs.microsoft.com/en-us/aspnet/core/signalr/javascript-client) in your page. |
||||
|
|
||||
|
#### Other UI Frameworks / Clients |
||||
|
|
||||
|
Please refer to [Microsoft's documentation](https://docs.microsoft.com/en-us/aspnet/core/signalr/introduction) for other type of clients. |
||||
|
|
||||
|
## The ABP Framework Integration |
||||
|
|
||||
|
This section covers the additional benefits when you use the ABP Framework integration packages. |
||||
|
|
||||
|
### Hub Route & Mapping |
||||
|
|
||||
|
ABP automatically registers all the hubs to the [dependency injection](Dependency-Injection.md) (as transient) and maps the hub endpoint. So, you don't have to use the ` app.UseEndpoints(...)` to map your hubs. Hub route (URL) is determined conventionally based on your hub name. |
||||
|
|
||||
|
Example: |
||||
|
|
||||
|
````csharp |
||||
|
public class MessagingHub : Hub |
||||
|
{ |
||||
|
//... |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
The hub route will be `/signalr-hubs/messasing` for the `MessasingHub`: |
||||
|
|
||||
|
* Adding a standard `/signalr-hubs/` prefix |
||||
|
* Continue with the **camel case** hub name, without the `Hub` suffix. |
||||
|
|
||||
|
If you want to specify the route, you can use the `HubRoute` attribute: |
||||
|
|
||||
|
````csharp |
||||
|
[HubRoute("/my-messasing-hub")] |
||||
|
public class MessagingHub : Hub |
||||
|
{ |
||||
|
//... |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
### AbpHub Base Classes |
||||
|
|
||||
|
Instead of the standard `Hub` and `Hub<T>` classes, you can inherit from the `AbpHub` or `AbpHub<T>` which hve useful base properties like `CurrentUser`. |
||||
|
|
||||
|
Example: |
||||
|
|
||||
|
````csharp |
||||
|
public class MessagingHub : AbpHub |
||||
|
{ |
||||
|
public async Task SendMessage(string targetUserName, string message) |
||||
|
{ |
||||
|
var currentUserName = CurrentUser.UserName; //Access to the current user info |
||||
|
var txt = L["MyText"]; //Localization |
||||
|
} |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
> While you could inject the same properties into your hub constructor, this way simplifies your hub class. |
||||
|
|
||||
|
### Manual Registration / Mapping |
||||
|
|
||||
|
ABP automatically registers all the hubs to the [dependency injection](Dependency-Injection.md) as a **transient service**. If you want to **disable auto dependency injection** registration for your hub class, just add a `DisableConventionalRegistration` attribute. You can still register your hub class to dependency injection in the `ConfigureServices` method of your module if you like: |
||||
|
|
||||
|
````csharp |
||||
|
context.Services.AddTransient<MessagingHub>(); |
||||
|
```` |
||||
|
|
||||
|
When **you or ABP** register the class to the dependency injection, it is automatically mapped to the endpoint route configuration just as described in the previous sections. You can use `DisableAutoHubMap` attribute if you want to manually map your hub class. |
||||
|
|
||||
|
For manual mapping, you have two options: |
||||
|
|
||||
|
1. Use the `AbpSignalROptions` to add your map configuration (in the `ConfigureServices` method of your [module](Module-Development-Basics.md)), so ABP still performs the endpoint mapping for your hub: |
||||
|
|
||||
|
````csharp |
||||
|
Configure<AbpSignalROptions>(options => |
||||
|
{ |
||||
|
options.Hubs.Add( |
||||
|
new HubConfig( |
||||
|
typeof(MessagingHub), //Hub type |
||||
|
"/my-messaging/route", //Hub route (URL) |
||||
|
hubOptions => |
||||
|
{ |
||||
|
//Additional options |
||||
|
hubOptions.LongPolling.PollTimeout = TimeSpan.FromSeconds(30); |
||||
|
} |
||||
|
) |
||||
|
); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
This is a good way to provide additional SignalR options. |
||||
|
|
||||
|
If you don't want to disable auto hub map, but still want to perform additional SignalR configuration, use the `options.Hubs.AddOrUpdate(...)` method: |
||||
|
|
||||
|
````csharp |
||||
|
Configure<AbpSignalROptions>(options => |
||||
|
{ |
||||
|
options.Hubs.AddOrUpdate( |
||||
|
typeof(MessagingHub), //Hub type |
||||
|
config => //Additional configuration |
||||
|
{ |
||||
|
config.RoutePattern = "/my-messaging-hub"; //override the default route |
||||
|
config.ConfigureActions.Add(hubOptions => |
||||
|
{ |
||||
|
//Additional options |
||||
|
hubOptions.LongPolling.PollTimeout = TimeSpan.FromSeconds(30); |
||||
|
}); |
||||
|
} |
||||
|
); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
This is the way you can modify the options of a hub class defined in a depended module (where you don't have the source code access). |
||||
|
|
||||
|
2. Change `app.UseConfiguredEndpoints` in the `OnApplicationInitialization` method of your [module](Module-Development-Basics.md) as shown below (added a lambda method as the parameter). |
||||
|
|
||||
|
````csharp |
||||
|
app.UseConfiguredEndpoints(endpoints => |
||||
|
{ |
||||
|
endpoints.MapHub<MessagingHub>("/my-messaging-hub", options => |
||||
|
{ |
||||
|
options.LongPolling.PollTimeout = TimeSpan.FromSeconds(30); |
||||
|
}); |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
### UserIdProvider |
||||
|
|
||||
|
ABP implements SignalR's `IUserIdProvider` interface to provide the current user id from the `ICurrentUser` service of the ABP framework (see [the current user service](CurrentUser.md)), so it will be integrated to the authentication system of your application. The implementing class is the `AbpSignalRUserIdProvider`, if you want to change/override it. |
||||
|
|
||||
|
## Example Application |
||||
|
|
||||
|
See the [SignalR Integration Demo](https://github.com/abpframework/abp-samples/tree/master/SignalRDemo) as a sample application. It has a simple Chat page to send messages between (authenticated) users. |
||||
|
|
||||
|
 |
||||
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 45 KiB |
@ -1,14 +1,12 @@ |
|||||
using System.Collections.Generic; |
namespace Volo.Abp.AspNetCore.SignalR |
||||
|
|
||||
namespace Volo.Abp.AspNetCore.SignalR |
|
||||
{ |
{ |
||||
public class AbpSignalROptions |
public class AbpSignalROptions |
||||
{ |
{ |
||||
public List<HubConfig> Hubs { get; } |
public HubConfigList Hubs { get; } |
||||
|
|
||||
public AbpSignalROptions() |
public AbpSignalROptions() |
||||
{ |
{ |
||||
Hubs = new List<HubConfig>(); |
Hubs = new HubConfigList(); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.SignalR |
||||
|
{ |
||||
|
public class DisableAutoHubMapAttribute : Attribute |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.SignalR |
||||
|
{ |
||||
|
public class HubConfigList : List<HubConfig> |
||||
|
{ |
||||
|
public void AddOrUpdate<THub>(Action<HubConfig> configAction = null) |
||||
|
{ |
||||
|
AddOrUpdate(typeof(THub)); |
||||
|
} |
||||
|
|
||||
|
public void AddOrUpdate(Type hubType, Action<HubConfig> configAction = null) |
||||
|
{ |
||||
|
var hubConfig = this.GetOrAdd( |
||||
|
c => c.HubType == hubType, |
||||
|
() => HubConfig.Create(hubType) |
||||
|
); |
||||
|
|
||||
|
configAction?.Invoke(hubConfig); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +0,0 @@ |
|||||
$(function () { |
|
||||
var links = $("a.page-link"); |
|
||||
|
|
||||
$.each(links, function (key, value) { |
|
||||
var oldUrl = links[key].getAttribute("href"); |
|
||||
var value = Number(oldUrl.match(/currentPage=(\d+)&page/)[1]); |
|
||||
links[key].setAttribute("href", "/Components/Paginator?currentPage=" + value); |
|
||||
}) |
|
||||
}); |
|
||||
@ -0,0 +1,20 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.test.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netcoreapp3.1</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.AspNetCore.SignalR\Volo.Abp.AspNetCore.SignalR.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
||||
|
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp.Testing; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.SignalR |
||||
|
{ |
||||
|
public abstract class AbpAspNetCoreSignalRTestBase : AbpIntegratedTest<AbpAspNetCoreSignalRTestModule> |
||||
|
{ |
||||
|
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
|
{ |
||||
|
options.UseAutofac(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.SignalR |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAspNetCoreSignalRModule), |
||||
|
typeof(AbpTestBaseModule), |
||||
|
typeof(AbpAutofacModule) |
||||
|
)] |
||||
|
public class AbpAspNetCoreSignalRTestModule : AbpModule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using Microsoft.Extensions.Options; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.AspNetCore.SignalR.SampleHubs; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.SignalR |
||||
|
{ |
||||
|
public class AbpSignalROptions_Tests : AbpAspNetCoreSignalRTestBase |
||||
|
{ |
||||
|
private readonly AbpSignalROptions _options; |
||||
|
|
||||
|
public AbpSignalROptions_Tests() |
||||
|
{ |
||||
|
_options = GetRequiredService<IOptions<AbpSignalROptions>>().Value; |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Auto_Add_Maps() |
||||
|
{ |
||||
|
_options.Hubs.ShouldContain(h => h.HubType == typeof(RegularHub)); |
||||
|
_options.Hubs.ShouldContain(h => h.HubType == typeof(RegularAbpHub)); |
||||
|
_options.Hubs.ShouldNotContain(h => h.HubType == typeof(DisableConventionalRegistrationHub)); |
||||
|
_options.Hubs.ShouldNotContain(h => h.HubType == typeof(DisableAutoHubMapHub)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,10 @@ |
|||||
|
using Microsoft.AspNetCore.SignalR; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.SignalR.SampleHubs |
||||
|
{ |
||||
|
[DisableAutoHubMap] |
||||
|
public class DisableAutoHubMapHub : Hub |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Microsoft.AspNetCore.SignalR; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.SignalR.SampleHubs |
||||
|
{ |
||||
|
[DisableConventionalRegistration] |
||||
|
public class DisableConventionalRegistrationHub : Hub |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.SignalR.SampleHubs |
||||
|
{ |
||||
|
public class RegularAbpHub : AbpHub |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using Microsoft.AspNetCore.SignalR; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.SignalR.SampleHubs |
||||
|
{ |
||||
|
public class RegularHub : Hub |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue