├── .gitignore
├── 1.Websockets
├── CustomServer
│ ├── CustomServer.csproj
│ └── Program.cs
├── Websockets.sln
└── Websockets
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── Startup.cs
│ ├── Websockets.csproj
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ └── index.html
├── 2.SSE_and_LP
├── LongPolling
│ ├── LongPolling.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ │ └── index.html
├── ServerSentEvents.sln
└── ServerSentEvents
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── ServerSentEvents.csproj
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ └── index.html
├── 3.FeatureOverview
├── FeatureOverview.sln
└── FeatureOverview
│ ├── CustomHub.cs
│ ├── Data.cs
│ ├── FeatureOverview.csproj
│ ├── GroupsHub.cs
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── Startup.cs
│ ├── TestController.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ ├── groups.html
│ ├── index.html
│ ├── signalr.js
│ ├── signalr.js.map
│ ├── signalr.min.js
│ └── signalr.min.js.map
├── 4.StreamingData
├── StreamingData.sln
├── StreamingData_7
│ ├── Data.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Startup.cs
│ ├── StreamingData_7.csproj
│ ├── StreamingHub.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ │ ├── index.html
│ │ ├── signalr.js
│ │ ├── signalr.js.map
│ │ ├── signalr.min.js
│ │ └── signalr.min.js.map
├── StreamingData_8
│ ├── Data.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Startup.cs
│ ├── StreamingData_8.csproj
│ ├── StreamingHub.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ │ ├── index.html
│ │ ├── signalr.js
│ │ ├── signalr.js.map
│ │ ├── signalr.min.js
│ │ └── signalr.min.js.map
└── global.json
├── 5.Authentication
├── Authentication.sln
├── Authentication
│ ├── Authentication.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── ProtectedHub.cs
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ │ ├── index.html
│ │ ├── signalr.js
│ │ ├── signalr.js.map
│ │ ├── signalr.min.js
│ │ └── signalr.min.js.map
└── AuthenticationExpiry
│ ├── AuthHubFilter.cs
│ ├── AuthenticationExpiry.csproj
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── ProtectedHub.cs
│ ├── Startup.cs
│ └── wwwroot
│ ├── index.html
│ ├── signalr.js
│ ├── signalr.js.map
│ ├── signalr.min.js
│ └── signalr.min.js.map
├── 6.Recepies
├── ChatApp
│ ├── ChatApp.csproj
│ ├── ChatHub.cs
│ ├── ChatRegistry.cs
│ ├── DefaultController.cs
│ ├── Models.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Startup.cs
│ ├── UserIdProvider.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ │ ├── index.html
│ │ ├── signalr.js
│ │ ├── signalr.js.map
│ │ ├── signalr.min.js
│ │ └── signalr.min.js.map
├── Collaboration
│ ├── AuthenticationHandler.cs
│ ├── Collaboration.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── SquareHub.cs
│ ├── Startup.cs
│ ├── State.cs
│ ├── UserIdProvider.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ │ ├── bad_v_good.png
│ │ ├── index.html
│ │ ├── signalr.js
│ │ ├── signalr.js.map
│ │ ├── signalr.min.js
│ │ └── signalr.min.js.map
├── DrawingGame
│ ├── AuthenticationHandler.cs
│ ├── DrawingGame.csproj
│ ├── GameHub.cs
│ ├── HttpContextExtensions.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── RoomController.cs
│ ├── RoomManager.cs
│ ├── RoomView.cs
│ ├── Startup.cs
│ ├── UserIdProvider.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── vue-client
│ │ ├── .gitignore
│ │ ├── .vscode
│ │ └── extensions.json
│ │ ├── README.md
│ │ ├── gameConnection.js
│ │ ├── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── public
│ │ └── favicon.ico
│ │ ├── src
│ │ ├── App.vue
│ │ ├── Canvas.vue
│ │ ├── Rooms.vue
│ │ ├── ToolBar.vue
│ │ └── main.js
│ │ └── vite.config.js
├── Notifications
│ ├── AuthenticationHandler.cs
│ ├── DefaultController.cs
│ ├── NotificationHub.cs
│ ├── NotificationService.cs
│ ├── Notifications.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Startup.cs
│ ├── UserIdProvider.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── redis_pub_sub.linq
│ └── wwwroot
│ │ ├── index.html
│ │ ├── signalr.js
│ │ ├── signalr.js.map
│ │ ├── signalr.min.js
│ │ └── signalr.min.js.map
├── Recepies.sln
└── VideoStreaming
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── Startup.cs
│ ├── StreamHub.cs
│ ├── VideoStreaming.csproj
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ ├── fetch.html
│ ├── file.html
│ ├── live.html
│ ├── signalr.js
│ ├── signalr.js.map
│ ├── signalr.min.js
│ ├── signalr.min.js.map
│ ├── source.html
│ ├── vid0.webm
│ ├── vid1.webm
│ └── vid2.webm
├── 7.CustomClient
├── CustomClient.sln
└── CustomClient
│ ├── CustomClient.csproj
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── python_client
│ ├── README.md
│ ├── main.py
│ └── requirements.txt
└── global.json
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | obj
3 | .vs
4 | .idea
--------------------------------------------------------------------------------
/1.Websockets/CustomServer/CustomServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net5.0
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/1.Websockets/CustomServer/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Net;
4 | using System.Net.Sockets;
5 | using System.Text;
6 | using System.Text.RegularExpressions;
7 | using System.Threading.Tasks;
8 |
9 | namespace CustomServer
10 | {
11 | class Program
12 | {
13 | // https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers
14 | static async Task Main(string[] args)
15 | {
16 | var ip = new IPEndPoint(IPAddress.Loopback, 5000);
17 | var listenSocket = new Socket(SocketType.Stream, ProtocolType.Tcp);
18 | listenSocket.Bind(ip);
19 | listenSocket.Listen();
20 | const string EOL = "\r\n";
21 |
22 | while (true)
23 | {
24 | var socket = await listenSocket.AcceptAsync();
25 | var stream = new NetworkStream(socket);
26 | var buffer = new byte[1024];
27 |
28 | while (true)
29 | {
30 | var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
31 |
32 | var data = Encoding.UTF8.GetString(buffer[..bytesRead]);
33 | if (data.StartsWith("GET"))
34 | {
35 | // handshake https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#the_websocket_handshake
36 | Console.WriteLine(data);
37 | var key = new Regex("Sec-WebSocket-Key: (.*)").Match(data).Groups[1].Value;
38 | var acceptWebsocket = Convert.ToBase64String(System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(key.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")));
39 |
40 | var responseMessage = "HTTP/1.1 101 Switching Protocols"
41 | + EOL + "Connection: Upgrade"
42 | + EOL + "Upgrade: websocket"
43 | + EOL + "Sec-WebSocket-Accept: " + acceptWebsocket
44 | + EOL + EOL;
45 |
46 | var response = Encoding.UTF8.GetBytes(responseMessage);
47 | await stream.WriteAsync(response, 0, response.Length);
48 | stream.Flush();
49 | }
50 | else
51 | {
52 | // https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#format
53 | // Only for small messages, < 126 bytes
54 |
55 | // var length = buffer[1] - 0b10000000;
56 | var length = buffer[1] - 0x80;
57 | var key = buffer[2..6];
58 | var wsData = new byte[length];
59 |
60 | for (int i = 0; i < length; i++)
61 | {
62 | var offset = 6 + i;
63 | wsData[i] = (byte)(buffer[offset] ^ key[i % 4]);
64 | }
65 |
66 | var text = Encoding.UTF8.GetString(wsData);
67 | Console.WriteLine("{0}", text);
68 | }
69 | }
70 | }
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/1.Websockets/Websockets.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Websockets", "Websockets\Websockets.csproj", "{7FF9F4A0-B2E8-44E8-8DCC-36DABF0CF8B4}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomServer", "CustomServer\CustomServer.csproj", "{724F1D50-9EF8-4C4F-BB11-7AA2302D0FA2}"
6 | EndProject
7 | Global
8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
9 | Debug|Any CPU = Debug|Any CPU
10 | Release|Any CPU = Release|Any CPU
11 | EndGlobalSection
12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
13 | {7FF9F4A0-B2E8-44E8-8DCC-36DABF0CF8B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14 | {7FF9F4A0-B2E8-44E8-8DCC-36DABF0CF8B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
15 | {7FF9F4A0-B2E8-44E8-8DCC-36DABF0CF8B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
16 | {7FF9F4A0-B2E8-44E8-8DCC-36DABF0CF8B4}.Release|Any CPU.Build.0 = Release|Any CPU
17 | {724F1D50-9EF8-4C4F-BB11-7AA2302D0FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18 | {724F1D50-9EF8-4C4F-BB11-7AA2302D0FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
19 | {724F1D50-9EF8-4C4F-BB11-7AA2302D0FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
20 | {724F1D50-9EF8-4C4F-BB11-7AA2302D0FA2}.Release|Any CPU.Build.0 = Release|Any CPU
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/1.Websockets/Websockets/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace Websockets
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IHostBuilder CreateHostBuilder(string[] args) =>
14 | Host.CreateDefaultBuilder(args)
15 | .ConfigureWebHostDefaults(webBuilder =>
16 | {
17 | webBuilder.UseStartup();
18 | });
19 | }
20 | }
--------------------------------------------------------------------------------
/1.Websockets/Websockets/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:42077",
8 | "sslPort": 44363
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "swagger",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "SignalRWebsockets": {
21 | "commandName": "Project",
22 | "dotnetRunMessages": "true",
23 | "launchBrowser": true,
24 | "launchUrl": "swagger",
25 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
26 | "environmentVariables": {
27 | "ASPNETCORE_ENVIRONMENT": "Development"
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/1.Websockets/Websockets/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net.WebSockets;
4 | using System.Text;
5 | using System.Threading;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Microsoft.Extensions.Hosting;
10 |
11 | namespace Websockets
12 | {
13 | public class Startup
14 | {
15 | private readonly List _connections = new();
16 |
17 | public void ConfigureServices(IServiceCollection services)
18 | {
19 |
20 | }
21 |
22 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
23 | {
24 | if (env.IsDevelopment())
25 | {
26 | app.UseDeveloperExceptionPage();
27 | }
28 |
29 | app.UseStaticFiles();
30 |
31 | app.UseRouting();
32 |
33 | app.UseWebSockets(new() {KeepAliveInterval = TimeSpan.FromSeconds(30)});
34 |
35 | app.UseEndpoints(endpoints =>
36 | {
37 | endpoints.Map("/ws", async ctx =>
38 | {
39 | var buffer = new byte[1024 * 4];
40 | var webSocket = await ctx.WebSockets.AcceptWebSocketAsync();
41 | _connections.Add(webSocket);
42 |
43 | var result = await webSocket.ReceiveAsync(new(buffer), CancellationToken.None);
44 | int i = 0;
45 | while (!result.CloseStatus.HasValue)
46 | {
47 | var message = Encoding.UTF8.GetBytes($"message index {i++}");
48 | foreach (var c in _connections)
49 | {
50 | await c.SendAsync(new(message, 0, message.Length), result.MessageType, result.EndOfMessage, CancellationToken.None);
51 | }
52 |
53 | result = await webSocket.ReceiveAsync(new(buffer), CancellationToken.None);
54 |
55 | Console.WriteLine($"Received: {Encoding.UTF8.GetString(buffer[..result.Count])}");
56 | }
57 |
58 | await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
59 | _connections.Remove(webSocket);
60 | });
61 | });
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/1.Websockets/Websockets/Websockets.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | Websockets
6 | Websockets
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/1.Websockets/Websockets/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/1.Websockets/Websockets/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/1.Websockets/Websockets/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
25 |
26 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/LongPolling/LongPolling.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/LongPolling/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace LongPolling
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
--------------------------------------------------------------------------------
/2.SSE_and_LP/LongPolling/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:29405",
7 | "sslPort": 44343
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "LongPolling": {
19 | "commandName": "Project",
20 | "dotnetRunMessages": "true",
21 | "launchBrowser": true,
22 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/LongPolling/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Channels;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.AspNetCore.Http;
9 | using Microsoft.AspNetCore.Http.Connections;
10 | using Microsoft.AspNetCore.SignalR;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Hosting;
13 |
14 | namespace LongPolling
15 | {
16 | public class Startup
17 | {
18 | private readonly Channel _channel;
19 |
20 | public Startup()
21 | {
22 | _channel = Channel.CreateUnbounded();
23 | // Task.Run(async () =>
24 | // {
25 | // int i = 0;
26 | // while (true)
27 | // {
28 | // await _channel.Writer.WriteAsync($"data: {i++}");
29 | // await Task.Delay(5000);
30 | // }
31 | // });
32 | }
33 |
34 | public void ConfigureServices(IServiceCollection services)
35 | {
36 | }
37 |
38 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
39 | {
40 | if (env.IsDevelopment())
41 | {
42 | app.UseDeveloperExceptionPage();
43 | }
44 |
45 | app.UseStaticFiles();
46 |
47 | app.UseRouting();
48 |
49 | app.UseEndpoints(endpoints =>
50 | {
51 | endpoints.Map("/listen", async ctx =>
52 | {
53 | if (await _channel.Reader.WaitToReadAsync())
54 | {
55 | if (_channel.Reader.TryRead(out var data))
56 | {
57 | ctx.Response.StatusCode = 200;
58 | await ctx.Response.WriteAsync(data);
59 | return;
60 | }
61 | }
62 |
63 | ctx.Response.StatusCode = 200;
64 | });
65 |
66 | endpoints.Map("/send", async ctx =>
67 | {
68 | if (ctx.Request.Query.TryGetValue("m", out var m))
69 | {
70 | Console.WriteLine("message to send: " + m);
71 | await _channel.Writer.WriteAsync(m);
72 | }
73 |
74 | ctx.Response.StatusCode = 200;
75 | });
76 | });
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/2.SSE_and_LP/LongPolling/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/LongPolling/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/LongPolling/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
23 |
24 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/ServerSentEvents.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerSentEvents", "ServerSentEvents\ServerSentEvents.csproj", "{1014F863-2B59-4E3A-9945-73D4F878597C}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LongPolling", "LongPolling\LongPolling.csproj", "{DA3534D6-5EB3-4EC9-9F0B-3C8A965BE8A0}"
6 | EndProject
7 | Global
8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
9 | Debug|Any CPU = Debug|Any CPU
10 | Release|Any CPU = Release|Any CPU
11 | EndGlobalSection
12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
13 | {1014F863-2B59-4E3A-9945-73D4F878597C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14 | {1014F863-2B59-4E3A-9945-73D4F878597C}.Debug|Any CPU.Build.0 = Debug|Any CPU
15 | {1014F863-2B59-4E3A-9945-73D4F878597C}.Release|Any CPU.ActiveCfg = Release|Any CPU
16 | {1014F863-2B59-4E3A-9945-73D4F878597C}.Release|Any CPU.Build.0 = Release|Any CPU
17 | {DA3534D6-5EB3-4EC9-9F0B-3C8A965BE8A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18 | {DA3534D6-5EB3-4EC9-9F0B-3C8A965BE8A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
19 | {DA3534D6-5EB3-4EC9-9F0B-3C8A965BE8A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
20 | {DA3534D6-5EB3-4EC9-9F0B-3C8A965BE8A0}.Release|Any CPU.Build.0 = Release|Any CPU
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/ServerSentEvents/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace ServerSentEvents
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
--------------------------------------------------------------------------------
/2.SSE_and_LP/ServerSentEvents/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:32636",
8 | "sslPort": 44384
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "swagger",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "ServerSentEvents": {
21 | "commandName": "Project",
22 | "dotnetRunMessages": "true",
23 | "launchBrowser": true,
24 | "launchUrl": "swagger",
25 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
26 | "environmentVariables": {
27 | "ASPNETCORE_ENVIRONMENT": "Development"
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/ServerSentEvents/ServerSentEvents.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/ServerSentEvents/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Channels;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.AspNetCore.Http;
9 | using Microsoft.AspNetCore.HttpsPolicy;
10 | using Microsoft.AspNetCore.Mvc;
11 | using Microsoft.Extensions.Configuration;
12 | using Microsoft.Extensions.DependencyInjection;
13 | using Microsoft.Extensions.Hosting;
14 | using Microsoft.Extensions.Logging;
15 | using Microsoft.OpenApi.Models;
16 |
17 | namespace ServerSentEvents
18 | {
19 | public class Startup
20 | {
21 | private readonly Channel _channel;
22 |
23 | public Startup()
24 | {
25 | _channel = Channel.CreateUnbounded();
26 | }
27 |
28 | public void ConfigureServices(IServiceCollection services)
29 | {
30 | }
31 |
32 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
33 | {
34 | if (env.IsDevelopment())
35 | {
36 | app.UseDeveloperExceptionPage();
37 | }
38 |
39 | app.UseStaticFiles();
40 |
41 | app.UseRouting();
42 |
43 | app.UseEndpoints(endpoints =>
44 | {
45 | endpoints.Map("/send", async ctx =>
46 | {
47 | if (ctx.Request.Query.TryGetValue("m", out var m))
48 | {
49 | Console.WriteLine("message to send: " + m);
50 | await _channel.Writer.WriteAsync(m);
51 | }
52 |
53 | ctx.Response.StatusCode = 200;
54 | });
55 | });
56 |
57 | app.Use(async (ctx, next) =>
58 | {
59 | if (ctx.Request.Path.ToString().Equals("/sse"))
60 | {
61 | var response = ctx.Response;
62 | response.Headers.Add("Content-Type", "text/event-stream");
63 |
64 | await response.WriteAsync("event: custom\r");
65 | await response.WriteAsync("data: custom event data\r\r");
66 | await response.Body.FlushAsync();
67 |
68 | while (await _channel.Reader.WaitToReadAsync())
69 | {
70 | var message = await _channel.Reader.ReadAsync();
71 | Console.WriteLine("sending message: " + message);
72 | await response.WriteAsync($"data: {message}\r\r");
73 |
74 | await response.Body.FlushAsync();
75 | }
76 | }
77 |
78 | await next();
79 | });
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/2.SSE_and_LP/ServerSentEvents/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/ServerSentEvents/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/2.SSE_and_LP/ServerSentEvents/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
25 |
26 |
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FeatureOverview", "FeatureOverview\FeatureOverview.csproj", "{8443E865-19C2-474A-B470-992D2391A8E7}"
4 | EndProject
5 | Global
6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 | Debug|Any CPU = Debug|Any CPU
8 | Release|Any CPU = Release|Any CPU
9 | EndGlobalSection
10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
11 | {8443E865-19C2-474A-B470-992D2391A8E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
12 | {8443E865-19C2-474A-B470-992D2391A8E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
13 | {8443E865-19C2-474A-B470-992D2391A8E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
14 | {8443E865-19C2-474A-B470-992D2391A8E7}.Release|Any CPU.Build.0 = Release|Any CPU
15 | EndGlobalSection
16 | EndGlobal
17 |
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/CustomHub.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.SignalR;
4 | using Microsoft.Extensions.Logging;
5 |
6 | namespace FeatureOverview
7 | {
8 | public interface IClientInterface
9 | {
10 | Task ClientHook(Data data);
11 | }
12 |
13 | public class CustomHub : Hub
14 | {
15 | private readonly ILogger _logger;
16 |
17 | public CustomHub(ILogger logger) => _logger = logger;
18 |
19 | public void ServerHook(Data data)
20 | {
21 | _logger.LogInformation("Receiving data: {0}, {1}", data, Context.ConnectionId);
22 | }
23 |
24 | public Task PingAll()
25 | {
26 | _logger.LogInformation("pinging everyone");
27 | return Clients.All.ClientHook(new(111, "ping all"));
28 | }
29 |
30 | public Task SelfPing()
31 | {
32 | _logger.LogInformation("self pinging");
33 | return Clients.Caller.ClientHook(new(222, "self ping"));
34 | }
35 |
36 | [HubMethodName("invocation_with_return")]
37 | public Data JustAFunction()
38 | {
39 | return new(1, "returned data from JustAFunction");
40 | }
41 |
42 | // -------------------------------
43 | // on connected/disconnected hooks
44 | // -------------------------------
45 | public override Task OnConnectedAsync()
46 | {
47 | return base.OnConnectedAsync();
48 | }
49 |
50 | public override Task OnDisconnectedAsync(Exception exception)
51 | {
52 | return base.OnDisconnectedAsync(exception);
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/Data.cs:
--------------------------------------------------------------------------------
1 | namespace FeatureOverview
2 | {
3 | public record Data(int Id, string Message);
4 | }
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/FeatureOverview.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/GroupsHub.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.SignalR;
3 |
4 | namespace FeatureOverview
5 | {
6 | public class GroupsHub : Hub
7 | {
8 | public Task Join() => Groups.AddToGroupAsync(Context.ConnectionId, "group_name");
9 |
10 | public Task Leave() => Groups.RemoveFromGroupAsync(Context.ConnectionId, "group_name");
11 |
12 | public Task Message() => Clients
13 | .Groups("group_name")
14 | .SendAsync("group_message", new Data(69, "secret group message"));
15 |
16 | }
17 | }
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace FeatureOverview
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IHostBuilder CreateHostBuilder(string[] args) =>
14 | Host.CreateDefaultBuilder(args)
15 | .ConfigureWebHostDefaults(webBuilder =>
16 | {
17 | webBuilder.UseStartup();
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:6611",
7 | "sslPort": 44308
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "FeatureOverview": {
19 | "commandName": "Project",
20 | "dotnetRunMessages": "true",
21 | "launchBrowser": true,
22 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.Extensions.Hosting;
5 |
6 | namespace FeatureOverview
7 | {
8 | public class Startup
9 | {
10 | public void ConfigureServices(IServiceCollection services)
11 | {
12 | services.AddControllers();
13 | services.AddSignalR();
14 | }
15 |
16 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
17 | {
18 | if (env.IsDevelopment())
19 | {
20 | app.UseDeveloperExceptionPage();
21 | }
22 |
23 | app.UseStaticFiles();
24 |
25 | app.UseRouting();
26 |
27 | app.UseEndpoints(endpoints =>
28 | {
29 | endpoints.MapDefaultControllerRoute();
30 | endpoints.MapHub("/custom");
31 | endpoints.MapHub("/groups");
32 | });
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/TestController.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Mvc;
3 | using Microsoft.AspNetCore.SignalR;
4 |
5 | namespace FeatureOverview
6 | {
7 | public class TestController : ControllerBase
8 | {
9 | private readonly IHubContext _customHub;
10 | // private readonly IHubContext _customHub;
11 |
12 | public TestController(
13 | IHubContext customHub
14 | // IHubContext customHub
15 | )
16 | {
17 | _customHub = customHub;
18 | }
19 |
20 | [HttpGet("/send")]
21 | public async Task SendData()
22 | {
23 | await _customHub.Clients.All.SendAsync("client_function_name", new Data(100, "Dummy Data"));
24 | return Ok();
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/wwwroot/groups.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
10 |
24 |
25 |
--------------------------------------------------------------------------------
/3.FeatureOverview/FeatureOverview/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
40 |
41 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamingData_8", "StreamingData_8\StreamingData_8.csproj", "{987616F4-075C-4216-AC78-AED415B2803B}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamingData_7", "StreamingData_7\StreamingData_7.csproj", "{D83D7CB5-64CB-4CF6-9467-5A003E8F72AD}"
6 | EndProject
7 | Global
8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
9 | Debug|Any CPU = Debug|Any CPU
10 | Release|Any CPU = Release|Any CPU
11 | EndGlobalSection
12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
13 | {987616F4-075C-4216-AC78-AED415B2803B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14 | {987616F4-075C-4216-AC78-AED415B2803B}.Debug|Any CPU.Build.0 = Debug|Any CPU
15 | {987616F4-075C-4216-AC78-AED415B2803B}.Release|Any CPU.ActiveCfg = Release|Any CPU
16 | {987616F4-075C-4216-AC78-AED415B2803B}.Release|Any CPU.Build.0 = Release|Any CPU
17 | {D83D7CB5-64CB-4CF6-9467-5A003E8F72AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18 | {D83D7CB5-64CB-4CF6-9467-5A003E8F72AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
19 | {D83D7CB5-64CB-4CF6-9467-5A003E8F72AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
20 | {D83D7CB5-64CB-4CF6-9467-5A003E8F72AD}.Release|Any CPU.Build.0 = Release|Any CPU
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_7/Data.cs:
--------------------------------------------------------------------------------
1 | namespace StreamingData_7
2 | {
3 | public class Data
4 | {
5 | public int Count { get; set; }
6 | public string Message { get; set; }
7 | }
8 | }
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_7/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace StreamingData_7
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IHostBuilder CreateHostBuilder(string[] args) =>
14 | Host.CreateDefaultBuilder(args)
15 | .ConfigureWebHostDefaults(webBuilder =>
16 | {
17 | webBuilder.UseStartup();
18 | });
19 | }
20 | }
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_7/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:47263",
8 | "sslPort": 44370
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "StreamingData": {
20 | "commandName": "Project",
21 | "dotnetRunMessages": "true",
22 | "launchBrowser": true,
23 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
24 | "environmentVariables": {
25 | "ASPNETCORE_ENVIRONMENT": "Development"
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_7/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.Extensions.Hosting;
5 |
6 | namespace StreamingData_7
7 | {
8 | public class Startup
9 | {
10 | public void ConfigureServices(IServiceCollection services)
11 | {
12 | services.AddSignalR();
13 | }
14 |
15 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
16 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
17 | {
18 | if (env.IsDevelopment())
19 | {
20 | app.UseDeveloperExceptionPage();
21 | }
22 |
23 | app.UseStaticFiles();
24 |
25 | app.UseRouting();
26 |
27 | app.UseEndpoints(endpoints =>
28 | {
29 | endpoints.MapHub("/stream");
30 | });
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_7/StreamingData_7.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | 7.3
6 | StreamingData_7
7 | StreamingData_7
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_7/StreamingHub.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Channels;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.SignalR;
6 |
7 | namespace StreamingData_7
8 | {
9 | public class StreamingHub : Hub
10 | {
11 | public ChannelReader Download(
12 | Data data,
13 | CancellationToken cancellationToken
14 | )
15 | {
16 | var channel = Channel.CreateUnbounded();
17 |
18 | Task.Run(async () =>
19 | {
20 | try
21 | {
22 | for (var i = 0; i < data.Count; i++)
23 | {
24 | await channel.Writer.WriteAsync($"{i}_{data.Message}", cancellationToken);
25 | await Task.Delay(1000, cancellationToken);
26 | }
27 | }
28 | catch (Exception ignored)
29 | {
30 | }
31 | finally
32 | {
33 | channel.Writer.Complete();
34 | }
35 | }, cancellationToken);
36 |
37 |
38 | return channel.Reader;
39 | }
40 |
41 | public async Task Upload(ChannelReader dataStream)
42 | {
43 | while (await dataStream.WaitToReadAsync())
44 | {
45 | if (dataStream.TryRead(out var data))
46 | {
47 | Console.WriteLine("Received Data: {0},{1}", data.Count, data.Message);
48 | }
49 | }
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_7/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_7/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_7/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
40 |
41 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_8/Data.cs:
--------------------------------------------------------------------------------
1 | namespace StreamingData_8
2 | {
3 | public class Data
4 | {
5 | public int Count { get; set; }
6 | public string Message { get; set; }
7 | }
8 | }
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_8/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace StreamingData_8
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IHostBuilder CreateHostBuilder(string[] args) =>
14 | Host.CreateDefaultBuilder(args)
15 | .ConfigureWebHostDefaults(webBuilder =>
16 | {
17 | webBuilder.UseStartup();
18 | });
19 | }
20 | }
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_8/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:47263",
8 | "sslPort": 44370
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "swagger",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "StreamingData": {
21 | "commandName": "Project",
22 | "dotnetRunMessages": "true",
23 | "launchBrowser": true,
24 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
25 | "environmentVariables": {
26 | "ASPNETCORE_ENVIRONMENT": "Development"
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_8/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.Extensions.Hosting;
5 |
6 | namespace StreamingData_8
7 | {
8 | public class Startup
9 | {
10 | public void ConfigureServices(IServiceCollection services)
11 | {
12 | services.AddSignalR();
13 | }
14 |
15 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
16 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
17 | {
18 | if (env.IsDevelopment())
19 | {
20 | app.UseDeveloperExceptionPage();
21 | }
22 |
23 | app.UseStaticFiles();
24 |
25 | app.UseRouting();
26 |
27 | app.UseEndpoints(endpoints =>
28 | {
29 | endpoints.MapHub("/stream");
30 | });
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_8/StreamingData_8.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | 8
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_8/StreamingHub.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.CompilerServices;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.SignalR;
7 |
8 | namespace StreamingData_8
9 | {
10 | public class StreamingHub : Hub
11 | {
12 | private readonly string _id;
13 |
14 | public StreamingHub()
15 | {
16 | _id = Guid.NewGuid().ToString();
17 | }
18 |
19 | public string Call() => _id;
20 |
21 | public async IAsyncEnumerable Download(
22 | Data data,
23 | [EnumeratorCancellation] CancellationToken cancellationToken
24 | )
25 | {
26 | for (var i = 0; i < data.Count; i++)
27 | {
28 | cancellationToken.ThrowIfCancellationRequested();
29 |
30 | yield return $"{i}_{data.Message}_{_id}";
31 |
32 | await Task.Delay(1000, cancellationToken);
33 | }
34 | }
35 |
36 | public async Task Upload(IAsyncEnumerable dataStream)
37 | {
38 | await foreach (var data in dataStream)
39 | {
40 | Console.WriteLine("Received Data: {0},{1},{2}", data.Count, data.Message, _id);
41 | }
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_8/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_8/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/4.StreamingData/StreamingData_8/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
44 |
45 |
--------------------------------------------------------------------------------
/4.StreamingData/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "5.0",
4 | "rollForward": "latestMajor",
5 | "allowPrerelease": false
6 | }
7 | }
--------------------------------------------------------------------------------
/5.Authentication/Authentication.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Authentication", "Authentication\Authentication.csproj", "{D8E41CB0-DEDB-46BF-A36C-4DAC7FE518AC}"
4 | EndProject
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthenticationExpiry", "AuthenticationExpiry\AuthenticationExpiry.csproj", "{D811BD99-1995-48FF-8029-C89A87355D5C}"
6 | EndProject
7 | Global
8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
9 | Debug|Any CPU = Debug|Any CPU
10 | Release|Any CPU = Release|Any CPU
11 | EndGlobalSection
12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
13 | {D8E41CB0-DEDB-46BF-A36C-4DAC7FE518AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14 | {D8E41CB0-DEDB-46BF-A36C-4DAC7FE518AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
15 | {D8E41CB0-DEDB-46BF-A36C-4DAC7FE518AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
16 | {D8E41CB0-DEDB-46BF-A36C-4DAC7FE518AC}.Release|Any CPU.Build.0 = Release|Any CPU
17 | {D811BD99-1995-48FF-8029-C89A87355D5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18 | {D811BD99-1995-48FF-8029-C89A87355D5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
19 | {D811BD99-1995-48FF-8029-C89A87355D5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
20 | {D811BD99-1995-48FF-8029-C89A87355D5C}.Release|Any CPU.Build.0 = Release|Any CPU
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/5.Authentication/Authentication/Authentication.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/5.Authentication/Authentication/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace Authentication
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | CreateHostBuilder(args).Build().Run();
11 | }
12 |
13 | public static IHostBuilder CreateHostBuilder(string[] args) =>
14 | Host.CreateDefaultBuilder(args)
15 | .ConfigureWebHostDefaults(webBuilder =>
16 | {
17 | webBuilder.UseStartup();
18 | });
19 | }
20 | }
--------------------------------------------------------------------------------
/5.Authentication/Authentication/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:7620",
8 | "sslPort": 44310
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "environmentVariables": {
16 | "ASPNETCORE_ENVIRONMENT": "Development"
17 | }
18 | },
19 | "Auth_Cookie": {
20 | "commandName": "Project",
21 | "dotnetRunMessages": "true",
22 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/5.Authentication/Authentication/ProtectedHub.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Microsoft.AspNetCore.Authorization;
3 | using Microsoft.AspNetCore.SignalR;
4 |
5 | namespace Authentication
6 | {
7 | // [Authorize]
8 | // [Authorize(AuthenticationSchemes = Startup.CustomCookieScheme)]
9 | [Authorize(AuthenticationSchemes = Startup.CustomCookieScheme + "," + Startup.CustomTokenScheme)]
10 | public class ProtectedHub : Hub
11 | {
12 | [Authorize("Cookie")]
13 | public object CookieProtected()
14 | {
15 | return CompileResult();
16 | }
17 |
18 | [Authorize("Token")]
19 | public object TokenProtected()
20 | {
21 | return CompileResult();
22 | }
23 |
24 | private object CompileResult() =>
25 | new
26 | {
27 | UserId = Context.UserIdentifier,
28 | Claims = Context.User.Claims.Select(x => new { x.Type, x.Value })
29 | };
30 | }
31 | }
--------------------------------------------------------------------------------
/5.Authentication/Authentication/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Security.Claims;
4 | using System.Text.Encodings.Web;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Authentication;
7 | using Microsoft.AspNetCore.Builder;
8 | using Microsoft.AspNetCore.Hosting;
9 | using Microsoft.AspNetCore.Http;
10 | using Microsoft.AspNetCore.Http.Connections;
11 | using Microsoft.AspNetCore.SignalR;
12 | using Microsoft.Extensions.DependencyInjection;
13 | using Microsoft.Extensions.Hosting;
14 | using Microsoft.Extensions.Logging;
15 | using Microsoft.Extensions.Options;
16 |
17 | namespace Authentication
18 | {
19 | public class Startup
20 | {
21 | public const string CustomCookieScheme = nameof(CustomCookieScheme);
22 | public const string CustomTokenScheme = nameof(CustomTokenScheme);
23 |
24 | public void ConfigureServices(IServiceCollection services)
25 | {
26 | services.AddAuthentication()
27 | .AddScheme(CustomCookieScheme, _ =>
28 | {
29 | })
30 | .AddJwtBearer(CustomTokenScheme, o =>
31 | {
32 | o.Events = new()
33 | {
34 | OnMessageReceived = (context) =>
35 | {
36 | var path = context.HttpContext.Request.Path;
37 | if (path.StartsWithSegments("/protected")
38 | || path.StartsWithSegments("/token"))
39 | {
40 | var accessToken = context.Request.Query["access_token"];
41 |
42 | if (!string.IsNullOrWhiteSpace(accessToken))
43 | {
44 | // context.Token = accessToken;
45 |
46 | var claims = new Claim[]
47 | {
48 | new("user_id", accessToken),
49 | new("token", "token_claim"),
50 | };
51 | var identity = new ClaimsIdentity(claims, CustomTokenScheme);
52 | context.Principal = new(identity);
53 | context.Success();
54 | }
55 | }
56 |
57 | return Task.CompletedTask;
58 | },
59 | };
60 | });
61 |
62 | services.AddAuthorization(c =>
63 | {
64 | c.AddPolicy("Cookie", pb => pb
65 | .AddAuthenticationSchemes(CustomCookieScheme)
66 | .RequireAuthenticatedUser());
67 |
68 | c.AddPolicy("Token", pb => pb
69 | // schema get's ignored in signalr
70 | .AddAuthenticationSchemes(CustomTokenScheme)
71 | .RequireClaim("token")
72 | .RequireAuthenticatedUser());
73 | });
74 |
75 | services.AddSignalR();
76 |
77 | services.AddSingleton();
78 | }
79 |
80 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
81 | {
82 | if (env.IsDevelopment())
83 | {
84 | app.UseDeveloperExceptionPage();
85 | }
86 |
87 | app.UseStaticFiles();
88 |
89 | app.UseRouting();
90 |
91 | app.UseAuthentication();
92 | app.UseAuthorization();
93 |
94 | app.UseEndpoints(endpoints =>
95 | {
96 | endpoints.MapHub("/protected", o =>
97 | {
98 | // o.Transports = HttpTransportType.LongPolling;
99 | });
100 |
101 | endpoints.Map("/get-cookie", ctx =>
102 | {
103 | ctx.Response.StatusCode = 200;
104 | ctx.Response.Cookies.Append("signalr-auth-cookie", Guid.NewGuid().ToString(), new()
105 | {
106 | Expires = DateTimeOffset.UtcNow.AddSeconds(30)
107 | });
108 | return ctx.Response.WriteAsync("");
109 | });
110 |
111 | endpoints.Map("/token", ctx =>
112 | {
113 | ctx.Response.StatusCode = 200;
114 | return ctx.Response.WriteAsync(ctx.User?.Claims.FirstOrDefault(x => x.Type == "user_id")?.Value);
115 | }).RequireAuthorization("Token");
116 |
117 | endpoints.Map("/cookie", ctx =>
118 | {
119 | ctx.Response.StatusCode = 200;
120 | return ctx.Response.WriteAsync(ctx.User?.Claims.FirstOrDefault(x => x.Type == "user_id")?.Value);
121 | }).RequireAuthorization("Cookie");
122 | });
123 | }
124 |
125 | public class CustomCookie : AuthenticationHandler
126 | {
127 | public CustomCookie(
128 | IOptionsMonitor options,
129 | ILoggerFactory logger,
130 | UrlEncoder encoder,
131 | ISystemClock clock
132 | ) : base(options, logger, encoder, clock)
133 | {
134 | }
135 |
136 | protected override Task HandleAuthenticateAsync()
137 | {
138 | if (Context.Request.Cookies.TryGetValue("signalr-auth-cookie", out var cookie))
139 | {
140 | var claims = new Claim[]
141 | {
142 | new("user_id", cookie),
143 | new("cookie", "cookie_claim"),
144 | };
145 | var identity = new ClaimsIdentity(claims, CustomCookieScheme);
146 | var principal = new ClaimsPrincipal(identity);
147 | var ticket = new AuthenticationTicket(principal, new(), CustomCookieScheme);
148 | return Task.FromResult(AuthenticateResult.Success(ticket));
149 | }
150 |
151 | return Task.FromResult(AuthenticateResult.Fail("signalr-auth-cookie not found"));
152 | }
153 | }
154 |
155 | public class UserIdProvider : IUserIdProvider
156 | {
157 | public string GetUserId(HubConnectionContext connection)
158 | {
159 | return connection.User?.Claims.FirstOrDefault(x => x.Type == "user_id")?.Value;
160 | }
161 | }
162 | }
163 | }
--------------------------------------------------------------------------------
/5.Authentication/Authentication/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/5.Authentication/Authentication/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
11 |
--------------------------------------------------------------------------------
/5.Authentication/Authentication/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
27 |
28 |
--------------------------------------------------------------------------------
/5.Authentication/AuthenticationExpiry/AuthHubFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNetCore.SignalR;
5 |
6 | namespace AuthenticationExpiry
7 | {
8 | public class AuthException : HubException
9 | {
10 | public AuthException(string message) : base(message)
11 | {
12 | }
13 | }
14 |
15 | public class AuthHubFilter : IHubFilter
16 | {
17 | public async ValueTask