Skip to content

Commit d5e3ceb

Browse files
authored
Username-header sample to .net 10 (#7493)
1 parent fd475d5 commit d5e3ceb

File tree

13 files changed

+304
-0
lines changed

13 files changed

+304
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net10.0</TargetFramework>
4+
<LangVersion>preview</LangVersion>
5+
<OutputType>Exe</OutputType>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
<ItemGroup>
9+
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="4.0.0-alpha.1" />
10+
</ItemGroup>
11+
<ItemGroup>
12+
<ProjectReference Include="..\Shared\Shared.csproj" />
13+
</ItemGroup>
14+
</Project>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Security.Principal;
3+
using System.Threading.Tasks;
4+
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.Hosting;
6+
using Microsoft.Extensions.Logging;
7+
using NServiceBus;
8+
using NServiceBus.MessageMutator;
9+
10+
11+
var principalAccessor = new PrincipalAccessor();
12+
13+
var builder = Host.CreateApplicationBuilder(args);
14+
var host = Host.CreateDefaultBuilder(args)
15+
.UseNServiceBus(x =>
16+
{
17+
var endpointConfiguration = new EndpointConfiguration("Samples.UsernameHeader.Endpoint1");
18+
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
19+
endpointConfiguration.UseTransport(new LearningTransport());
20+
21+
22+
#region component-registration-sender
23+
24+
builder.Services.AddSingleton<IPrincipalAccessor>(principalAccessor);
25+
var serviceProvider = builder.Services.BuildServiceProvider();
26+
27+
var logger = serviceProvider.GetRequiredService<ILogger<AddUserNameToOutgoingHeadersMutator>>();
28+
var mutator = new AddUserNameToOutgoingHeadersMutator(principalAccessor, logger);
29+
endpointConfiguration.RegisterMessageMutator(mutator);
30+
31+
#endregion
32+
return endpointConfiguration;
33+
}).Build();
34+
35+
36+
await host.StartAsync();
37+
38+
39+
#region send-message
40+
41+
async Task SendMessage(int userNumber)
42+
{
43+
var identity = new GenericIdentity($"FakeUser{userNumber}");
44+
principalAccessor.CurrentPrincipal = new GenericPrincipal(identity, new string[0]);
45+
46+
var messageSession = host.Services.GetRequiredService<IMessageSession>();
47+
48+
var message = new MyMessage();
49+
await messageSession.Send("Samples.UsernameHeader.Endpoint2", message);
50+
}
51+
52+
await Task.WhenAll(SendMessage(1), SendMessage(2));
53+
54+
#endregion
55+
56+
Console.WriteLine("Message sent. Press any key to exit");
57+
Console.ReadKey();
58+
59+
await host.StopAsync();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net10.0</TargetFramework>
4+
<LangVersion>preview</LangVersion>
5+
<OutputType>Exe</OutputType>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
<ItemGroup>
9+
<PackageReference Include="NServiceBus.Extensions.Hosting" Version="4.0.0-alpha.1" />
10+
</ItemGroup>
11+
<ItemGroup>
12+
<ProjectReference Include="..\Shared\Shared.csproj" />
13+
</ItemGroup>
14+
</Project>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System.Threading.Tasks;
2+
using Microsoft.Extensions.Logging;
3+
using NServiceBus;
4+
5+
#region handler-using-custom-header
6+
7+
public class HandlerUsingAccessor :
8+
IHandleMessages<MyMessage>
9+
{
10+
readonly IPrincipalAccessor principalAccessor;
11+
private readonly ILogger<HandlerUsingAccessor> logger;
12+
13+
public HandlerUsingAccessor(IPrincipalAccessor principalAccessor, ILogger<HandlerUsingAccessor> logger)
14+
{
15+
this.principalAccessor = principalAccessor;
16+
this.logger = logger;
17+
}
18+
19+
public Task Handle(MyMessage message, IMessageHandlerContext context)
20+
{
21+
var headers = context.MessageHeaders;
22+
var usernameFromHeader = headers["UserName"];
23+
var usernameFromAccessor = principalAccessor?.CurrentPrincipal?.Identity?.Name ?? "null";
24+
logger.LogInformation("Username extracted from header: {UsernameFromHeader}", usernameFromHeader);
25+
logger.LogInformation("Username extracted from accessor: {UsernameFromAccessor}", usernameFromAccessor);
26+
return Task.CompletedTask;
27+
}
28+
}
29+
30+
#endregion
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Hosting;
4+
using NServiceBus;
5+
using NServiceBus.MessageMutator;
6+
7+
Console.Title = "Endpoint2";
8+
9+
var builder = Host.CreateApplicationBuilder(args);
10+
11+
var endpointConfiguration = new EndpointConfiguration("Samples.UsernameHeader.Endpoint2");
12+
endpointConfiguration.UseSerialization<SystemJsonSerializer>();
13+
endpointConfiguration.UseTransport(new LearningTransport());
14+
15+
#region component-registration-receiver
16+
// Register both services
17+
builder.Services.AddSingleton<IPrincipalAccessor, PrincipalAccessor>();
18+
builder.Services.AddSingleton<SetCurrentPrincipalBasedOnHeaderMutator>();
19+
20+
var serviceProvider = builder.Services.BuildServiceProvider();
21+
var principalAccessor = serviceProvider.GetRequiredService<IPrincipalAccessor>(); // Use the interface type here
22+
var mutator = serviceProvider.GetRequiredService<SetCurrentPrincipalBasedOnHeaderMutator>();
23+
24+
endpointConfiguration.RegisterMessageMutator(mutator);
25+
26+
endpointConfiguration.RegisterComponents(c =>
27+
{
28+
//Register the accessor in the container so that the handler can access it
29+
c.AddSingleton<IPrincipalAccessor>(principalAccessor);
30+
});
31+
32+
#endregion
33+
34+
builder.UseNServiceBus(endpointConfiguration);
35+
await builder.Build().RunAsync();
36+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.Threading.Tasks;
2+
using Microsoft.Extensions.Logging;
3+
using NServiceBus.MessageMutator;
4+
5+
#region username-header-mutator
6+
7+
public class AddUserNameToOutgoingHeadersMutator:
8+
IMutateOutgoingTransportMessages
9+
{
10+
readonly IPrincipalAccessor principalAccessor;
11+
private readonly ILogger<AddUserNameToOutgoingHeadersMutator> logger;
12+
13+
public AddUserNameToOutgoingHeadersMutator(IPrincipalAccessor principalAccessor, ILogger<AddUserNameToOutgoingHeadersMutator> logger)
14+
{
15+
this.principalAccessor = principalAccessor;
16+
this.logger = logger;
17+
}
18+
19+
public Task MutateOutgoing(MutateOutgoingTransportMessageContext context)
20+
{
21+
if (principalAccessor.CurrentPrincipal?.Identity.Name != null)
22+
{
23+
24+
logger.LogInformation("Adding CurrentPrincipal user to headers");
25+
context.OutgoingHeaders["UserName"] = principalAccessor.CurrentPrincipal.Identity.Name;
26+
}
27+
28+
return Task.CompletedTask;
29+
}
30+
}
31+
32+
#endregion
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
using System.Security.Principal;
2+
3+
public interface IPrincipalAccessor
4+
{
5+
IPrincipal CurrentPrincipal { get; set; }
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
using NServiceBus;
2+
3+
public class MyMessage :
4+
IMessage
5+
{
6+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Security.Principal;
2+
using System.Threading;
3+
4+
public class PrincipalAccessor : IPrincipalAccessor
5+
{
6+
AsyncLocal<CurrentPrincipalHolder> principalCurrent = new AsyncLocal<CurrentPrincipalHolder>();
7+
8+
public IPrincipal CurrentPrincipal
9+
{
10+
get
11+
{
12+
return principalCurrent.Value?.CurrentPrincipal;
13+
}
14+
set
15+
{
16+
var holder = principalCurrent.Value;
17+
if (holder != null)
18+
{
19+
// Clear current IPrincipal trapped in the AsyncLocals, as its done.
20+
holder.CurrentPrincipal = null;
21+
}
22+
23+
if (value != null)
24+
{
25+
// Use an object indirection to hold the IPrincipal in the AsyncLocal,
26+
// so it can be cleared in all ExecutionContexts when its cleared.
27+
principalCurrent.Value = new CurrentPrincipalHolder { CurrentPrincipal = value };
28+
}
29+
}
30+
}
31+
32+
class CurrentPrincipalHolder
33+
{
34+
public IPrincipal CurrentPrincipal;
35+
}
36+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.Security.Principal;
2+
using System.Threading.Tasks;
3+
using Microsoft.Extensions.Logging;
4+
using NServiceBus.MessageMutator;
5+
6+
#region set-principal-from-header-mutator
7+
public class SetCurrentPrincipalBasedOnHeaderMutator :
8+
IMutateIncomingTransportMessages
9+
{
10+
11+
readonly IPrincipalAccessor principalAccessor;
12+
private readonly ILogger<SetCurrentPrincipalBasedOnHeaderMutator> logger;
13+
14+
public SetCurrentPrincipalBasedOnHeaderMutator(IPrincipalAccessor principalAccessor, ILogger<SetCurrentPrincipalBasedOnHeaderMutator> logger)
15+
{
16+
this.principalAccessor = principalAccessor;
17+
this.logger = logger;
18+
}
19+
20+
public Task MutateIncoming(MutateIncomingTransportMessageContext context)
21+
{
22+
if (context.Headers.TryGetValue("UserName", out var userNameHeader))
23+
{
24+
logger.LogInformation("Adding CurrentPrincipal user from headers");
25+
var identity = new GenericIdentity(userNameHeader);
26+
principalAccessor.CurrentPrincipal = new GenericPrincipal(identity, new string[0]);
27+
}
28+
29+
return Task.CompletedTask;
30+
}
31+
}
32+
#endregion

0 commit comments

Comments
 (0)