Skip to content

Commit f79b677

Browse files
authored
Merge pull request #2 from PandaTechAM/development
Added redis and signalR utils
2 parents ca6fc01 + a00fe41 commit f79b677

File tree

9 files changed

+115
-28
lines changed

9 files changed

+115
-28
lines changed

Readme.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ This package currently supports:
2323
- **Cors Configuration** with easy configuration options.
2424
- **Resilience Pipelines** for `HttpClient` operations.
2525
- **Controller Extensions** for mapping old-style MVC controllers.
26+
- **SignalR Extensions** for adding simple SignalR or distributed SignalR backed with Redis.
2627
- **OpenTelemetry Integration** for tracking metrics, traces, and logging.
2728
- **Health Checks** with default endpoints and startup validation.
2829
- Various **Extensions and Utilities**, including enumerable, string, and queryable extensions.
@@ -121,6 +122,7 @@ Follow this example to set up your project with all the features provided by thi
121122
},
122123
"RepositoryName": "be-lib-sharedkernel",
123124
"ConnectionStrings": {
125+
"Redis": "localhost:6379",
124126
"PersistentStorage": "/persistence"
125127
},
126128
"Security": {
@@ -143,14 +145,15 @@ builder
143145
.AddResponseCrafter(NamingConvention.ToSnakeCase)
144146
.AddOpenApi()
145147
.AddOpenTelemetry()
146-
.AddEndpoints(AssemblyRegistry.ToArray())
148+
.AddMapMinimalApis(AssemblyRegistry.ToArray())
147149
.AddControllers(AssemblyRegistry.ToArray())
148150
.AddMediatrWithBehaviors(AssemblyRegistry.ToArray())
149151
.AddResilienceDefaultPipeline()
150152
.MapDefaultTimeZone()
151-
.AddCors();
152-
153-
builder.Services.AddHealthChecks();
153+
.AddRedis(KeyPrefix.AssemblyNamePrefix)
154+
.AddDistributedSignalR("DistributedSignalR") // or .AddSignalR()
155+
.AddCors()
156+
.AddHealthChecks();
154157

155158

156159
var app = builder.Build();
@@ -159,11 +162,12 @@ app
159162
.UseRequestResponseLogging()
160163
.UseResponseCrafter()
161164
.UseCors()
162-
.MapEndpoints()
165+
.MapMinimalApis()
163166
.MapDefaultEndpoints()
164167
.EnsureHealthy()
165168
.ClearAssemblyRegistry()
166-
.UseOpenApi();
169+
.UseOpenApi()
170+
.MapControllers();
167171

168172
app.LogStartSuccess();
169173
app.Run();
@@ -531,11 +535,16 @@ The default resilience pipeline includes the following policies:
531535

532536
For mapping old style MVC controllers, use `builder.AddControllers()`.
533537
The `AddControllers()` method can also accept assembly names as parameters to scan for controllers.
538+
The `MapControllers()` method maps the controllers to the application.
534539

535540
Example:
536541

537542
```csharp
543+
var builder = WebApplication.CreateBuilder(args);
538544
builder.AddControllers([typeof(Program).Assembly]);
545+
var app = builder.Build();
546+
app.MapControllers();
547+
app.Run();
539548
```
540549

541550
## OpenTelemetry
@@ -598,6 +607,7 @@ This package includes various extensions and utilities to aid development:
598607
- **Pandatech.FluentMinimalApiMapper:** Simplifies mapping in minimal APIs.
599608
- **Pandatech.RegexBox:** A collection of useful regular expressions.
600609
- **Pandatech.ResponseCrafter:** A utility for crafting consistent API responses.
610+
- **Pandatech.DistributedCache:** A distributed cache provider for Redis.
601611

602612
## License
603613

src/SharedKernel/Extensions/ConfigurationExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ internal static class ConfigurationExtensions
88
private const string PersistentConfigurationPath = "PersistentStorage";
99
private const string RepositoryNameConfigurationPath = "RepositoryName";
1010
private const string TimeZoneConfigurationPath = "DefaultTimeZone";
11+
private const string RedisConfigurationPath = "Redis";
1112

1213
internal static string GetAllowedCorsOrigins(this IConfiguration configuration)
1314
{
@@ -52,4 +53,15 @@ public static string GetDefaultTimeZone(this IConfiguration configuration)
5253

5354
return timeZone;
5455
}
56+
57+
public static string GetRedisUrl(this IConfiguration configuration)
58+
{
59+
var redisConnectionString = configuration.GetConnectionString(RedisConfigurationPath);
60+
if (redisConnectionString is null)
61+
{
62+
throw new InvalidOperationException("Redis connection string is not configured.");
63+
}
64+
65+
return redisConnectionString;
66+
}
5567
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using DistributedCache.Extensions;
2+
using DistributedCache.Options;
3+
using Microsoft.AspNetCore.Builder;
4+
5+
namespace SharedKernel.Extensions;
6+
7+
public static class DistributedCacheExtension
8+
{
9+
public static WebApplicationBuilder AddRedis(this WebApplicationBuilder builder, KeyPrefix keyPrefix)
10+
{
11+
builder.AddDistributedCache(options =>
12+
{
13+
options.RedisConnectionString = builder.Configuration.GetRedisUrl();
14+
options.KeyPrefixForIsolation = keyPrefix;
15+
});
16+
17+
return builder;
18+
}
19+
}

src/SharedKernel/Extensions/HealthCheckRunnerExtension.cs renamed to src/SharedKernel/Extensions/HealthCheckExtensions.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace SharedKernel.Extensions;
77

8-
public static class HealthCheckRunnerExtension
8+
public static class HealthCheckExtensions
99
{
1010
public static WebApplication EnsureHealthy(this WebApplication app)
1111
{
@@ -42,4 +42,10 @@ public static WebApplication EnsureHealthy(this WebApplication app)
4242
var message = $"Unhealthy services detected: {string.Join(", ", unhealthyChecks)}";
4343
throw new ServiceUnavailableException(message);
4444
}
45+
46+
public static WebApplicationBuilder AddHealthChecks(this WebApplicationBuilder builder)
47+
{
48+
builder.Services.AddHealthChecks();
49+
return builder;
50+
}
4551
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using StackExchange.Redis;
4+
5+
namespace SharedKernel.Extensions;
6+
7+
public static class SignalRExtensions
8+
{
9+
10+
public static WebApplicationBuilder AddSignalR(this WebApplicationBuilder builder)
11+
{
12+
builder
13+
.Services
14+
.AddSignalR()
15+
.AddMessagePackProtocol();
16+
17+
return builder;
18+
}
19+
20+
public static WebApplicationBuilder AddDistributedSignalR(this WebApplicationBuilder builder, string redisChannelName)
21+
{
22+
builder
23+
.Services
24+
.AddSignalR()
25+
.AddMessagePackProtocol()
26+
.AddStackExchangeRedis(builder.Configuration.GetRedisUrl(),
27+
options =>
28+
{
29+
options.Configuration.ChannelPrefix = RedisChannel.Literal("FinHub:SignalR:");
30+
});
31+
32+
33+
return builder;
34+
}
35+
}

src/SharedKernel/Logging/StartupLoggerExtensions.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Globalization;
2+
using System.Text.Json;
23
using Microsoft.AspNetCore.Builder;
3-
using Newtonsoft.Json;
44

55
namespace SharedKernel.Logging;
66

@@ -11,7 +11,7 @@ public static class StartupLoggerExtensions
1111
public static WebApplicationBuilder LogStartAttempt(this WebApplicationBuilder builder)
1212
{
1313
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
14-
Console.WriteLine(JsonConvert.SerializeObject(new
14+
Console.WriteLine(JsonSerializer.Serialize(new
1515
{
1616
Timestamp = now,
1717
Event = "ApplicationStartAttempt",
@@ -27,7 +27,7 @@ public static WebApplication LogStartSuccess(this WebApplication app)
2727
.TotalMilliseconds;
2828
var deltaInSeconds = Math.Round(delta / 1000, 2);
2929
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
30-
Console.WriteLine(JsonConvert.SerializeObject(new
30+
Console.WriteLine(JsonSerializer.Serialize(new
3131
{
3232
Timestamp = now,
3333
Event = "ApplicationStartSuccess",
@@ -40,7 +40,7 @@ public static WebApplicationBuilder LogModuleRegistrationSuccess(this WebApplica
4040
string moduleName)
4141
{
4242
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
43-
Console.WriteLine(JsonConvert.SerializeObject(new
43+
Console.WriteLine(JsonSerializer.Serialize(new
4444
{
4545
Timestamp = now,
4646
Event = "ModuleRegistrationSuccess",
@@ -52,12 +52,12 @@ public static WebApplicationBuilder LogModuleRegistrationSuccess(this WebApplica
5252
public static WebApplication LogModuleUseSuccess(this WebApplication app, string moduleName)
5353
{
5454
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
55-
Console.WriteLine(JsonConvert.SerializeObject(new
55+
Console.WriteLine(JsonSerializer.Serialize(new
5656
{
5757
Timestamp = now,
5858
Event = "ModuleUseSuccess",
5959
Module = moduleName
6060
}));
6161
return app;
6262
}
63-
}
63+
}

src/SharedKernel/SharedKernel.csproj

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
<PackageReadmeFile>Readme.md</PackageReadmeFile>
99
<Authors>Pandatech</Authors>
1010
<Copyright>MIT</Copyright>
11-
<Version>1.0.1</Version>
11+
<Version>1.0.2</Version>
1212
<PackageId>Pandatech.SharedKernel</PackageId>
1313
<Title>Pandatech Shared Kernel Library</Title>
1414
<PackageTags>Pandatech, shared kernel, library, OpenAPI, Swagger, utilities, scalar</PackageTags>
1515
<Description>Pandatech.SharedKernel provides centralized configurations, utilities, and extensions for ASP.NET Core projects. For more information refere to readme.md document.</Description>
1616
<RepositoryUrl>https://github.com/PandaTechAM/be-lib-sharedkernel</RepositoryUrl>
17-
<PackageReleaseNotes>Nuget updates</PackageReleaseNotes>
17+
<PackageReleaseNotes>Added redis and signalR utils</PackageReleaseNotes>
1818
</PropertyGroup>
1919

2020
<ItemGroup>
@@ -26,10 +26,14 @@
2626
<PackageReference Include="AspNetCore.HealthChecks.Prometheus.Metrics" Version="8.0.1" />
2727
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="8.0.1" />
2828
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="8.12.2" />
29+
<PackageReference Include="FluentDateTime" Version="3.0.0" />
2930
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
3031
<PackageReference Include="HtmlSanitizer" Version="8.1.870" />
3132
<PackageReference Include="MediatR" Version="12.4.1" />
3233
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
34+
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.0" />
35+
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="9.0.0" />
36+
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="9.0.0" />
3337
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0" />
3438
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" />
3539
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.8.0-rc.1"/>
@@ -38,18 +42,14 @@
3842
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0"/>
3943
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0"/>
4044
<PackageReference Include="Pandatech.Crypto" Version="4.0.0" />
41-
<PackageReference Include="Pandatech.FluentMinimalApiMapper" Version="2.0.0" />
45+
<PackageReference Include="Pandatech.DistributedCache" Version="3.0.0" />
46+
<PackageReference Include="Pandatech.FluentMinimalApiMapper" Version="2.0.1" />
4247
<PackageReference Include="Pandatech.PandaVaultClient" Version="4.0.0" />
4348
<PackageReference Include="Pandatech.RegexBox" Version="3.0.0" />
44-
<PackageReference Include="Pandatech.ResponseCrafter" Version="4.0.1" />
49+
<PackageReference Include="Pandatech.ResponseCrafter" Version="5.0.1" />
4550
<PackageReference Include="Scalar.AspNetCore" Version="1.2.42" />
4651
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
4752
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.0.0" />
4853
</ItemGroup>
4954

50-
<ItemGroup>
51-
<Content Include="wwwroot\**" CopyToOutputDirectory="PreserveNewest" Pack="true" PackagePath="contentFiles\any\any" />
52-
</ItemGroup>
53-
54-
5555
</Project>

test/SharedKernel.Demo/Program.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using DistributedCache.Extensions;
2+
using DistributedCache.Options;
13
using FluentMinimalApiMapper;
24
using Microsoft.AspNetCore.Mvc;
35
using SharedKernel.Demo;
@@ -21,14 +23,15 @@
2123
.AddResponseCrafter(NamingConvention.ToSnakeCase)
2224
.AddOpenApi()
2325
.AddOpenTelemetry()
24-
.AddEndpoints(AssemblyRegistry.ToArray())
26+
.AddMinimalApis(AssemblyRegistry.ToArray())
2527
.AddControllers(AssemblyRegistry.ToArray())
2628
.AddMediatrWithBehaviors(AssemblyRegistry.ToArray())
2729
.AddResilienceDefaultPipeline()
30+
.AddRedis(KeyPrefix.AssemblyNamePrefix)
31+
.AddDistributedSignalR("DistributedSignalR") // or .AddSignalR()
2832
.MapDefaultTimeZone()
29-
.AddCors();
30-
31-
builder.Services.AddHealthChecks();
33+
.AddCors()
34+
.AddHealthChecks();
3235

3336

3437
var app = builder.Build();
@@ -37,11 +40,12 @@
3740
.UseRequestResponseLogging()
3841
.UseResponseCrafter()
3942
.UseCors()
40-
.MapEndpoints()
43+
.MapMinimalApis()
4144
.MapDefaultEndpoints()
4245
.EnsureHealthy()
4346
.ClearAssemblyRegistry()
44-
.UseOpenApi();
47+
.UseOpenApi()
48+
.MapControllers();
4549

4650
app.MapPost("/params", ([AsParameters] TestTypes testTypes) => TypedResults.Ok(testTypes));
4751
app.MapPost("/body", ([FromBody] TestTypes testTypes) => TypedResults.Ok(testTypes));

test/SharedKernel.Demo/appsettings.Development.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"DefaultTimeZone": "Caucasus Standard Time",
1313
"RepositoryName": "be-lib-sharedkernel",
1414
"ConnectionStrings": {
15+
"Redis": "localhost:6379",
1516
"PersistentStorage": "/persistence"
1617
}
1718
}

0 commit comments

Comments
 (0)