Skip to content

Commit 578b445

Browse files
author
Sharifuzzaman Nakib
committed
Some doc and basic-communication tutorial is added.
1 parent 7b97076 commit 578b445

17 files changed

Lines changed: 628 additions & 0 deletions

documentation/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
_site/

documentation/docfx.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/dotnet/docfx/main/schemas/docfx.schema.json",
3+
"build": {
4+
"content": [
5+
{
6+
"files": [
7+
"**/*.{md,yml}"
8+
],
9+
"exclude": [
10+
"_site/**"
11+
]
12+
}
13+
],
14+
"resource": [
15+
{
16+
"files": [
17+
"images/**"
18+
]
19+
}
20+
],
21+
"output": "_site",
22+
"template": [
23+
"default",
24+
"modern"
25+
],
26+
"globalMetadata": {
27+
"_appName": "OpenTransit",
28+
"_appTitle": "OpenTransit",
29+
"_appLogoPath": "images/logo.svg",
30+
"_appFooter": "<footer></footer>",
31+
"_enableSearch": true,
32+
"pdf": true
33+
}
34+
}
35+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
The generic broker concept is an abstraction of all the Broker supported by Masstransit. It contains all the common features of all the supported brokers.
3+
4+
# Common Broker Features
5+
6+
Different message brokers provide different capabilities, but if you look at the most popular ones—RabbitMQ, Azure Service Bus, ActiveMQ, and Amazon SQS—you’ll notice a shared set of core features.
7+
In practice, these common features cover the majority of real-world use cases.
8+
9+
For example:
10+
11+
- All of them offer a **Publish Endpoint** where messages can be published.
12+
- RabbitMQ calls this an **Exchange**.
13+
- Azure Service Bus, ActiveMQ, and Amazon SQS call it a **Topic**.
14+
15+
- All of them provide a **Receive Endpoint**, typically referred to as a **Queue**, where consumers subscribe.
16+
17+
Producers publish messages to Publish Endpoints, and Consumers subscribe to Receive Endpoints.
18+
19+
Most brokers also allow you to configure **routing** between Publish Endpoints and Receive Endpoints.
20+
This means that when a message arrives at a Publish Endpoint, the broker forwards it to one or more Receive Endpoints based on the defined routing configuration.
21+
(You can still send messages directly to the ReceiveEndpoint if needed.)
22+
23+
These behaviors are consistent across brokers.
24+
25+
26+
27+
# The Generic Broker Concept
28+
29+
OpenTransit takes advantage of these shared capabilities by introducing a **Generic Broker**—an abstraction that represents the common behavior of message brokers.
30+
You configure your topology against this Generic Broker, and OpenTransit translates that configuration into the appropriate broker-specific topology under the hood.
31+
32+
This abstraction is the foundation of the Generic Broker concept.
33+
34+
35+
## Generic Broker Terminologies
36+
37+
A Generic Broker defines two types of endpoints:
38+
39+
- **Publish Endpoints**
40+
- **Receive Endpoints**
41+
42+
You can create and configure the routing between PublishEndpoint to the ReceiveEndpoint based on Message Types.
43+
44+
- Messages are generally **published** to a Publish Endpoint.
45+
- Consumers **subscribe** to Receive Endpoints.
46+
- Messages may also be sent **directly** to a Receive Endpoint if needed.
47+
48+
You can define **routing mappings** between endpoints—specifying which Receive Endpoint(s) should receive messages published to a given Publish Endpoint.
49+
50+
In the [Basic Communication Tutorial](../tutorials/basic-communication.md) we have seen how Message types is used to Create and Configure Create Endpoints and Receive Endpoints.
51+
52+
> [!NOTE]
53+
> Some concepts in this documentation are still evolving. Details on how the Generic Broker constructs the underlying topology for different message types will be added in a future update.
54+
55+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
- name: Generic Broker
3+
href: generic-broker.md
4+
- name: Topology
5+
href: topology.md
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
The term Topology is used in many context and have different meaning in different context.
2+
3+
However, in distributed system, it is generally used in two Contexts. They are,
4+
1. Broker
5+
2. Architectural pattern.
6+
7+
In the context of a **broker**, it means the broker’s internal routing configuration i.e. the route mapping between the Publish Endpoint(i.e. Topics, Exchanges, etc) to Receive Endpoint(i.e Queues).
8+
9+
In the context of **Architectural patterns**, the Producers, Consumers and the Broker consists of the Topology.
10+
11+
Opentransit’s Definition is sort of a combination of the both cause opentransit helps you not only to Configure the Broker internally, but also helps to interact with it(i.e to Produce, consume, etc).
12+
13+
So in OpenTransit, **Topology is the broker’s internal configuration, and also the Configuration of how the Application (via OpenTransit) interacts with the broker.**
14+
15+
However, when we want to mean only in broker's context, we will use the term 'Broker's Underlying Topology' throughout the doc.
16+
17+
18+
19+
## Configuring the Topology:
20+
So we now know what a topology is. Now we will know how to Configure the topology.
21+
22+
From the definition, Configuring topology may mean Configuring both of the following things,
23+
24+
- Configuring the broker’s internal configuration like Publishendpoints(topic, exchange), Receive Endpoints(i.e. queue), routing, etc.
25+
- Configuring how OpenTransit interacts with the broker.
26+
27+
OpenTransit defines topology via the Message type
28+
29+
### Message Types as First-class citizens:
30+
You have already seen in the [tutorial](../tutorials/basic-communication) how Message Types (classes, records, or interfaces) are used when Configuring the broker, and how Producers and Consumers interact with the PublishEndpoint and ReceiveEndpoint depending on the Message Type.
31+
It gives a strongly typed facility that you wouldn’t have found if you were to use the raw .NET Client of the broker.
32+
It also abstracts away the details of topology from the Broker interaction point of view and provides a Method call-like syntax and hides the detail of broker Communication.
33+
34+
However, OpenTransit is flexible enough to provide lower level API’s if we want a lower level interaction.
35+
36+
OpenTransit provides two ways to define the broker topology.
37+
38+
- Broker Agnostic way(Common for any broker)
39+
- Broker Specific way(features provided by the broker, for example, routing key by RabbitMQ)(give an example link)
40+
41+
42+
## Broker agnostic Way:
43+
We can define both the Broker’s internal Configuraiton and OpenTransit’s Interaction in a Broker agnostic way.
44+
45+
In the [tutorial](../tutorials/basic-communication.md), the topology is defined in a broker agnostic way.
46+
47+
One of the most powerful feature of OpenTransit is the way it abstracts away the detail of a broker.
48+
We can use an underlying broker without knowing the intrinsic details.
49+
50+
How Masstransit defines the abstraction and what are the benefits is discussed in the [Generic Broker](generic-broker.md).
51+
52+
The abstraction provides many benefits and most of the time it provides the feature we needs so we should choose the Broker agnostic configuration whenever possible.
53+
54+
55+
## Broker Specific Way:
56+
Though broker agnostic configuration is recommended, however, in some scenarios, we may have some special requirements and need to use some special features that is provided by a specific broker.
57+
OpenTransit is flexible and provides a way where you can define broker specific features.
58+
59+
> [!NOTE]
60+
> We will add tutorials/examples later.
61+
62+
63+
64+
65+
66+
67+
### Producer, Consumer, Publish, Subscribe, etc:
68+
69+
You may get confused with the usage of these terms in the doc with the terms used on Producer Consumer or Pub-Sub pattern.
70+
71+
Well, in OpenTransit, we generally use the terms in our own way which may sometimes not exactly the same as their definition in other contexts.
72+
73+
For example,
74+
75+
- Producer Publishes Messages to the PublishEndpoint
76+
- Producer Sends Messages directly to the ReceiveEndpoint
77+
- Consumer Subscribes to a Receive Endpoint
78+
- Consumer Consumes Messages
79+
80+
Here,
81+
Producer is something that Publishes/Sends Messages to the broker.
82+
Consumer is something that Consumes/Subscribes to a ReceiveEndpoint to Consume Messages.
83+
84+
If two consumer subsribes to the Same ReceiveEndpoint, then only one will get a particular message(Competing Consumer pattern). So in that way it matches the Consumer’s definition of the Producer-Consumer pattern.
85+
86+
Sometimes the terms Producer and Consumer is used to Describe the Application.
87+
For example, the Applicaiton that publishes messages is a Producer Application, the application that Consumes messages is a Consumer.
88+
However, an application may be both Producer and Consumer at the same time.
89+
90+
91+
92+
93+
94+
95+
96+
97+
98+
99+
100+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
## Documentation as a First-Class Citizen
2+
3+
At OpenTransit, documentation is a **first-class citizen**. We believe that great software is only as good as its ability to be understood, adopted, and extended.
4+
5+
That’s why we treat documentation with the same level of importance as the project’s source code — clear, accurate, and helpful documentation is a core part of our mission.
6+
7+
8+
## Our Current Focus: Understanding Through Clarity
9+
10+
MassTransit v8 will continue receiving support until the end of 2026. During this period, our primary focus is to build an outstanding documentation experience for OpenTransit.
11+
We are actively researching the codebase, exploring real-world use cases, and developing analogies, explanations, and examples that make distributed system concepts easier to understand.
12+
13+
For example, As part of this effort, we have introduced a concept called the **[Generic Broker](concepts/generic-broker.md)** — an abstraction that captures the common functionalities shared by all message brokers.
14+
For each [pattern](why-opentransit#patterns) and other concepts, we will explain the underlying [topology](concepts/topology) using the [Generic Broker](concepts/generic-broker.md) first, and then show how to customize it for each broker’s specific implementation.
15+
16+
Initially, the examples, will be given with **RabbitMQ**, and **Mongodb**. however, we will cover other broker's and db's soon.
17+
18+
19+
Our goal is to create **Understanding Documentation** — content that not only tells you *how* to use the framework, but also helps you truly *grasp* the reasoning and patterns behind it.
20+
21+
## Community Feedback Matters
22+
23+
Because documentation is a first-class citizen, we strongly encourage the community to participate.
24+
If any part of the documentation feels unclear, incomplete, confusing, or could simply be improved — **please let us know**.
25+
26+
We welcome:
27+
28+
- Feedback
29+
- Suggestions
30+
- Requests for clarification
31+
- Reports of unclear or hard-to-follow sections
32+
33+
Your input directly helps us improve OpenTransit for everyone. We’re fully open to community collaboration and want to build documentation that genuinely serves developers at all levels.

documentation/docs/toc.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
- name: Documentation
3+
href: documentation.md
4+
- name: Why OpenTransit?
5+
href: why-openTransit.md
6+
- name: Tutorials
7+
href: tutorials/toc.yml
8+
- name: Concepts
9+
href: concepts/toc.yml
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
2+
In this tutorial, we will explore the basics of publishing and consuming messages.
3+
The source code for this example is available **[here](https://github.com/OpenTransitLab/Tutorials/tree/main/Tutorials.BasicCommunication)**
4+
5+
6+
## Introducing the Services
7+
In this tutorial, we’ll work with three services:
8+
9+
- **Client** – A simple console application that publishes a message to simulate an order arriving from the frontend.
10+
- **OrderService** – Handles incoming orders. After processing an order, it publishes another message to continue the workflow.
11+
- **InventoryService** – Listens for order-processing–related messages and handles the inventory side of the workflow.
12+
13+
In this setup:
14+
- The **Client** acts as a **Producer** — it only publishes messages.
15+
- The **InventoryService** acts as a **Consumer** — it only receives messages.
16+
- The **OrderService** is both a **Producer** and a **Consumer** — it consumes one message and then publishes another.
17+
18+
19+
## Explanation
20+
You need to understand these 5 things to have a basic knowledge of Distributed Communication with OpenTransit.
21+
22+
1. [Defining Messages](#1-defining-messages)
23+
2. [How Messages are published](#2-publishing-messages)
24+
3. [How Messages are Consumed](#3-consuming-a-message)
25+
4. [How the OpenTransit Setup is done](#4-masstransit-setup)
26+
5. [The Topology Created inside the Broker](#5-the-broker-topologyrabbitmq)
27+
28+
29+
### 1. Defining Messages
30+
31+
Messages are the means of communication between Services. They can be defined using **classes**, **interfaces**, or **records**.
32+
33+
In this project, we define two messages using C# classes: **SubmitOrder** and **ProcessOrder**.
34+
35+
- The **Client** publishes a **SubmitOrder** message.
36+
- The **OrderService** consumes **SubmitOrder**, processes it, and then publishes **ProcessOrder**.
37+
- The **InventoryService** consumes **ProcessOrder**.
38+
39+
#### Sharing Message Types Across Projects
40+
41+
When a message is used by multiple applications—such as a producer and a consumer—they **must use the exact same namespace** for the message type.
42+
43+
For example:
44+
45+
- **SubmitOrder** is used by both Client and OrderService → same namespace required
46+
- **ProcessOrder** is used by OrderService and InventoryService → same namespace required
47+
48+
To simplify this, we created a **shared class library** that contains the message definitions. This is the easiest and most maintainable approach.
49+
50+
However, using a shared library is **not mandatory**. Each project may define its own copy of the message class, as long as the **namespace matches exactly**, ensuring that the broker treats them as the same message type.
51+
52+
---
53+
54+
### 2. Publishing Messages
55+
56+
Messages are published by **Producers**. A Producer exposes a `Publish(T message)` method, which is used to send messages to the broker.
57+
(We’ll cover Producers in detail later in the documentation.)
58+
59+
In this example, messages are published from two places:
60+
61+
- From the **Client** project’s `Program.cs`
62+
[!code-csharp[](code-sample/Client.Program.cs#L25-L33)]
63+
64+
65+
- From inside the **SubmitOrderConsumer**
66+
[!code-csharp[](code-sample/OrderService.SubmitOrderConsumer.cs#L6-L18)]
67+
68+
Both `IBus` and `ConsumeContext<T>` act as Producers, because you can call `Publish(T message)` on either of them.
69+
70+
When publishing inside a [Consumer](#publishing-from-inside-a-consumer), it is **highly recommended** to use the `ConsumeContext<T>` Producer as we have done in the SubmitOrderConsumer. We’ll discuss why in the dedicated Producers section.
71+
72+
When publishing *outside* a Consumer, you can resolve the `IBus` service and publish messages using it like we have done in the **Client** Project's `Program.cs`.
73+
74+
In OpenTransit, the necessary services (such as `IBus`) are registered in `Program.cs`(See the [Setup](#4-masstransit-setup), allowing you to resolve and use them throughout the application.
75+
76+
---
77+
78+
### 3. Consuming a Message:
79+
80+
To consume a message of type `T`, you need to implement `IConsumer<T>`.
81+
82+
In our example, we have two consumers:
83+
84+
- **SubmitOrderConsumer** in the **OrderService**
85+
[!code-csharp[](code-sample/OrderService.SubmitOrderConsumer.cs#L6-L18)]
86+
- **ProcessOrderConsumer** in the **InventoryService**
87+
[!code-csharp[](code-sample/InventoryService.ProcessOrderConsumer.cs#L6-L13)]
88+
89+
Each consumer must also be registered in the OpenTransit [Setup](#4-masstransit-setup) so the framework knows to create and connect them to the message pipeline.
90+
91+
#### Publishing from inside a Consumer
92+
93+
The `IConsumer<T>` defines a `Consume` method which is called when a message of type `T` is consumed. The method passes a Producer namely `ConsumeContext<T>`, it is highly recommended to use this producer(`ConsumeContext`) when we publish messages from inside the consumer. As you see we have done it in the SubmitOrderConsumer.
94+
95+
---
96+
97+
98+
### 4. MassTransit Setup:
99+
We configure OpenTransit in the **Service Registration** section of `Program.cs`.
100+
In this step, we perform three main tasks:
101+
102+
1. **Register the required services**
103+
Simply call `builder.Services.AddMassTransit()` and it will register everything needed.
104+
105+
2. **Configure the connection to the message broker**
106+
107+
3. **Register the consumers**(if any)
108+
109+
All the above 3 tasks is done onthe `Program.cs` of OrderService
110+
[!code-csharp[](code-sample/OrderService.Program.cs#L12-L25)]
111+
112+
113+
---
114+
115+
### 5. The Broker Topology(RabbitMQ):
116+
117+
This example uses **[broker-agnostic](../concepts/topology#broker-agnostic-way)** configuration, so you don’t need to understand the underlying broker [topology](../concepts/topology) for basic communication.
118+
Here, we only used the `UsingRabbitMq` method to provide the Connection Configuration and to configure the [ReceiveEndpoint](../concepts/generic-broker#generic-broker-terminologies)(a generic concept among all the brokers) on the broker.
119+
120+
Since this Configurations aren't RabbitMQ specific, and you may use any other broker here and, the Message Communication would work fine.
121+
122+
However, knowing the underlying broker [topology](../concepts/topology) is very helpful when debugging message-routing issues.
123+
124+
In our example, Each Consumer is consuming a single message type.
125+
Here, for each MessageType, 2 **Exchanges** and one **Queue** are being created.
126+
127+
For example, if you open the RabbitMq management plugin, you will see, for the SubmitOrder MessageType, a **Queue** named `SubmitOrder` is bound to the **Exchange** Named `SubmitOrder`.
128+
Another **Exchange** named `Shared:SubmitOrder` is created and the `SubmitOrder` **Exchange** is bound to it. (Here, **'Shared'** came from the **Namespace** of the message)
129+
130+
When we publish SubmitOrder messages via a Producer, the message is published to the `Shared:SubmitOrder` exchange, then routed to the SubmitOrder exchange and, then ultimately routed to the SubmitOrder queue.
131+
132+
133+
#### Generic Broker's Perspective
134+
From the perspective of the [Generic Broker](../concepts/generic-broker), the `Shared:SubmitOrder` **Exchange** is the PublishEndpoint, the `SubmitOrder` **Queue** is the ReceiveEndpoint.
135+
The `SubmitOrder` **Exchange** can be seen as an Internal ReceiveEndpoint. However, we haven't added such concept/term in the [Generic Broker](../concepts/generic-broker) yet.
136+
137+
138+
Why the topology is defined that way, what we are gaining, etc, is out of scope of this tutorial. We will have separate sections for it.
139+
140+
To have a better understanding, you may clone the [project](https://github.com/OpenTransitLab/Tutorials/tree/main/Tutorials.BasicCommunication) and create more message types experimentation.
141+
142+
143+

0 commit comments

Comments
 (0)