Skip to content

Commit 5c71b6d

Browse files
Outbox pattern implementation
1 parent aecad94 commit 5c71b6d

45 files changed

Lines changed: 343 additions & 121 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<ImplicitUsings>enable</ImplicitUsings>
55
<Nullable>enable</Nullable>
66
<IsPackable>true</IsPackable>
7-
<Version>2.2.73</Version>
7+
<Version>2.2.88</Version>
88
<Authors>Andrey Serdyuk</Authors>
99
<Company>TaskHub</Company>
1010
<Title>TaskHub.Shared - Reusable Primitives for .NET Microservices</Title>

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ TaskHub.Shared contains the fundamental components and patterns used across all
1919
## Persistence
2020
- **TaskHub.Shared.Persistence.Abstractions** — Interfaces for read/write repositories, unit of work, and persistence contracts.
2121
- **TaskHub.Shared.Persistence.EntityFramework** — EntityFramework Core helpers, base configurations, and interceptors for database integration.
22+
- **TaskHub.Shared.Persistence.Outbox** - Outbox pattern abstractions.
2223
- **TaskHub.Shared.Redis** — Integration with Redis for caching and distributed state management.
23-
- **TaskHub.Shared.Persistence.Outbox** - Outbox pattern implementation for reliable event publishing.
2424

2525
## Authorization
2626
- **TaskHub.Shared.Authorization.Abstractions** — Authorization contracts, roles/permissions abstractions, and policies shared across services.

TaskHub.Observability.Traces/Service/ITracesService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace TaskHub.Observability.Traces.Service;
66

77
public interface ITracesService : IService
88
{
9+
string CorrelationId { get; }
910
Activity? Current { get; }
1011
Activity? StartSpan(string spanName, [CallerMemberName] string caller = "");
1112
Activity? StartSpan<T>(string spanName, T data, [CallerMemberName] string caller = "");

TaskHub.Observability.Traces/Service/TracesService.cs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
using System.Diagnostics;
1+
using Microsoft.AspNetCore.Http;
2+
using Microsoft.Extensions.Primitives;
3+
using System.Diagnostics;
24
using System.Reflection;
35
using System.Runtime.CompilerServices;
46
using TaskHub.Shared.Refactoring.Abstractions;
57

68
namespace TaskHub.Observability.Traces.Service;
79

8-
public sealed class TracesService(ServiceInfo appInfo) : ITracesService
10+
public sealed class TracesService(ServiceInfo appInfo, IHttpContextAccessor http) : ITracesService
911
{
1012
private readonly ActivitySource Source = new(appInfo.Name);
1113

1214
public Activity? Current => Activity.Current;
1315

16+
public string CorrelationId => ResolveCorrelationId();
17+
1418
public Activity? StartSpan(string spanName, [CallerMemberName] string caller = "")
1519
{
1620
var act = Source.StartActivity(spanName, ActivityKind.Internal);
@@ -89,4 +93,32 @@ private static void SetTagTyped(Activity? act, string key, object value)
8993
break;
9094
}
9195
}
92-
}
96+
97+
private static readonly string[] KnownHeaders =
98+
[
99+
"X-Correlation-Id",
100+
"Correlation-Id",
101+
"X-Request-Id",
102+
"Request-Id",
103+
"traceparent",
104+
"uber-trace-id",
105+
"x-b3-traceid",
106+
"x-b3-spanid",
107+
"X-Amzn-Trace-Id",
108+
"X-Cloud-Trace-Context",
109+
];
110+
111+
public string ResolveCorrelationId()
112+
{
113+
foreach (var h in KnownHeaders)
114+
{
115+
if (http.HttpContext.Request.Headers.TryGetValue(h, out var value) && !StringValues.IsNullOrEmpty(value))
116+
{
117+
return value.ToString();
118+
}
119+
}
120+
121+
return Activity.Current?.TraceId.ToString()
122+
?? Guid.NewGuid().ToString();
123+
}
124+
}

TaskHub.Observability.Traces/TaskHub.Observability.Traces.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
<Nullable>enable</Nullable>
1010
</PropertyGroup>
1111

12+
<ItemGroup>
13+
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.3.0" />
14+
</ItemGroup>
15+
1216
<ItemGroup>
1317
<ProjectReference Include="..\TaskHub.Shared.Refactoring.Implementation\TaskHub.Shared.Refactoring.Implementation.csproj" />
1418
<ProjectReference Include="..\TaskHub.Shared.Services.Abstractions\TaskHub.Shared.Services.Abstractions.csproj" />
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
namespace TaskHub.Shared.Authorization.Abstractions;
2+
3+
public interface IGuidUserService : IUserService<Guid>;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
namespace TaskHub.Shared.Authorization.Abstractions;
2+
3+
public interface IIntUserService : IUserService<int>;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
namespace TaskHub.Shared.Authorization.Abstractions;
2+
3+
public interface IStringUserService : IUserService<string>;

TaskHub.Shared.Authorization.Abstractions/IUserService.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
using TaskHub.Shared.Refactoring.Abstractions;
2-
using TaskHub.Shared.Services.Abstractions;
1+
using TaskHub.Shared.Services.Abstractions;
32

43
namespace TaskHub.Shared.Authorization.Abstractions;
54

6-
[Unresolvable]
75
public interface IUserService<T> : IService where T : IEquatable<T>
86
{
97
T UserId { get; }

TaskHub.Shared.Authorization.Identity/Bootstrap/AuthorizationBootsrap.cs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
using Microsoft.AspNetCore.Authentication.JwtBearer;
2-
using Microsoft.AspNetCore.Http;
32
using Microsoft.Extensions.Caching.Distributed;
43
using Microsoft.Extensions.DependencyInjection;
54
using Microsoft.IdentityModel.Tokens;
65
using System.Security.Claims;
76
using TaskHub.Shared.Authorization.Abstractions;
8-
using TaskHub.Shared.Authorization.Identity.Exceptions;
97
using TaskHub.Shared.Authorization.Identity.Options;
108
using TaskHub.Shared.Authorization.Identity.Services;
119

@@ -17,6 +15,11 @@ public static void AddAppAuthorization(this IServiceCollection services, Action<
1715
{
1816
var options = new JwtOptions();
1917
action(options);
18+
services.AddSingleton(options);
19+
services.AddScoped<IGuidUserService, GuidUserService>();
20+
services.AddScoped<IIntUserService, IntUserService>();
21+
services.AddScoped<IGuidUserService, GuidUserService>();
22+
2023
services.AddAuthentication(o =>
2124
{
2225
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
@@ -69,15 +72,4 @@ public static void AddAppAuthorization(this IServiceCollection services, Action<
6972
};
7073
});
7174
}
72-
73-
public static void AddAppUserService<T>(this IServiceCollection services, Func<ClaimsPrincipal, T> resolveUserId)
74-
where T : IEquatable<T>
75-
{
76-
services.AddScoped<IUserService<T>>(sp =>
77-
{
78-
var http = sp.GetRequiredService<IHttpContextAccessor>();
79-
var user = http.HttpContext?.User ?? throw new AuthorizationException("No HttpContext");
80-
return new UserService<T>(resolveUserId(user));
81-
});
82-
}
8375
}

0 commit comments

Comments
 (0)