diff --git a/src/Ch16/SignalRClient/Program.cs b/src/Ch16/SignalRClient/Program.cs new file mode 100644 index 00000000..bc1cc5eb --- /dev/null +++ b/src/Ch16/SignalRClient/Program.cs @@ -0,0 +1,38 @@ +using Microsoft.AspNetCore.SignalR.Client; + +var connection = new HubConnectionBuilder() + .WithUrl("https://localhost:5001/chathub") + .WithAutomaticReconnect([TimeSpan.Zero, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10)]) + .Build(); + +try +{ + await connection.StartAsync(); + Console.WriteLine("Connection started successfully."); +} +catch (Exception ex) +{ + Console.WriteLine($"Connection failed: {ex.Message}"); +} + +connection.On("ReceiveMessage", (user, message) => +{ + Console.WriteLine($"{user}: {message}"); +}); + +await connection.InvokeAsync("SendMessage", "User1", "Hello, SignalR!"); + +connection.Closed += async (error) => +{ + Console.WriteLine($"Connection closed. Error: {error?.Message}"); + await Task.Delay(5000); // Wait before attempting to reconnect + try + { + await connection.StartAsync(); + Console.WriteLine("Reconnection successful."); + } + catch (Exception ex) + { + Console.WriteLine($"Reconnection failed: {ex.Message}"); + } +}; \ No newline at end of file diff --git a/src/Ch16/SignalRClient/SignalRClient.csproj b/src/Ch16/SignalRClient/SignalRClient.csproj new file mode 100644 index 00000000..29308bd3 --- /dev/null +++ b/src/Ch16/SignalRClient/SignalRClient.csproj @@ -0,0 +1,15 @@ + + + + Exe + net9.0 + latest + enable + enable + + + + + + + diff --git a/src/Ch16/SignalRServerExample/ChatHub.cs b/src/Ch16/SignalRServerExample/ChatHub.cs new file mode 100644 index 00000000..dd8bc4dd --- /dev/null +++ b/src/Ch16/SignalRServerExample/ChatHub.cs @@ -0,0 +1,11 @@ +namespace SignalRServerExample; + +using Microsoft.AspNetCore.SignalR; + +public class ChatHub : Hub +{ + public async Task SendMessage(string user, string message) + { + await Clients.All.SendAsync("ReceiveMessage", user, message); + } +} \ No newline at end of file diff --git a/src/Ch16/SignalRServerExample/Program.cs b/src/Ch16/SignalRServerExample/Program.cs new file mode 100644 index 00000000..545c17e3 --- /dev/null +++ b/src/Ch16/SignalRServerExample/Program.cs @@ -0,0 +1,33 @@ +using SignalRServerExample; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddSignalR(); + +var app = builder.Build(); + +app.UseHttpsRedirection(); + +app.UseDefaultFiles(); + +app.UseStaticFiles(); + +app.UseRouting(); + +app.Use(async (context, next) => +{ + Console.WriteLine($"Incoming connection: {context.Request.Path}"); + await next(); +}); + +app.UseEndpoints(endpoints => +{ + endpoints.MapHub("/chathub"); + endpoints.MapFallback(context => + { + context.Response.StatusCode = 404; + return context.Response.WriteAsync("Endpoint not found."); + }); +}); + +app.Run(); \ No newline at end of file diff --git a/src/Ch16/SignalRServerExample/Properties/launchSettings.json b/src/Ch16/SignalRServerExample/Properties/launchSettings.json new file mode 100644 index 00000000..e58a4edd --- /dev/null +++ b/src/Ch16/SignalRServerExample/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/Ch16/SignalRServerExample/SignalRServerExample.csproj b/src/Ch16/SignalRServerExample/SignalRServerExample.csproj new file mode 100644 index 00000000..d4dc7660 --- /dev/null +++ b/src/Ch16/SignalRServerExample/SignalRServerExample.csproj @@ -0,0 +1,13 @@ + + + + net9.0 + enable + enable + + + + + + + diff --git a/src/Ch16/SignalRServerExample/appsettings.Development.json b/src/Ch16/SignalRServerExample/appsettings.Development.json new file mode 100644 index 00000000..ff66ba6b --- /dev/null +++ b/src/Ch16/SignalRServerExample/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/Ch16/SignalRServerExample/appsettings.json b/src/Ch16/SignalRServerExample/appsettings.json new file mode 100644 index 00000000..4d566948 --- /dev/null +++ b/src/Ch16/SignalRServerExample/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/Ch16/SignalRServerExample/wwwroot/index.html b/src/Ch16/SignalRServerExample/wwwroot/index.html new file mode 100644 index 00000000..c697d03d --- /dev/null +++ b/src/Ch16/SignalRServerExample/wwwroot/index.html @@ -0,0 +1,35 @@ + + + + SignalR Test + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Ch16/ch16.sln b/src/Ch16/ch16.sln index a55ff74c..816d3be0 100644 --- a/src/Ch16/ch16.sln +++ b/src/Ch16/ch16.sln @@ -1,8 +1,22 @@  Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalRServerExample", "SignalRServerExample\SignalRServerExample.csproj", "{D130D4A9-88F6-47D8-A409-4F64F8AD4691}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SignalRClient", "SignalRClient\SignalRClient.csproj", "{B12A3362-5795-4FEF-9FBC-102253CD6BB4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D130D4A9-88F6-47D8-A409-4F64F8AD4691}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D130D4A9-88F6-47D8-A409-4F64F8AD4691}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D130D4A9-88F6-47D8-A409-4F64F8AD4691}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D130D4A9-88F6-47D8-A409-4F64F8AD4691}.Release|Any CPU.Build.0 = Release|Any CPU + {B12A3362-5795-4FEF-9FBC-102253CD6BB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B12A3362-5795-4FEF-9FBC-102253CD6BB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B12A3362-5795-4FEF-9FBC-102253CD6BB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B12A3362-5795-4FEF-9FBC-102253CD6BB4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection EndGlobal