Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ This package currently supports:
- **Cors Configuration** with easy configuration options.
- **Resilience Pipelines** for `HttpClient` operations.
- **Controller Extensions** for mapping old-style MVC controllers.
- **SignalR Extensions** for adding simple SignalR or distributed SignalR backed with Redis.
- **OpenTelemetry Integration** for tracking metrics, traces, and logging.
- **Health Checks** with default endpoints and startup validation.
- Various **Extensions and Utilities**, including enumerable, string, and queryable extensions.
Expand Down Expand Up @@ -121,6 +122,7 @@ Follow this example to set up your project with all the features provided by thi
},
"RepositoryName": "be-lib-sharedkernel",
"ConnectionStrings": {
"Redis": "localhost:6379",
"PersistentStorage": "/persistence"
},
"Security": {
Expand All @@ -143,14 +145,15 @@ builder
.AddResponseCrafter(NamingConvention.ToSnakeCase)
.AddOpenApi()
.AddOpenTelemetry()
.AddEndpoints(AssemblyRegistry.ToArray())
.AddMapMinimalApis(AssemblyRegistry.ToArray())
.AddControllers(AssemblyRegistry.ToArray())
.AddMediatrWithBehaviors(AssemblyRegistry.ToArray())
.AddResilienceDefaultPipeline()
.MapDefaultTimeZone()
.AddCors();

builder.Services.AddHealthChecks();
.AddRedis(KeyPrefix.AssemblyNamePrefix)
.AddDistributedSignalR("DistributedSignalR") // or .AddSignalR()
.AddCors()
.AddHealthChecks();


var app = builder.Build();
Expand All @@ -159,11 +162,12 @@ app
.UseRequestResponseLogging()
.UseResponseCrafter()
.UseCors()
.MapEndpoints()
.MapMinimalApis()
.MapDefaultEndpoints()
.EnsureHealthy()
.ClearAssemblyRegistry()
.UseOpenApi();
.UseOpenApi()
.MapControllers();

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

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

Example:

```csharp
var builder = WebApplication.CreateBuilder(args);
builder.AddControllers([typeof(Program).Assembly]);
var app = builder.Build();
app.MapControllers();
app.Run();
```

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

## License

Expand Down
12 changes: 12 additions & 0 deletions src/SharedKernel/Extensions/ConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ internal static class ConfigurationExtensions
private const string PersistentConfigurationPath = "PersistentStorage";
private const string RepositoryNameConfigurationPath = "RepositoryName";
private const string TimeZoneConfigurationPath = "DefaultTimeZone";
private const string RedisConfigurationPath = "Redis";

internal static string GetAllowedCorsOrigins(this IConfiguration configuration)
{
Expand Down Expand Up @@ -52,4 +53,15 @@ public static string GetDefaultTimeZone(this IConfiguration configuration)

return timeZone;
}

public static string GetRedisUrl(this IConfiguration configuration)
{
var redisConnectionString = configuration.GetConnectionString(RedisConfigurationPath);
if (redisConnectionString is null)
{
throw new InvalidOperationException("Redis connection string is not configured.");
}

return redisConnectionString;
}
}
19 changes: 19 additions & 0 deletions src/SharedKernel/Extensions/DistributedCacheExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using DistributedCache.Extensions;
using DistributedCache.Options;
using Microsoft.AspNetCore.Builder;

namespace SharedKernel.Extensions;

public static class DistributedCacheExtension
{
public static WebApplicationBuilder AddRedis(this WebApplicationBuilder builder, KeyPrefix keyPrefix)
{
builder.AddDistributedCache(options =>
{
options.RedisConnectionString = builder.Configuration.GetRedisUrl();
options.KeyPrefixForIsolation = keyPrefix;
});

return builder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace SharedKernel.Extensions;

public static class HealthCheckRunnerExtension
public static class HealthCheckExtensions
{
public static WebApplication EnsureHealthy(this WebApplication app)
{
Expand Down Expand Up @@ -42,4 +42,10 @@ public static WebApplication EnsureHealthy(this WebApplication app)
var message = $"Unhealthy services detected: {string.Join(", ", unhealthyChecks)}";
throw new ServiceUnavailableException(message);
}

public static WebApplicationBuilder AddHealthChecks(this WebApplicationBuilder builder)
{
builder.Services.AddHealthChecks();
return builder;
}
}
35 changes: 35 additions & 0 deletions src/SharedKernel/Extensions/SignalRExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;

namespace SharedKernel.Extensions;

public static class SignalRExtensions
{

public static WebApplicationBuilder AddSignalR(this WebApplicationBuilder builder)
{
builder
.Services
.AddSignalR()
.AddMessagePackProtocol();

return builder;
}

public static WebApplicationBuilder AddDistributedSignalR(this WebApplicationBuilder builder, string redisChannelName)
{
builder
.Services
.AddSignalR()
.AddMessagePackProtocol()
.AddStackExchangeRedis(builder.Configuration.GetRedisUrl(),
options =>
{
options.Configuration.ChannelPrefix = RedisChannel.Literal("FinHub:SignalR:");
});


return builder;
}
}
12 changes: 6 additions & 6 deletions src/SharedKernel/Logging/StartupLoggerExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Globalization;
using System.Text.Json;
using Microsoft.AspNetCore.Builder;
using Newtonsoft.Json;

namespace SharedKernel.Logging;

Expand All @@ -11,7 +11,7 @@ public static class StartupLoggerExtensions
public static WebApplicationBuilder LogStartAttempt(this WebApplicationBuilder builder)
{
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
Console.WriteLine(JsonConvert.SerializeObject(new
Console.WriteLine(JsonSerializer.Serialize(new
{
Timestamp = now,
Event = "ApplicationStartAttempt",
Expand All @@ -27,7 +27,7 @@ public static WebApplication LogStartSuccess(this WebApplication app)
.TotalMilliseconds;
var deltaInSeconds = Math.Round(delta / 1000, 2);
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
Console.WriteLine(JsonConvert.SerializeObject(new
Console.WriteLine(JsonSerializer.Serialize(new
{
Timestamp = now,
Event = "ApplicationStartSuccess",
Expand All @@ -40,7 +40,7 @@ public static WebApplicationBuilder LogModuleRegistrationSuccess(this WebApplica
string moduleName)
{
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
Console.WriteLine(JsonConvert.SerializeObject(new
Console.WriteLine(JsonSerializer.Serialize(new
{
Timestamp = now,
Event = "ModuleRegistrationSuccess",
Expand All @@ -52,12 +52,12 @@ public static WebApplicationBuilder LogModuleRegistrationSuccess(this WebApplica
public static WebApplication LogModuleUseSuccess(this WebApplication app, string moduleName)
{
var now = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
Console.WriteLine(JsonConvert.SerializeObject(new
Console.WriteLine(JsonSerializer.Serialize(new
{
Timestamp = now,
Event = "ModuleUseSuccess",
Module = moduleName
}));
return app;
}
}
}
18 changes: 9 additions & 9 deletions src/SharedKernel/SharedKernel.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
<PackageReadmeFile>Readme.md</PackageReadmeFile>
<Authors>Pandatech</Authors>
<Copyright>MIT</Copyright>
<Version>1.0.1</Version>
<Version>1.0.2</Version>
<PackageId>Pandatech.SharedKernel</PackageId>
<Title>Pandatech Shared Kernel Library</Title>
<PackageTags>Pandatech, shared kernel, library, OpenAPI, Swagger, utilities, scalar</PackageTags>
<Description>Pandatech.SharedKernel provides centralized configurations, utilities, and extensions for ASP.NET Core projects. For more information refere to readme.md document.</Description>
<RepositoryUrl>https://github.com/PandaTechAM/be-lib-sharedkernel</RepositoryUrl>
<PackageReleaseNotes>Nuget updates</PackageReleaseNotes>
<PackageReleaseNotes>Added redis and signalR utils</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
Expand All @@ -26,10 +26,14 @@
<PackageReference Include="AspNetCore.HealthChecks.Prometheus.Metrics" Version="8.0.1" />
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="8.0.1" />
<PackageReference Include="Elastic.CommonSchema.Serilog" Version="8.12.2" />
<PackageReference Include="FluentDateTime" Version="3.0.0" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
<PackageReference Include="HtmlSanitizer" Version="8.1.870" />
<PackageReference Include="MediatR" Version="12.4.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" />
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.8.0-rc.1"/>
Expand All @@ -38,18 +42,14 @@
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0"/>
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0"/>
<PackageReference Include="Pandatech.Crypto" Version="4.0.0" />
<PackageReference Include="Pandatech.FluentMinimalApiMapper" Version="2.0.0" />
<PackageReference Include="Pandatech.DistributedCache" Version="3.0.0" />
<PackageReference Include="Pandatech.FluentMinimalApiMapper" Version="2.0.1" />
<PackageReference Include="Pandatech.PandaVaultClient" Version="4.0.0" />
<PackageReference Include="Pandatech.RegexBox" Version="3.0.0" />
<PackageReference Include="Pandatech.ResponseCrafter" Version="4.0.1" />
<PackageReference Include="Pandatech.ResponseCrafter" Version="5.0.1" />
<PackageReference Include="Scalar.AspNetCore" Version="1.2.42" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.0.0" />
</ItemGroup>

<ItemGroup>
<Content Include="wwwroot\**" CopyToOutputDirectory="PreserveNewest" Pack="true" PackagePath="contentFiles\any\any" />
</ItemGroup>


</Project>
16 changes: 10 additions & 6 deletions test/SharedKernel.Demo/Program.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using DistributedCache.Extensions;
using DistributedCache.Options;
using FluentMinimalApiMapper;
using Microsoft.AspNetCore.Mvc;
using SharedKernel.Demo;
Expand All @@ -21,14 +23,15 @@
.AddResponseCrafter(NamingConvention.ToSnakeCase)
.AddOpenApi()
.AddOpenTelemetry()
.AddEndpoints(AssemblyRegistry.ToArray())
.AddMinimalApis(AssemblyRegistry.ToArray())
.AddControllers(AssemblyRegistry.ToArray())
.AddMediatrWithBehaviors(AssemblyRegistry.ToArray())
.AddResilienceDefaultPipeline()
.AddRedis(KeyPrefix.AssemblyNamePrefix)
.AddDistributedSignalR("DistributedSignalR") // or .AddSignalR()
.MapDefaultTimeZone()
.AddCors();

builder.Services.AddHealthChecks();
.AddCors()
.AddHealthChecks();


var app = builder.Build();
Expand All @@ -37,11 +40,12 @@
.UseRequestResponseLogging()
.UseResponseCrafter()
.UseCors()
.MapEndpoints()
.MapMinimalApis()
.MapDefaultEndpoints()
.EnsureHealthy()
.ClearAssemblyRegistry()
.UseOpenApi();
.UseOpenApi()
.MapControllers();

app.MapPost("/params", ([AsParameters] TestTypes testTypes) => TypedResults.Ok(testTypes));
app.MapPost("/body", ([FromBody] TestTypes testTypes) => TypedResults.Ok(testTypes));
Expand Down
1 change: 1 addition & 0 deletions test/SharedKernel.Demo/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"DefaultTimeZone": "Caucasus Standard Time",
"RepositoryName": "be-lib-sharedkernel",
"ConnectionStrings": {
"Redis": "localhost:6379",
"PersistentStorage": "/persistence"
}
}