Skip to content

Commit

Permalink
Main update
Browse files Browse the repository at this point in the history
Fix request\response deserialization
Multiple SignalR hub support
Migrate from Newtonsoft.Json to System.Text.Json
JSON WART event beautifier
  • Loading branch information
engineering87 committed Jun 2, 2024
1 parent 76565e4 commit e1330af
Show file tree
Hide file tree
Showing 20 changed files with 498 additions and 46 deletions.
24 changes: 17 additions & 7 deletions src/WART-Client/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// (c) 2019 Francesco Del Re <[email protected]>
// This code is licensed under MIT license (see LICENSE.txt for details)
using System;
using Microsoft.Extensions.Configuration;

namespace WART_Client
{
Expand All @@ -9,19 +10,28 @@ public class Program
private static void Main()
{
Console.WriteLine("Starting WartTestClient");

#region JWT Client Test

WartTestClientJwt.ConnectAsync();
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();

#endregion
var wartHubUrl = $"{configuration["Scheme"]}://{configuration["Host"]}:{configuration["Port"]}/{configuration["Hubname"]}";

#region No authentication Client Test
Console.WriteLine($"Connecting to {wartHubUrl}");

//WartTestClient.ConnectAsync();
var auth = configuration["AuthenticationJwt"];

#endregion
if (bool.Parse(auth))
{
var key = configuration["Key"];
WartTestClientJwt.ConnectAsync(wartHubUrl, key);
}
else
{
WartTestClient.ConnectAsync(wartHubUrl);
}

Console.WriteLine($"Connected to {wartHubUrl}");
Console.ReadLine();
}
}
Expand Down
19 changes: 17 additions & 2 deletions src/WART-Client/WART-Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,26 @@
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>WART_Client</RootNamespace>
<StartupObject>WART_Client.Program</StartupObject>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.4" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1" />
<None Remove="appsettings.json" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.6.0" />
</ItemGroup>

</Project>
4 changes: 2 additions & 2 deletions src/WART-Client/WartTestClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ namespace WART_Client
/// </summary>
public class WartTestClient
{
public static async void ConnectAsync()
public static async void ConnectAsync(string wartHubUrl)
{
try
{
var hubConnection = new HubConnectionBuilder()
.WithUrl($"http://localhost:51392/warthub")
.WithUrl(wartHubUrl)
.WithAutomaticReconnect()
.Build();

Expand Down
11 changes: 5 additions & 6 deletions src/WART-Client/WartTestClientJwt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,18 @@ namespace WART_Client
/// </summary>
public class WartTestClientJwt
{
private const string Token = "dn3341fmcscscwe28419";
private static readonly SymmetricSecurityKey SecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Token));
private static readonly JwtSecurityTokenHandler JwtTokenHandler = new JwtSecurityTokenHandler();

public static async void ConnectAsync()
public static async void ConnectAsync(string wartHubUrl, string key)
{
try
{
var hubConnection = new HubConnectionBuilder()
.WithUrl($"http://localhost:51392/warthub", options =>
.WithUrl(wartHubUrl, options =>
{
options.SkipNegotiation = true;
options.Transports = HttpTransportType.WebSockets;
options.AccessTokenProvider = () => Task.FromResult(GenerateToken());
options.AccessTokenProvider = () => Task.FromResult(GenerateToken(key));
})
.WithAutomaticReconnect()
.Build();
Expand All @@ -47,8 +45,9 @@ public static async void ConnectAsync()
}
}

private static string GenerateToken()
private static string GenerateToken(string key)
{
var SecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var credentials = new SigningCredentials(SecurityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(expires: DateTime.UtcNow.AddHours(24), signingCredentials: credentials);
return JwtTokenHandler.WriteToken(token);
Expand Down
8 changes: 8 additions & 0 deletions src/WART-Client/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Scheme": "https",
"Host": "localhost",
"Port": "50980",
"Hubname": "warthub",
"AuthenticationJwt": "true",
"Key": "dn3341fmcscscwe28419brhwbwgbss4t"
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public static IServiceCollection AddJwtMiddleware(this IServiceCollection servic

services.AddLogging(configure => configure.AddConsole());

var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenKey));
var key = Encoding.UTF8.GetBytes(tokenKey);
var securityKey = new SymmetricSecurityKey(key);

services.AddAuthentication(options =>
{
Expand Down
34 changes: 25 additions & 9 deletions src/WART-Core/Entity/WartEvent.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// (c) 2019 Francesco Del Re <[email protected]>
// This code is licensed under MIT license (see LICENSE.txt for details)
using Newtonsoft.Json;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using WART_Core.Serialization;

namespace WART_Core.Entity
{
Expand All @@ -14,7 +16,9 @@ public class WartEvent
public string HttpMethod { get; set; }
public string HttpPath { get; set; }
public string RemoteAddress { get; set; }
[JsonConverter(typeof(JsonArrayOrObjectStringConverter))]
public string JsonRequestPayload { get; set; }
[JsonConverter(typeof(JsonArrayOrObjectStringConverter))]
public string JsonResponsePayload { get; set; }
public string ExtraInfo { get; set; }

Expand Down Expand Up @@ -49,14 +53,20 @@ public WartEvent(string httpMethod, string httpPath, string remoteAddress)
/// <param name="remoteAddress"></param>
public WartEvent(object request, object response, string httpMethod, string httpPath, string remoteAddress)
{
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

this.EventId = Guid.NewGuid();
this.TimeStamp = DateTime.Now;
this.UtcTimeStamp = DateTime.UtcNow;
this.HttpMethod = httpMethod;
this.HttpPath = httpPath;
this.RemoteAddress = remoteAddress;
this.JsonRequestPayload = request != null ? JsonConvert.SerializeObject(request) : string.Empty;
this.JsonResponsePayload = response != null ? JsonConvert.SerializeObject(response) : string.Empty;
this.JsonRequestPayload = request != null ? JsonSerializer.Serialize(request, serializeOptions) : string.Empty;
this.JsonResponsePayload = response != null ? JsonSerializer.Serialize(response, serializeOptions) : string.Empty;
}

/// <summary>
Expand All @@ -65,7 +75,13 @@ public WartEvent(object request, object response, string httpMethod, string http
/// <returns></returns>
public override string ToString()
{
return JsonConvert.SerializeObject(this);
var serializeOptions = new JsonSerializerOptions
{
WriteIndented = true,
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

return JsonSerializer.Serialize(this, serializeOptions);
}

/// <summary>
Expand All @@ -75,8 +91,8 @@ public override string ToString()
/// <returns></returns>
public T GetRequestObject<T>() where T : class
{
return string.IsNullOrEmpty(JsonRequestPayload) ?
JsonConvert.DeserializeObject<T>(JsonRequestPayload) : null;
return !string.IsNullOrEmpty(JsonRequestPayload) ?
JsonSerializer.Deserialize<T>(JsonRequestPayload) : null;
}

/// <summary>
Expand All @@ -86,8 +102,8 @@ public T GetRequestObject<T>() where T : class
/// <returns></returns>
public T GetResponseObject<T>() where T : class
{
return string.IsNullOrEmpty(JsonResponsePayload) ?
JsonConvert.DeserializeObject<T>(JsonResponsePayload) : null;
return !string.IsNullOrEmpty(JsonResponsePayload) ?
JsonSerializer.Deserialize<T>(JsonResponsePayload) : null;
}
}
}
}
6 changes: 6 additions & 0 deletions src/WART-Core/Enum/HubType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ namespace WART_Core.Enum
/// </summary>
public enum HubType
{
/// <summary>
/// Simple SignalR hub without authentication
/// </summary>
NoAuthentication,
/// <summary>
/// SignalR hub with JWT authentication
/// </summary>
JwtAuthentication
}
}
91 changes: 85 additions & 6 deletions src/WART-Core/Middleware/WartApplicationBuilderExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// This code is licensed under MIT license (see LICENSE.txt for details)
using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Linq;
using WART_Core.Authentication.JWT;
using WART_Core.Enum;
using WART_Core.Hubs;
Expand All @@ -20,6 +22,8 @@ public static class WartApplicationBuilderExtension
/// <returns></returns>
public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app)
{
app.UseRouting();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
Expand All @@ -35,11 +39,13 @@ public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app
/// Use WART dependency to IApplicationBuilder.
/// The default SignalR hub name is warthub.
/// </summary>
/// <param name="app"></param>
/// <param name="hubType"></param>
/// <param name="app">The IApplicationBuilder</param>
/// <param name="hubType">The SignalR hub type</param>
/// <returns></returns>
public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app, HubType hubType)
{
app.UseRouting();

if (hubType == HubType.NoAuthentication)
{
app.UseEndpoints(endpoints =>
Expand All @@ -66,14 +72,16 @@ public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app
/// <summary>
/// Use WART dependency to IApplicationBuilder.
/// </summary>
/// <param name="app"></param>
/// <param name="hubName"></param>
/// <param name="app">The IApplicationBuilder</param>
/// <param name="hubName">The SignalR hub name</param>
/// <returns></returns>
public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app, string hubName)
{
if (string.IsNullOrEmpty(hubName))
throw new ArgumentNullException("Invalid hub name");

app.UseRouting();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
Expand All @@ -88,15 +96,45 @@ public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app
/// <summary>
/// Use WART dependency to IApplicationBuilder.
/// </summary>
/// <param name="app"></param>
/// <param name="app">The IApplicationBuilder</param>
/// <param name="hubNameList">The SignalR hub name list</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app, IEnumerable<string> hubNameList)
{
if (hubNameList == null)
throw new ArgumentNullException("Invalid hub list");

app.UseRouting();

foreach (var hubName in hubNameList.Distinct())
{
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<WartHub>($"/{hubName.Trim()}");
});
}

app.UseForwardedHeaders();

return app;
}

/// <summary>
/// Use WART dependency to IApplicationBuilder.
/// </summary>
/// <param name="app">The IApplicationBuilder</param>
/// <param name="hubName">The SignalR hub name</param>
/// <param name="hubType"></param>
/// <param name="hubType">The SignalR hub type</param>
/// <returns></returns>
public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app, string hubName, HubType hubType)
{
if (string.IsNullOrEmpty(hubName))
throw new ArgumentNullException("Invalid hub name");

app.UseRouting();

if (hubType == HubType.NoAuthentication)
{
app.UseEndpoints(endpoints =>
Expand All @@ -119,5 +157,46 @@ public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app

return app;
}

/// <summary>
/// Use WART dependency to IApplicationBuilder.
/// </summary>
/// <param name="app">The IApplicationBuilder</param>
/// <param name="hubNameList">The SignalR hub name list</param>
/// <param name="hubType">The SignalR hub type</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app, IEnumerable<string> hubNameList, HubType hubType)
{
if (hubNameList == null)
throw new ArgumentNullException("Invalid hub list");

app.UseRouting();

foreach (var hubName in hubNameList.Distinct())
{
if (hubType == HubType.NoAuthentication)
{
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<WartHub>($"/{hubName.Trim()}");
});
}
else
{
app.UseJwtMiddleware();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<WartHubJwt>($"/{hubName.Trim()}");
});
}
}

app.UseForwardedHeaders();

return app;
}
}
}
2 changes: 1 addition & 1 deletion src/WART-Core/Middleware/WartServiceCollectionExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static IServiceCollection AddWartMiddleware(this IServiceCollection servi

services.AddSignalR(options =>
{
options.EnableDetailedErrors = true;
options.EnableDetailedErrors = true;
});

return services;
Expand Down
Loading

0 comments on commit e1330af

Please sign in to comment.