Unverified Commit 0d73b915 authored by Almouhannad Hafez's avatar Almouhannad Hafez Committed by GitHub

Merge pull request #13 from Almouhannad/B_Add-SignalR

B add signal r
parents 33ad80b5 0f2dd34b
......@@ -26,6 +26,7 @@
<ItemGroup>
<ProjectReference Include="..\Application\Application.csproj" />
<ProjectReference Include="..\Domain\Domain.csproj" />
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
<ProjectReference Include="..\Persistence\Persistence.csproj" />
<ProjectReference Include="..\Presentation\Presentation.csproj" />
</ItemGroup>
......
......@@ -3,6 +3,8 @@ using API.Options.JWT;
using API.SeedDatabaseHelper;
using Application.Behaviors;
using FluentValidation;
using Infrastructure.BackgroundServices.Notifications;
using Infrastructure.NotificationsService;
using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
......@@ -12,6 +14,10 @@ using Persistence.Context;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
#region Add Database context
// First, get database options
builder.Services.ConfigureOptions<DatabaseOptionsSetup>();
......@@ -35,7 +41,16 @@ builder.Services.AddDbContext<ClinicsDbContext>(
});
#endregion
// Add services to the container.
#region Add SignalR
builder.Services.AddSignalR();
// Background services:
builder.Services.AddHostedService<ServerTimeNotifier>();
#endregion
#region Add CORS
builder.Services.AddCors();
#endregion
#region Link interfaces implemented in persistence
// Using Scrutor library
......@@ -126,9 +141,17 @@ if (app.Environment.IsDevelopment())
app.UseHttpsRedirection();
#region Map notification HUB
app.MapHub<NotificationHub>("api/Notifications");
#endregion
#region CORS
// TODO: Configure allows
app.UseCors(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin());
app.UseCors(policy =>
policy
.AllowAnyHeader().AllowAnyMethod().AllowAnyHeader()
.AllowCredentials().SetIsOriginAllowed(origin => true));
#endregion
......
......@@ -19,7 +19,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Presentation", "Presentatio
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence", "Persistence\Persistence.csproj", "{2B5111ED-7AB8-46E2-90F8-AF0C70265618}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API", "API\API.csproj", "{15B2AA13-EBBD-408B-A4B3-4BAB43D74267}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "API", "API\API.csproj", "{15B2AA13-EBBD-408B-A4B3-4BAB43D74267}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure", "Infrastructure\Infrastructure.csproj", "{4EB41743-695F-4822-87F6-E6F9B48A8E6B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
......@@ -47,6 +49,10 @@ Global
{15B2AA13-EBBD-408B-A4B3-4BAB43D74267}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15B2AA13-EBBD-408B-A4B3-4BAB43D74267}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15B2AA13-EBBD-408B-A4B3-4BAB43D74267}.Release|Any CPU.Build.0 = Release|Any CPU
{4EB41743-695F-4822-87F6-E6F9B48A8E6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EB41743-695F-4822-87F6-E6F9B48A8E6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EB41743-695F-4822-87F6-E6F9B48A8E6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EB41743-695F-4822-87F6-E6F9B48A8E6B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......@@ -59,6 +65,7 @@ Global
{CE41FA28-76D7-4DC0-A980-B953F87253F5} = {6FC36DEB-2BC3-4980-B46B-7E518DAF09BF}
{D04C0D6C-3FC9-4359-A017-DFCFA1475639} = {878AE2C9-3E34-4332-ACC0-E6B601085710}
{2B5111ED-7AB8-46E2-90F8-AF0C70265618} = {FDA56BCD-A53D-4BA1-A59D-3F44FA32DDD7}
{4EB41743-695F-4822-87F6-E6F9B48A8E6B} = {FDA56BCD-A53D-4BA1-A59D-3F44FA32DDD7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E9FC9252-1283-485F-8F84-3574CFA12633}
......
using Infrastructure.NotificationsService;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Infrastructure.BackgroundServices.Notifications;
public class ServerTimeNotifier : BackgroundService
{
private static readonly TimeSpan Period = TimeSpan.FromSeconds(3);
#region CTOR DI
private readonly ILogger<ServerTimeNotifier> _logger;
private readonly IHubContext<NotificationHub, INotificationClient> _context;
public ServerTimeNotifier(ILogger<ServerTimeNotifier> logger, IHubContext<NotificationHub, INotificationClient> context)
{
_logger = logger;
_context = context;
}
#endregion
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using var timer = new PeriodicTimer(Period);
while (!stoppingToken.IsCancellationRequested &&
await timer.WaitForNextTickAsync(stoppingToken))
{
var dateTime = DateTime.Now;
_logger.LogInformation("Executing {Service} {Time}", nameof(ServerTimeNotifier), dateTime);
await _context.Clients.All.ReceiveNotification($"Server time = {dateTime}");
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.2" />
<PackageReference Include="MediatR" Version="12.4.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Scrutor" Version="4.2.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Application\Application.csproj" />
<ProjectReference Include="..\Domain\Domain.csproj" />
</ItemGroup>
</Project>
using Microsoft.AspNetCore.SignalR;
namespace Infrastructure.NotificationsService;
public class NotificationHub : Hub<INotificationClient>
{
public override async Task OnConnectedAsync()
{
await Clients.Client(Context.ConnectionId).ReceiveNotification(
$"Connected successfully { Context.User?.Identity?.Name}");
await base.OnConnectedAsync();
}
}
public interface INotificationClient
{
Task ReceiveNotification(string message);
}
\ No newline at end of file
......@@ -17,6 +17,7 @@
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@fortawesome/fontawesome-free": "^6.6.0",
"@microsoft/signalr": "^8.0.7",
"@ng-bootstrap/ng-bootstrap": "^17.0.0",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.2",
......@@ -3764,6 +3765,40 @@
"win32"
]
},
"node_modules/@microsoft/signalr": {
"version": "8.0.7",
"resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-8.0.7.tgz",
"integrity": "sha512-PHcdMv8v5hJlBkRHAuKG5trGViQEkPYee36LnJQx4xHOQ5LL4X0nEWIxOp5cCtZ7tu+30quz5V3k0b1YNuc6lw==",
"license": "MIT",
"dependencies": {
"abort-controller": "^3.0.0",
"eventsource": "^2.0.2",
"fetch-cookie": "^2.0.3",
"node-fetch": "^2.6.7",
"ws": "^7.4.5"
}
},
"node_modules/@microsoft/signalr/node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"license": "MIT",
"engines": {
"node": ">=8.3.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
......@@ -5115,6 +5150,18 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
"license": "MIT",
"dependencies": {
"event-target-shim": "^5.0.0"
},
"engines": {
"node": ">=6.5"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
......@@ -6942,7 +6989,6 @@
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
......@@ -6953,7 +6999,6 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
......@@ -7263,6 +7308,15 @@
"node": ">= 0.6"
}
},
"node_modules/event-target-shim": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
......@@ -7280,6 +7334,15 @@
"node": ">=0.8.x"
}
},
"node_modules/eventsource": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
"integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==",
"license": "MIT",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/execa": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
......@@ -7507,6 +7570,16 @@
"node": ">=0.8.0"
}
},
"node_modules/fetch-cookie": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-2.2.0.tgz",
"integrity": "sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ==",
"license": "Unlicense",
"dependencies": {
"set-cookie-parser": "^2.4.8",
"tough-cookie": "^4.0.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
......@@ -10413,6 +10486,26 @@
"dev": true,
"license": "MIT"
},
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-forge": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
......@@ -11571,6 +11664,12 @@
"license": "MIT",
"optional": true
},
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
"license": "MIT"
},
"node_modules/punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
......@@ -11604,6 +11703,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"license": "MIT"
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
......@@ -11812,7 +11917,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true,
"license": "MIT"
},
"node_modules/resolve": {
......@@ -12052,7 +12156,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"devOptional": true,
"license": "MIT"
},
"node_modules/sass": {
......@@ -12367,6 +12471,12 @@
"node": ">= 0.8.0"
}
},
"node_modules/set-cookie-parser": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz",
"integrity": "sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ==",
"license": "MIT"
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
......@@ -13232,6 +13342,45 @@
"node": ">=0.6"
}
},
"node_modules/tough-cookie": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
"license": "BSD-3-Clause",
"dependencies": {
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
},
"engines": {
"node": ">=6"
}
},
"node_modules/tough-cookie/node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/tough-cookie/node_modules/universalify": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"license": "MIT",
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
},
"node_modules/tree-dump": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz",
......@@ -13521,6 +13670,16 @@
"node": ">=6"
}
},
"node_modules/url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"license": "MIT",
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
......@@ -13686,6 +13845,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
"node_modules/webpack": {
"version": "5.92.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz",
......@@ -14044,6 +14209,16 @@
"node": ">=0.8.0"
}
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"license": "MIT",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
......
......@@ -19,6 +19,7 @@
"@angular/platform-browser-dynamic": "^18.1.0",
"@angular/router": "^18.1.0",
"@fortawesome/fontawesome-free": "^6.6.0",
"@microsoft/signalr": "^8.0.7",
"@ng-bootstrap/ng-bootstrap": "^17.0.0",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.2",
......
......@@ -5,6 +5,7 @@ import { RoleGuard } from './services/authentication/guards/role-guard';
import { Roles } from './classes/Authentication/roles';
import { ForbiddenComponent } from './components/errors/forbidden/forbidden.component';
import { NotFoundComponent } from './components/errors/not-found/not-found.component';
import { TestSignalRComponent } from './test-signal-r/test-signal-r.component';
const routes: Routes = [
{
......@@ -25,6 +26,16 @@ const routes: Routes = [
canActivate: [RoleGuard],
data: { role: Roles.NotRegistered }
},
// #region Testing SignalR
{
path: 'testing',
component: TestSignalRComponent,
canActivate: [RoleGuard],
data: { role: Roles.NotRegistered }
},
// #endregion
// Everything else
{
path: '**',
......
......@@ -18,6 +18,8 @@ import { AuthenticationService } from './services/authentication/authentication.
import { AuthenticationInterceptor } from './services/authentication/interceptor/authentication.interceptor';
import { ForbiddenComponent } from './components/errors/forbidden/forbidden.component';
import { NotFoundComponent } from './components/errors/not-found/not-found.component';
import { TestSignalRComponent } from './test-signal-r/test-signal-r.component';
import { SignalRService } from './notifications/signal-r.service';
@NgModule({
......@@ -39,6 +41,7 @@ import { NotFoundComponent } from './components/errors/not-found/not-found.compo
providers: [
AuthenticationService,
{ provide: HTTP_INTERCEPTORS, useClass: AuthenticationInterceptor, multi: true},
SignalRService
],
// components and directives that belong to this module
......@@ -52,7 +55,8 @@ import { NotFoundComponent } from './components/errors/not-found/not-found.compo
HomeComponent,
LoginFormComponent,
ForbiddenComponent,
NotFoundComponent
NotFoundComponent,
TestSignalRComponent
],
// identifies the root component that Angular should
......
import { Injectable } from '@angular/core';
import { HubConnectionBuilder } from '@microsoft/signalr';
import * as config from '../../../config'
@Injectable({
providedIn: 'root'
})
export class SignalRService {
constructor() { }
private readonly NOTIFICATIONS_ENDPOINT: string = `${config.apiUrl}/Notifications`
hubConnection: signalR.HubConnection;
startConnection(): void {
this.hubConnection = new HubConnectionBuilder()
.withUrl(this.NOTIFICATIONS_ENDPOINT)
.build();
this.hubConnection
.start()
.then(() => {
console.log('Connected to signalR!')
})
.catch(err => console.error('Error while starting connection: ' + err))
}
endConnection(): void {
if (this.hubConnection) {
this.hubConnection
.stop()
.then(() => {
console.log('disonnected from signalR!');
})
.catch(err => console.error('Error while stopping connection: ' + err));
} else {
console.log('No active connection to stop.');
}
}
}
\ No newline at end of file
<div>
<div class="text-center">
<h2>Notifications:</h2>
<h3>{{notification}}</h3>
<button (click)="onClick()" class="btn btn-outline-danger">Stop</button>
</div>
</div>
\ No newline at end of file
import { Component, OnInit } from '@angular/core';
import { SignalRService } from '../notifications/signal-r.service';
@Component({
selector: 'app-test-signal-r',
templateUrl: './test-signal-r.component.html',
styleUrls: ['./test-signal-r.component.css']
})
export class TestSignalRComponent implements OnInit {
notification: string = '';
constructor(private signalR: SignalRService){}
ngOnInit(): void {
this.signalR.startConnection();
this.signalR.hubConnection.on('ReceiveNotification', (message) => {
this.notification = message;
})
}
onClick(): void {
this.signalR.endConnection();
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment