Skip to content
Open
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
15 changes: 15 additions & 0 deletions Motor.NET.sln
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsumeWithRabbitMQAndDeadL
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Motor.Extensions.Diagnostics.Telemetry_IntegrationTest", "test\Motor.Extensions.Diagnostics.Telemetry_IntegrationTest\Motor.Extensions.Diagnostics.Telemetry_IntegrationTest.csproj", "{976B6FB8-CEB0-4544-A22F-3CF78348E43B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PublishToMultipleQueuesRabbitMQ", "examples\PublishToMultipleQueuesRabbitMQ\PublishToMultipleQueuesRabbitMQ.csproj", "{D2028002-1122-4F4B-9F38-E328FE4B8501}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -854,6 +856,18 @@ Global
{976B6FB8-CEB0-4544-A22F-3CF78348E43B}.Release|x64.Build.0 = Release|Any CPU
{976B6FB8-CEB0-4544-A22F-3CF78348E43B}.Release|x86.ActiveCfg = Release|Any CPU
{976B6FB8-CEB0-4544-A22F-3CF78348E43B}.Release|x86.Build.0 = Release|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Debug|x64.ActiveCfg = Debug|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Debug|x64.Build.0 = Debug|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Debug|x86.ActiveCfg = Debug|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Debug|x86.Build.0 = Debug|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Release|Any CPU.Build.0 = Release|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Release|x64.ActiveCfg = Release|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Release|x64.Build.0 = Release|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Release|x86.ActiveCfg = Release|Any CPU
{D2028002-1122-4F4B-9F38-E328FE4B8501}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -918,6 +932,7 @@ Global
{0896B5BC-CA32-40E6-A7CF-E9EF288C0C81} = {749B1421-3177-4C7A-A66B-541BD4E925B0}
{142BFD82-3C48-4E9A-9F9C-BF7401E057B4} = {3DC7D216-6908-4759-B86F-759FDAE393D9}
{976B6FB8-CEB0-4544-A22F-3CF78348E43B} = {ADD2EBBA-A839-4E4A-9253-CDE29A372F07}
{D2028002-1122-4F4B-9F38-E328FE4B8501} = {3DC7D216-6908-4759-B86F-759FDAE393D9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5E91C34C-3AEC-4084-BA02-753C9236AA34}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace PublishToMultipleQueuesRabbitMQ.Model;

public record InputMessage
{
public string FancyText { get; set; } = "FooBar";
public int FancyNumber { get; set; } = 42;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace PublishToMultipleQueuesRabbitMQ.Model;

// Since we send the same data to the queue, we can use a baseclass with the actual
// values, but still need to define an individual type for the queue.
public record LeftMessage : OutputMessage
{
// Or add additional data here.
public string Left { get; set; } = "Left";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace PublishToMultipleQueuesRabbitMQ.Model;

public record OutputMessage
{
public string NotSoFancyText { get; set; }
public int NotSoFancyNumber { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace PublishToMultipleQueuesRabbitMQ.Model;

// Since we send the same data to the queue, we can use a baseclass with the actual
// values, but still need to define an individual type for the queue.
public record RightMessage : OutputMessage
{
// Or add additional data here.
}
68 changes: 68 additions & 0 deletions examples/PublishToMultipleQueuesRabbitMQ/NoOutputService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Motor.Extensions.Hosting.Abstractions;
using Motor.Extensions.Hosting.CloudEvents;
using PublishToMultipleQueuesRabbitMQ.Model;

namespace PublishToMultipleQueuesRabbitMQ;

public class NoOutputService(
ITypedMessagePublisher<LeftMessage> leftPublisher,
ITypedMessagePublisher<RightMessage> rightPublisher)
: INoOutputService<InputMessage>
{
// Handle incoming messages
private static int _messageCount = 0;

public Task<ProcessedMessageStatus> HandleMessageAsync(MotorCloudEvent<InputMessage> inputEvent, CancellationToken token = default)
{
// Get the input message from the cloud event
var input = inputEvent.TypedData;

// Sometimes we dont have anything to publish.
if (string.IsNullOrEmpty(input.FancyText))
{
// Might need to be logged, or published to some additional queue, or can simply be ignored.
return Task.FromResult(ProcessedMessageStatus.Success);
}

_messageCount++;

// In all other cases we publish to the queue dictated by our business logic.
if (_messageCount % 2 == 0)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm finally working on Motor.NET again and I just noticed that the static code analysis fails.

I don't know if the error is visible to you, but Codacy complains about accessing a static variable from a non-static context. That may be a bit nitpicky, but alternatively, you could just flip a coin to decide which publisher gets the message. That would still show the purpose of the example.

{
var left = CreateLeftMessage(input);
leftPublisher.PublishMessageAsync(inputEvent.CreateNew(left), token);
}
else
{
var right = CreateRightMessage(input);
rightPublisher.PublishMessageAsync(inputEvent.CreateNew(right), token);
}

return Task.FromResult(ProcessedMessageStatus.Success);
}

private static LeftMessage CreateLeftMessage(InputMessage input)
{
var output = new LeftMessage
{
NotSoFancyText = input.FancyText.Reverse().ToString(),
NotSoFancyNumber = input.FancyNumber * -1,
};
return output;
}

private static RightMessage CreateRightMessage(InputMessage input)
{
var output = new RightMessage
{
NotSoFancyText = input.FancyText + " " + DateTime.Now,
NotSoFancyNumber = input.FancyNumber * 3,
};

return output;
}
}
72 changes: 72 additions & 0 deletions examples/PublishToMultipleQueuesRabbitMQ/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using PublishToMultipleQueuesRabbitMQ.Model;
using PublishToMultipleQueuesRabbitMQ;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Motor.Extensions.ContentEncoding.Gzip;
using Motor.Extensions.Conversion.SystemJson;
using Motor.Extensions.Hosting.Abstractions;
using Motor.Extensions.Hosting.Consumer;
using Motor.Extensions.Hosting.Publisher;
using Motor.Extensions.Hosting.RabbitMQ;
using Motor.Extensions.Utilities;

await MotorHost.CreateDefaultBuilder()
// Configure the types of the input message
.ConfigureNoOutputService<InputMessage>()
.ConfigureServices((_, services) =>
{
// Add a handler for the input message. this handler is a INoOutputService
// because we would have to specify the output type here, which we can't because
// the handler wants to send to different queues, depending on the incoming
// message data and its associated business logic.
// This handler is called for every new incoming message.
services.AddTransient<INoOutputService<InputMessage>, NoOutputService>();
})
// Add the incoming communication modules.
.ConfigureConsumer<InputMessage>((_, builder) =>
{
// In this case the messages are received from RabbitMQ
builder.AddRabbitMQ();
// The encoding of the incoming message, such that the handler is able to deserialize the message
builder.AddSystemJson();
// (Optional) Enable support for incoming messages that are gzip compressed. Uncompressed messages will still
// work to make the migration to compression backwards-compatible.
builder.AddGzipDecompression();
})
// Now add the different queues. For each individual queue
// we have to add here individual sections. Because of the template argument, each
// section needs to have its own message type. You can currently not send the same
// message type to different queues. Note that these dont have to be separate objects though.
// So if you want to send the same message to multiple queues, you can define your data in a
// base class, and then create an empty derived type, which is to be used here in the setup (as
// shown in this example).

// Add one publishing queue.
.ConfigurePublisher<LeftMessage>((_, builder) =>
{
// In this case the messages are sent to one RabbitMQ queue.
// We could still use the default name for any of the config sections, but
// using a descriptive name is better, especially because we still have
// the other queue, or as many as needed, with different settings.
// Obviously only one queue can have the default name anyway.
builder.AddRabbitMQ("LeftQueue");

// The encoding of the outgoing message, such that the handler is able to serialize the message
builder.AddSystemJson();

// (Optional) Compress the serialized data of the outgoing message with gzip.
builder.AddGzipCompression();
})
// Add another publishing queue.
.ConfigurePublisher<RightMessage>((_, builder) =>
{
// In this case the messages are sent to the other RabbitMQ queue.
builder.AddRabbitMQ("RightQueue");

// The encoding of the outgoing message, such that the handler is able to serialize the message
builder.AddSystemJson();

// (Optional) Compress the serialized data of the outgoing message with gzip.
builder.AddGzipCompression();
})
.RunConsoleAsync();
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:58904/",
"sslPort": 44350
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"ConsumeAndPublishWithRabbitMQ": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<Product>Motor.NET</Product>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Motor.Extensions.ContentEncoding.Gzip\Motor.Extensions.ContentEncoding.Gzip.csproj" />
<ProjectReference Include="..\..\src\Motor.Extensions.Conversion.SystemJson\Motor.Extensions.Conversion.SystemJson.csproj" />
<ProjectReference Include="..\..\src\Motor.Extensions.Hosting.RabbitMQ\Motor.Extensions.Hosting.RabbitMQ.csproj" />
<ProjectReference Include="..\..\src\Motor.Extensions.Utilities\Motor.Extensions.Utilities.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="appsettings.Production.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
5 changes: 5 additions & 0 deletions examples/PublishToMultipleQueuesRabbitMQ/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This example shows how to use MotorNET to publish to multiple different queues.
The method shown here uses a RabbitMQ but of course the pattern can be applied to any of the
other publishers as well. Or it can be combined with other services as well.
So suppose you have a SingleOutputService which always publishes to a certain queue,
but in some cases you might want to send data to another queue.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"Serilog": {
"MinimumLevel": {
"Default": "Information"
}
},
"RabbitMQConsumer": {
"Queue": {
"Name": "ExampleProductionQueue"
}
},
"RabbitMQPublisher": {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entry looks obsolete

"PublishingTarget": {
"RoutingKey": "production"
}
}
}
51 changes: 51 additions & 0 deletions examples/PublishToMultipleQueuesRabbitMQ/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"System": "Warning"
}
}
},
"RabbitMQConsumer": {
"Host": "localhost",
"VirtualHost": "/",
"User": "guest",
"Password": "guest",
"Queue": {
"Name": "ExampleQueue",
"Bindings": [
{
"Exchange": "amq.topic",
"RoutingKey": "input"
}
]
},
"PrefetchCount": 10
},
"LeftQueue":
{
"Host": "localhost",
"VirtualHost": "/",
"User": "guest",
"Password": "guest",
"PublishingTarget":
{
"Exchange": "amq.topic",
"RoutingKey": "output.left"
}
},
"RightQueue": {
"Host": "localhost",
"VirtualHost": "/",
"User": "guest",
"Password": "guest",
"PublishingTarget":
{
"Exchange": "amq.topic",
"RoutingKey": "output.right"
}
}
}
Loading