diff --git a/samples/unobtrusive/Core_10/Client/Client.csproj b/samples/unobtrusive/Core_10/Client/Client.csproj
new file mode 100644
index 00000000000..14df8df95c7
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Client/Client.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net10.0
+ preview
+ Exe
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Client/CommandSender.cs b/samples/unobtrusive/Core_10/Client/CommandSender.cs
new file mode 100644
index 00000000000..0d3971aee86
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Client/CommandSender.cs
@@ -0,0 +1,86 @@
+using Commands;
+using Messages;
+
+public class CommandSender
+{
+ public static async Task Start(IMessageSession messageSession)
+ {
+ Console.WriteLine("Press 'C' to send a command");
+ Console.WriteLine("Press 'R' to send a request");
+ Console.WriteLine("Press 'D' to send a large message that is marked to be sent using data bus");
+ Console.WriteLine("Press 'X' to send a message that is marked with expiration time.");
+ Console.WriteLine("Press any other key to exit");
+
+ while (true)
+ {
+ var key = Console.ReadKey();
+ Console.WriteLine();
+
+ switch (key.Key)
+ {
+ case ConsoleKey.C:
+ await SendCommand(messageSession);
+ continue;
+ case ConsoleKey.R:
+ await SendRequest(messageSession);
+ continue;
+ case ConsoleKey.D:
+ await Data(messageSession);
+ continue;
+ case ConsoleKey.X:
+ await Expiration(messageSession);
+ continue;
+ }
+ return;
+
+ }
+ }
+
+ // Shut down server before sending this message, after 30 seconds, the message will be moved to Transactional dead-letter messages queue.
+ static Task Expiration(IMessageSession messageSession)
+ {
+ var messageThatExpires = new MessageThatExpires
+ {
+ RequestId = Guid.NewGuid()
+ };
+ Console.WriteLine("message with expiration was sent");
+ return messageSession.Send("Samples.Unobtrusive.Server", messageThatExpires);
+ }
+
+ static Task Data(IMessageSession messageSession)
+ {
+ var requestId = Guid.NewGuid();
+
+ var largeMessage = new LargeMessage
+ {
+ RequestId = requestId,
+ LargeDataBus = new byte[1024 * 1024 * 5]
+ };
+ Console.WriteLine($"Request sent id: {requestId}");
+ return messageSession.Send("Samples.Unobtrusive.Server", largeMessage);
+ }
+
+ static Task SendRequest(IMessageSession messageSession)
+ {
+ var requestId = Guid.NewGuid();
+
+ var request = new Request
+ {
+ RequestId = requestId
+ };
+ Console.WriteLine($"Request sent id: {requestId}");
+ return messageSession.Send("Samples.Unobtrusive.Server", request);
+ }
+
+ static Task SendCommand(IMessageSession messageSession)
+ {
+ var commandId = Guid.NewGuid();
+
+ var myCommand = new MyCommand
+ {
+ CommandId = commandId,
+ };
+ Console.WriteLine($"Command sent id: {commandId}");
+ return messageSession.Send("Samples.Unobtrusive.Server", myCommand);
+ }
+}
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Client/InputLoopService.cs b/samples/unobtrusive/Core_10/Client/InputLoopService.cs
new file mode 100644
index 00000000000..e4b98fae8e9
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Client/InputLoopService.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Hosting;
+using NServiceBus.Routing;
+
+namespace Client
+{
+ public class InputLoopService(IMessageSession messageSession) : BackgroundService
+ {
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ await CommandSender.Start(messageSession);
+
+ }
+ }
+}
diff --git a/samples/unobtrusive/Core_10/Client/MyEventHandler.cs b/samples/unobtrusive/Core_10/Client/MyEventHandler.cs
new file mode 100644
index 00000000000..ac8afec0e54
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Client/MyEventHandler.cs
@@ -0,0 +1,11 @@
+using Events;
+using Microsoft.Extensions.Logging;
+
+public class MyEventHandler(ILogger logger) : IHandleMessages
+{
+ public Task Handle(MyEvent message, IMessageHandlerContext context)
+ {
+ logger.LogInformation("MyEvent received from server with id:{EventId}", message.EventId);
+ return Task.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Client/Program.cs b/samples/unobtrusive/Core_10/Client/Program.cs
new file mode 100644
index 00000000000..8a5c0b225d1
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Client/Program.cs
@@ -0,0 +1,20 @@
+using Client;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+Console.Title = "Client";
+var builder = Host.CreateApplicationBuilder(args);
+builder.Services.AddHostedService();
+var endpointConfiguration = new EndpointConfiguration("Samples.Unobtrusive.Client");
+endpointConfiguration.UseSerialization();
+endpointConfiguration.UseTransport(new LearningTransport());
+#pragma warning disable CS0618 // Type or member is obsolete
+var dataBus = endpointConfiguration.UseDataBus();
+dataBus.BasePath(@"..\..\..\..\DataBusShare\");
+#pragma warning restore CS0618 // Type or member is obsolete
+
+endpointConfiguration.ApplyCustomConventions();
+
+builder.UseNServiceBus(endpointConfiguration);
+
+await builder.Build().RunAsync();
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Client/ResponseHandler.cs b/samples/unobtrusive/Core_10/Client/ResponseHandler.cs
new file mode 100644
index 00000000000..fda742d912d
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Client/ResponseHandler.cs
@@ -0,0 +1,11 @@
+using Messages;
+using Microsoft.Extensions.Logging;
+
+public class ResponseHandler(ILogger logger) : IHandleMessages
+{
+ public Task Handle(Response message, IMessageHandlerContext context)
+ {
+ logger.LogInformation("Response received from server for request with id:{ResponseId}", message.ResponseId);
+ return Task.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/ConventionExtensions.cs b/samples/unobtrusive/Core_10/ConventionExtensions.cs
new file mode 100644
index 00000000000..1967efdb1b4
--- /dev/null
+++ b/samples/unobtrusive/Core_10/ConventionExtensions.cs
@@ -0,0 +1,38 @@
+public static class ConventionExtensions
+{
+ #region CustomConvention
+
+ public static void ApplyCustomConventions(this EndpointConfiguration endpointConfiguration)
+ {
+ var conventions = endpointConfiguration.Conventions();
+
+ conventions.DefiningCommandsAs(
+ type =>
+ type.Namespace != null &&
+ type.Namespace.EndsWith("Commands"));
+
+ conventions.DefiningEventsAs(
+ type =>
+ type.Namespace != null &&
+ type.Namespace.EndsWith("Events"));
+
+ conventions.DefiningMessagesAs(
+ type => type.Namespace == "Messages");
+#pragma warning disable CS0618 // Type or member is obsolete
+ conventions.DefiningDataBusPropertiesAs(
+ property => property.Name.EndsWith("DataBus"));
+#pragma warning restore CS0618 // Type or member is obsolete
+
+ conventions.DefiningTimeToBeReceivedAs(
+ type =>
+ {
+ if (type.Name.EndsWith("Expires"))
+ {
+ return TimeSpan.FromSeconds(30);
+ }
+ return TimeSpan.MaxValue;
+ });
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Server/CommandSender.cs b/samples/unobtrusive/Core_10/Server/CommandSender.cs
new file mode 100644
index 00000000000..faa62b6f4a4
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Server/CommandSender.cs
@@ -0,0 +1,36 @@
+using Events;
+
+class CommandSender
+{
+ public static async Task Start(IMessageSession messageSession)
+ {
+ Console.WriteLine("Press 'E' to publish an event");
+ Console.WriteLine("Press any other key to exit");
+
+ while (true)
+ {
+ var key = Console.ReadKey();
+ Console.WriteLine();
+
+ switch (key.Key)
+ {
+ case ConsoleKey.E:
+ await PublishEvent(messageSession);
+ continue;
+ }
+ return;
+ }
+ }
+
+ static Task PublishEvent(IMessageSession messageSession)
+ {
+ var eventId = Guid.NewGuid();
+
+ Console.WriteLine($"Event published, id: {eventId}");
+ var myEvent = new MyEvent
+ {
+ EventId = eventId
+ };
+ return messageSession.Publish(myEvent);
+ }
+}
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Server/InputLoopService.cs b/samples/unobtrusive/Core_10/Server/InputLoopService.cs
new file mode 100644
index 00000000000..0ce3dea9e94
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Server/InputLoopService.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Hosting;
+
+namespace Server
+{
+ public class InputLoopService(IMessageSession messageSession) : BackgroundService
+ {
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ await CommandSender.Start(messageSession);
+ }
+ }
+}
diff --git a/samples/unobtrusive/Core_10/Server/LargeMessageHandler.cs b/samples/unobtrusive/Core_10/Server/LargeMessageHandler.cs
new file mode 100644
index 00000000000..eba77ce2413
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Server/LargeMessageHandler.cs
@@ -0,0 +1,18 @@
+using Messages;
+using Microsoft.Extensions.Logging;
+
+public class LargeMessageHandler(ILogger logger) : IHandleMessages
+{
+ public Task Handle(LargeMessage message, IMessageHandlerContext context)
+ {
+ if (message.LargeDataBus == null)
+ {
+ logger.LogInformation("Message [{MessageType}] received, id:{RequestId}", message.GetType(), message.RequestId);
+ }
+ else
+ {
+ logger.LogInformation("Message [{MessageType}] received, id:{RequestId} and payload {PayloadLength} bytes", message.GetType(), message.RequestId, message.LargeDataBus.Length);
+ }
+ return Task.CompletedTask;
+ }
+}
diff --git a/samples/unobtrusive/Core_10/Server/MessageThatExpiresHandler.cs b/samples/unobtrusive/Core_10/Server/MessageThatExpiresHandler.cs
new file mode 100644
index 00000000000..1ae9e2bc11e
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Server/MessageThatExpiresHandler.cs
@@ -0,0 +1,12 @@
+using Messages;
+using Microsoft.Extensions.Logging;
+
+public class MessageThatExpiresHandler(ILogger logger) : IHandleMessages
+{
+
+ public Task Handle(MessageThatExpires message, IMessageHandlerContext context)
+ {
+ logger.LogInformation("Message [{MessageType}] received, id: [{RequestId}]", message.GetType(), message.RequestId);
+ return Task.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Server/MyCommandHandler.cs b/samples/unobtrusive/Core_10/Server/MyCommandHandler.cs
new file mode 100644
index 00000000000..f9adf73e4f3
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Server/MyCommandHandler.cs
@@ -0,0 +1,11 @@
+using Commands;
+using Microsoft.Extensions.Logging;
+
+public class MyCommandHandler(ILogger logger) : IHandleMessages
+{
+ public Task Handle(MyCommand message, IMessageHandlerContext context)
+ {
+ logger.LogInformation("Command received, id:{CommandId}", message.CommandId);
+ return Task.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Server/Program.cs b/samples/unobtrusive/Core_10/Server/Program.cs
new file mode 100644
index 00000000000..06ea8e86d66
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Server/Program.cs
@@ -0,0 +1,21 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Server;
+
+Console.Title = "Server";
+var builder = Host.CreateApplicationBuilder(args);
+builder.Services.AddHostedService();
+
+var endpointConfiguration = new EndpointConfiguration("Samples.Unobtrusive.Server");
+endpointConfiguration.UseSerialization();
+endpointConfiguration.UseTransport(new LearningTransport());
+#pragma warning disable CS0618 // Type or member is obsolete
+endpointConfiguration.UseDataBus()
+ .BasePath(@"..\..\..\..\DataBusShare\");
+#pragma warning restore CS0618 // Type or member is obsolete
+
+endpointConfiguration.ApplyCustomConventions();
+
+builder.UseNServiceBus(endpointConfiguration);
+
+await builder.Build().RunAsync();
diff --git a/samples/unobtrusive/Core_10/Server/RequestMessageHandler.cs b/samples/unobtrusive/Core_10/Server/RequestMessageHandler.cs
new file mode 100644
index 00000000000..f9984928311
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Server/RequestMessageHandler.cs
@@ -0,0 +1,15 @@
+using Messages;
+using Microsoft.Extensions.Logging;
+public class RequestMessageHandler(ILogger logger) : IHandleMessages
+{
+ public Task Handle(Request message, IMessageHandlerContext context)
+ {
+ logger.LogInformation("Request received with id:{RequestId}", message.RequestId);
+
+ var response = new Response
+ {
+ ResponseId = message.RequestId
+ };
+ return context.Reply(response);
+ }
+}
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Server/Server.csproj b/samples/unobtrusive/Core_10/Server/Server.csproj
new file mode 100644
index 00000000000..e8f718d6336
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Server/Server.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net10.0
+ preview
+ Exe
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Shared/LargeMessage.cs b/samples/unobtrusive/Core_10/Shared/LargeMessage.cs
new file mode 100644
index 00000000000..5d40788e982
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Shared/LargeMessage.cs
@@ -0,0 +1,10 @@
+namespace Messages;
+
+using System;
+
+public class LargeMessage
+{
+ public Guid RequestId { get; set; }
+
+ public byte[]? LargeDataBus { get; set; }
+}
diff --git a/samples/unobtrusive/Core_10/Shared/MessageThatExpires.cs b/samples/unobtrusive/Core_10/Shared/MessageThatExpires.cs
new file mode 100644
index 00000000000..75d589a6583
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Shared/MessageThatExpires.cs
@@ -0,0 +1,8 @@
+namespace Messages;
+
+using System;
+
+public class MessageThatExpires
+{
+ public Guid RequestId { get; set; }
+}
diff --git a/samples/unobtrusive/Core_10/Shared/MyCommand.cs b/samples/unobtrusive/Core_10/Shared/MyCommand.cs
new file mode 100644
index 00000000000..ca9fdfd028f
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Shared/MyCommand.cs
@@ -0,0 +1,8 @@
+namespace Commands;
+
+using System;
+
+public class MyCommand
+{
+ public Guid CommandId { get; set; }
+}
diff --git a/samples/unobtrusive/Core_10/Shared/MyEvent.cs b/samples/unobtrusive/Core_10/Shared/MyEvent.cs
new file mode 100644
index 00000000000..a34d1bdd8e2
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Shared/MyEvent.cs
@@ -0,0 +1,8 @@
+namespace Events;
+
+using System;
+
+public class MyEvent
+{
+ public Guid EventId { get; set; }
+}
diff --git a/samples/unobtrusive/Core_10/Shared/Request.cs b/samples/unobtrusive/Core_10/Shared/Request.cs
new file mode 100644
index 00000000000..4d57e5960cc
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Shared/Request.cs
@@ -0,0 +1,8 @@
+namespace Messages;
+
+using System;
+
+public class Request
+{
+ public Guid RequestId { get; set; }
+}
diff --git a/samples/unobtrusive/Core_10/Shared/Response.cs b/samples/unobtrusive/Core_10/Shared/Response.cs
new file mode 100644
index 00000000000..e746c5e9f00
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Shared/Response.cs
@@ -0,0 +1,8 @@
+namespace Messages;
+
+using System;
+
+public class Response
+{
+ public Guid ResponseId { get; set; }
+}
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Shared/Shared.csproj b/samples/unobtrusive/Core_10/Shared/Shared.csproj
new file mode 100644
index 00000000000..fb02879bdbf
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Shared/Shared.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net10.0
+ preview
+ enable
+ enable
+
+
+
\ No newline at end of file
diff --git a/samples/unobtrusive/Core_10/Unobtrusive.sln b/samples/unobtrusive/Core_10/Unobtrusive.sln
new file mode 100644
index 00000000000..a243791955e
--- /dev/null
+++ b/samples/unobtrusive/Core_10/Unobtrusive.sln
@@ -0,0 +1,29 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29728.190
+MinimumVisualStudioVersion = 15.0.26730.12
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{476D0A88-E281-4BC8-9617-93E53C1F9FE6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{75424F0A-458B-42DA-9DDD-600367893A93}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{DD0DC12D-D6DF-47C0-B75A-AEC351164196}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {476D0A88-E281-4BC8-9617-93E53C1F9FE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {476D0A88-E281-4BC8-9617-93E53C1F9FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {75424F0A-458B-42DA-9DDD-600367893A93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {75424F0A-458B-42DA-9DDD-600367893A93}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DD0DC12D-D6DF-47C0-B75A-AEC351164196}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DD0DC12D-D6DF-47C0-B75A-AEC351164196}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {9FC8A922-FADC-447B-BA38-9F47C3FBB51C}
+ EndGlobalSection
+EndGlobal
diff --git a/samples/unobtrusive/Core_10/prerelease.txt b/samples/unobtrusive/Core_10/prerelease.txt
new file mode 100644
index 00000000000..e69de29bb2d