(feature): MaksIT.Core lib usage

This commit is contained in:
Maksym Sadovnychyy 2025-11-01 20:09:49 +01:00
parent 4679300a64
commit 399415c6b8
13 changed files with 11 additions and 288 deletions

View File

@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>MaksIT.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Abstractions\**" />
<EmbeddedResource Remove="Abstractions\**" />
<None Remove="Abstractions\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.9" />
<PackageReference Include="System.Threading.RateLimiting" Version="9.0.9" />
</ItemGroup>
</Project>

View File

@ -1,36 +0,0 @@
using System.Text.Json.Serialization;
using System.Text.Json;
namespace MaksIT.Core.Extensions;
public static class ObjectExtensions {
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static string ToJson<T>(this T? obj) => obj.ToJson(null);
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <param name="converters"></param>
/// <returns></returns>
public static string ToJson<T>(this T? obj, List<JsonConverter>? converters) {
if (obj == null)
return "{}";
var options = new JsonSerializerOptions {
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = true
};
converters?.ForEach(x => options.Converters.Add(x));
return JsonSerializer.Serialize(obj, options);
}
}

View File

@ -1,55 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
namespace MaksIT.Core.Extensions;
public static class StringExtensions {
/// <summary>
/// Converts JSON string to object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="s"></param>
/// <returns></returns>
public static T? ToObject<T>(this string? s) => ToObjectCore<T>(s, null);
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="s"></param>
/// <param name="converters"></param>
/// <returns></returns>
public static T? ToObject<T>(this string? s, List<JsonConverter> converters) => ToObjectCore<T>(s, converters);
private static T? ToObjectCore<T>(string? s, List<JsonConverter>? converters) {
var options = new JsonSerializerOptions {
PropertyNameCaseInsensitive = true
};
converters?.ForEach(x => options.Converters.Add(x));
return s != null
? JsonSerializer.Deserialize<T>(s, options)
: default;
}
public static Guid? ToNullabeGuid(this string? s) {
if (Guid.TryParse(s, out var result)) {
return result;
}
return null;
}
public static Guid ToGuid(this string s) {
if (Guid.TryParse(s, out var result)) {
return result;
}
return Guid.Empty;
}
}

View File

@ -1,93 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Threading.RateLimiting;
public class LockManager : IDisposable {
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly ConcurrentDictionary<int, int> _reentrantCounts = new ConcurrentDictionary<int, int>();
private readonly TokenBucketRateLimiter _rateLimiter = new TokenBucketRateLimiter(new TokenBucketRateLimiterOptions {
TokenLimit = 5, // max 5 requests per second (adjust as needed)
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = 100,
ReplenishmentPeriod = TimeSpan.FromSeconds(1),
TokensPerPeriod = 5,
AutoReplenishment = true
});
public async Task<T> ExecuteWithLockAsync<T>(Func<Task<T>> action) {
var lease = await _rateLimiter.AcquireAsync(1);
if (!lease.IsAcquired) throw new InvalidOperationException("Rate limit exceeded");
var threadId = Thread.CurrentThread.ManagedThreadId;
if (!_reentrantCounts.ContainsKey(threadId)) _reentrantCounts[threadId] = 0;
if (_reentrantCounts[threadId] == 0) await _semaphore.WaitAsync();
_reentrantCounts[threadId]++;
try {
return await action();
}
finally {
_reentrantCounts[threadId]--;
if (_reentrantCounts[threadId] == 0) _semaphore.Release();
lease.Dispose();
}
}
public async Task ExecuteWithLockAsync(Func<Task> action) {
var lease = await _rateLimiter.AcquireAsync(1);
if (!lease.IsAcquired) throw new InvalidOperationException("Rate limit exceeded");
var threadId = Thread.CurrentThread.ManagedThreadId;
if (!_reentrantCounts.ContainsKey(threadId)) _reentrantCounts[threadId] = 0;
if (_reentrantCounts[threadId] == 0) await _semaphore.WaitAsync();
_reentrantCounts[threadId]++;
try {
await action();
}
finally {
_reentrantCounts[threadId]--;
if (_reentrantCounts[threadId] == 0) _semaphore.Release();
lease.Dispose();
}
}
public async Task<T> ExecuteWithLockAsync<T>(Func<T> action) {
var lease = await _rateLimiter.AcquireAsync(1);
if (!lease.IsAcquired) throw new InvalidOperationException("Rate limit exceeded");
var threadId = Thread.CurrentThread.ManagedThreadId;
if (!_reentrantCounts.ContainsKey(threadId)) _reentrantCounts[threadId] = 0;
if (_reentrantCounts[threadId] == 0) await _semaphore.WaitAsync();
_reentrantCounts[threadId]++;
try {
return await Task.Run(action);
}
finally {
_reentrantCounts[threadId]--;
if (_reentrantCounts[threadId] == 0) _semaphore.Release();
lease.Dispose();
}
}
public async Task ExecuteWithLockAsync(Action action) {
var lease = await _rateLimiter.AcquireAsync(1);
if (!lease.IsAcquired) throw new InvalidOperationException("Rate limit exceeded");
var threadId = Thread.CurrentThread.ManagedThreadId;
if (!_reentrantCounts.ContainsKey(threadId)) _reentrantCounts[threadId] = 0;
if (_reentrantCounts[threadId] == 0) await _semaphore.WaitAsync();
_reentrantCounts[threadId]++;
try {
await Task.Run(action);
}
finally {
_reentrantCounts[threadId]--;
if (_reentrantCounts[threadId] == 0) _semaphore.Release();
lease.Dispose();
}
}
public void Dispose() {
_semaphore.Dispose();
_rateLimiter.Dispose();
}
}

View File

@ -1,24 +0,0 @@

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MaksIT.Core.Logger;
public class MyCustomLogger : ILogger {
public IDisposable? BeginScope<TState>(TState state) where TState : notnull {
throw new NotImplementedException();
}
public bool IsEnabled(LogLevel logLevel) {
throw new NotImplementedException();
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter) {
throw new NotImplementedException();
}
}

View File

@ -1,19 +0,0 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MaksIT.Core.Logger;
public class MyCustomLoggerProvider : ILoggerProvider {
public ILogger CreateLogger(string categoryName) {
throw new NotImplementedException();
}
public void Dispose() {
throw new NotImplementedException();
}
}

View File

@ -1,8 +0,0 @@
using Microsoft.Extensions.Logging;
namespace MaksIT.Core.Logger;
public static class MyCustomLoggerExtensions {
}

View File

@ -1,13 +0,0 @@
using System.Runtime.InteropServices;
namespace MaksIT.Core;
public static class OperatingSystem {
public static bool IsWindows() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
public static bool IsMacOS() =>
RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
public static bool IsLinux() =>
RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
}

View File

@ -5,8 +5,6 @@ VisualStudioVersion = 17.6.33815.320
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LetsEncrypt", "LetsEncrypt\LetsEncrypt.csproj", "{7DE431E5-889C-434E-AD02-9F89D7A0ED27}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LetsEncrypt", "LetsEncrypt\LetsEncrypt.csproj", "{7DE431E5-889C-434E-AD02-9F89D7A0ED27}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "Core\Core.csproj", "{27A58A5F-B52A-44F2-9639-84C6F02EA75D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3374FDB1-C95E-4103-8E14-5BBF0BDC4E9D}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3374FDB1-C95E-4103-8E14-5BBF0BDC4E9D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LetsEncryptServer", "LetsEncryptServer\LetsEncryptServer.csproj", "{B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LetsEncryptServer", "LetsEncryptServer\LetsEncryptServer.csproj", "{B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}"
@ -29,10 +27,6 @@ Global
{7DE431E5-889C-434E-AD02-9F89D7A0ED27}.Debug|Any CPU.Build.0 = Debug|Any CPU {7DE431E5-889C-434E-AD02-9F89D7A0ED27}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7DE431E5-889C-434E-AD02-9F89D7A0ED27}.Release|Any CPU.ActiveCfg = Release|Any CPU {7DE431E5-889C-434E-AD02-9F89D7A0ED27}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7DE431E5-889C-434E-AD02-9F89D7A0ED27}.Release|Any CPU.Build.0 = Release|Any CPU {7DE431E5-889C-434E-AD02-9F89D7A0ED27}.Release|Any CPU.Build.0 = Release|Any CPU
{27A58A5F-B52A-44F2-9639-84C6F02EA75D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{27A58A5F-B52A-44F2-9639-84C6F02EA75D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{27A58A5F-B52A-44F2-9639-84C6F02EA75D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{27A58A5F-B52A-44F2-9639-84C6F02EA75D}.Release|Any CPU.Build.0 = Release|Any CPU
{B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}.Debug|Any CPU.Build.0 = Debug|Any CPU {B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}.Release|Any CPU.ActiveCfg = Release|Any CPU {B5F39E04-C2E3-49BF-82C2-9DEBAA949E3D}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@ -8,16 +8,13 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MaksIT.Results" Version="1.0.6" /> <PackageReference Include="MaksIT.Core" Version="1.5.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.9" /> <PackageReference Include="MaksIT.Results" Version="1.0.9" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.9" /> <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.9" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.9" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.9" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.10" />
</ItemGroup> <PackageReference Include="Microsoft.Extensions.Http" Version="9.0.10" />
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -9,8 +9,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MaksIT.Results" Version="1.0.6" /> <PackageReference Include="MaksIT.Results" Version="1.0.9" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.9" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.6" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.6" />
</ItemGroup> </ItemGroup>

View File

@ -2,6 +2,7 @@
using MaksIT.Core.Extensions; using MaksIT.Core.Extensions;
using MaksIT.Core.Threading;
using MaksIT.LetsEncrypt.Entities; using MaksIT.LetsEncrypt.Entities;
using MaksIT.Results; using MaksIT.Results;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;

View File

@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Extensions" Version="9.0.9" /> <PackageReference Include="Microsoft.AspNetCore.DataProtection.Extensions" Version="9.0.10" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
<PackageReference Include="Yarp.ReverseProxy" Version="2.3.0" /> <PackageReference Include="Yarp.ReverseProxy" Version="2.3.0" />
</ItemGroup> </ItemGroup>