GB.
Azure for .NET Developers - Step by Step
Step 6 of 786% through series
  1. 6
  2. 7
2026-06-028 min read

Azure Service Bus + Azure Functions: A Beginner's Guide with .NET

#Azure#Azure Service Bus#Azure Functions#.NET#Microservices#Message Queue

Azure Service Bus + Azure Functions - The Beginner-Friendly Way to Understand Them

Suppose your API needs to perform some work that doesn't need to happen immediately.

For example:

  • Upload a document to PandaDoc
  • Send an email
  • Generate a PDF
  • Process a large file
  • Send a notification
  • Call another microservice
  • Generate a report

You could do everything inside your API request.

But then the user has to wait for all of that work to finish.

Instead, we can use:

API → Azure Service Bus → Azure Function → Process

That's where Azure Service Bus and Azure Functions become useful.


1. What is Azure Service Bus?

Azure Service Bus is a message broker.

In simple words:

Service Bus provides a reliable place for applications to send and receive messages.

Think of it like a waiting line.

.NET API
   |
"Process this document"
   ↓
+----------------------+
|   Azure Service Bus  |
|        Queue         |
+----------------------+
   |
 Message
   ↓
Worker / Function

The API doesn't have to perform the actual processing immediately.

It can simply send a message and continue.


2. What is an Azure Function?

Azure Function is a small piece of code that runs when something happens.

For example:

Service Bus message arrives
        ↓
    Azure Function
        ↓
    Process message

A Function can be triggered by many things:

  • HTTP request
  • Service Bus message
  • Timer
  • Queue message
  • Blob upload
  • Event

For this article, we are mainly interested in:

Service Bus → Azure Function


3. Why Do We Need Both?

This is the easiest way to remember it.

Azure Service Bus

Responsible for:

"Carry and deliver the message."

Azure Function

Responsible for:

"Run the code that processes the message."

So:

Service Bus = Message delivery

Azure Function = Message processing

They solve different problems.


4. A Simple Real-World Example

Imagine your application allows users to upload documents.

Without Service Bus:

User
 ↓
API
 ↓
Upload document
 ↓
Call PandaDoc
 ↓
Process document
 ↓
Send notification
 ↓
Return response

The user may have to wait several seconds.

Instead:

User
 ↓
API
 ↓
Upload document
 ↓
Send message to Service Bus
 ↓
Return response

The background processing happens separately:

Service Bus
 ↓
Azure Function
 |
 +--> Process document
 |
 +--> Upload to PandaDoc
 |
 +--> Update database
 |
 +--> Send notification

Now the API doesn't need to wait for the entire operation.


5. What is a Queue?

A queue is one of the most common Service Bus features.

Imagine this:

API
 |
 | Message 1
 | Message 2
 | Message 3
 ↓
+----------------------+
|     Service Bus      |
|        Queue         |
+----------------------+
 ↓       ↓       ↓
 M1      M2      M3

Messages wait in the queue until a consumer processes them.

For example:

document-queue

Message 1 → Upload contract.pdf
Message 2 → Upload drawing.pdf
Message 3 → Delete old-file.pdf
Message 4 → Process report.pdf

This is very useful for background processing.


6. Why Not Just Call Another API?

You might ask:

"Why don't I simply call another API?"

You can.

But consider this:

API A
 |
 | HTTP call
 ↓
API B

What happens if API B is temporarily unavailable?

The request may fail.

With messaging:

API A
 ↓
Service Bus
 ↓
API B / Function

The message can remain in the queue until it can be processed.

This creates looser coupling between applications.


7. Sending a Message from .NET

Install the Azure Service Bus package:

dotnet add package Azure.Messaging.ServiceBus

Create a simple message model:

public class DocumentMessage
{
    public int DocumentId { get; set; }

    public string FileName { get; set; }

    public string Operation { get; set; }
}

Create a Service Bus client:

var client = new ServiceBusClient(connectionString);

var sender = client.CreateSender("document-queue");

Create a message:

var documentMessage = new DocumentMessage
{
    DocumentId = 123,
    FileName = "contract.pdf",
    Operation = "Upload"
};

Serialize and send it:

var json = JsonSerializer.Serialize(documentMessage);

var message = new ServiceBusMessage(json);

await sender.SendMessageAsync(message);

That's it.

The message is now sitting in the queue.


8. What Does the Message Look Like?

Conceptually, the message contains something like:

{
    "documentId": 123,
    "fileName": "contract.pdf",
    "operation": "Upload"
}

The important thing is:

Don't put the actual large file inside the Service Bus message.

For document processing, a better approach is usually:

File
 ↓
Blob Storage
 ↓
Service Bus
 |
 | DocumentId / Blob path
 ↓
Azure Function

The message can contain a reference:

{
    "documentId": 123,
    "fileName": "contract.pdf",
    "blobPath": "documents/123/contract.pdf",
    "operation": "Upload"
}

The Function then retrieves the actual file from storage.


9. Azure Function as a Service Bus Consumer

Now let's create a Function that listens to the queue.

A simplified example:

[Function("ProcessDocument")]
public async Task Run([ServiceBusTrigger("document-queue",Connection = "ServiceBusConnection")]
                      ServiceBusReceivedMessage message)
{
    var document = JsonSerializer.Deserialize<DocumentMessage>(message.Body.ToString());

    Console.WriteLine($"Processing {document.FileName}");

    // Process document here
}

The important part is:

[ServiceBusTrigger("document-queue")]

It tells the Function:

"Run this Function when a message arrives in this queue."


10. The Complete Flow

Now we have:

                  .NET API
                     |
                     | Send Message
                     ↓
              Azure Service Bus
                     |
                     | Trigger
                     ↓
              Azure Function
                     |
             +-------+-------+
             ↓       ↓       ↓
           Blob    Database PandaDoc
          Storage

This is a very common cloud architecture.


11. What If the Function Fails?

Suppose the Function receives:

Upload contract.pdf

but PandaDoc is temporarily unavailable.

The processing can fail.

Service Bus supports message retry behavior.

Conceptually:

Service Bus
     ↓
Function
     |
     X
   Failed
     ↓
   Retry
     |
     X
   Failed
     ↓
   Retry

If the message repeatedly fails, it can eventually be moved to the:

Dead-Letter Queue

Queue
 ↓
Function
 |
 X
 |
Retry
 |
 X
 |
Retry
 |
 X
 |
 ↓
Dead-Letter Queue

The dead-letter queue gives you a place to investigate messages that could not be processed successfully.


12. What is a Dead-Letter Queue?

A dead-letter queue is basically:

A place for messages that couldn't be successfully processed.

For example:

document-queue

Message 1 → Success
Message 2 → Success
Message 3 → Failed
Message 4 → Success
Message 5 → Failed repeatedly
                    ↓
                Dead-Letter Queue

You can later inspect those messages and determine what went wrong.


13. Queue vs Topic

Service Bus also supports Topics.

This is where things become interesting.

Queue

Usually used when one processing flow needs the message.

    Queue
     ↓
    Function

For example:

Upload Document
      ↓
Document Queue
      ↓
Document Processor

Topic

A Topic can distribute a message to multiple subscriptions.

                 Topic
                   |
          +--------+--------+
          |                 |
   Notification           Audit
   Subscription       Subscription
          |                 |
          ↓                 ↓
       Function          Function

For example:

Document Uploaded
       ↓
Document Topic
       |
       +----> Notification Service
       |
       +----> Audit Service
       |
       +----> Document Service

One event can therefore be consumed by multiple independent services.


14. Service Bus + SignalR

Can Service Bus be used with SignalR?

Yes.

But they have different responsibilities.

Service Bus
     |
     | Backend messaging
     ↓
Azure Function
     |
     | Real-time notification
     ↓
  SignalR
     |
     ↓
   Browser

For example:

Document Processing
        ↓
   Service Bus
        ↓
 Azure Function
        ↓
    SignalR
        ↓
    Browser

The Service Bus handles the backend message.

SignalR handles real-time communication with the browser.


15. When Should You Use Service Bus?

Use Service Bus when you need reliable asynchronous communication.

Common examples:

  1. Document processing
  2. Email sending
  3. PDF generation
  4. Image processing
  5. Order processing
  6. Payment workflow events
  7. Notification processing
  8. Audit events
  9. Data synchronization
  10. Microservice communication
  11. Import processing
  12. Export processing
  13. Report generation
  14. File conversion
  15. Background jobs
  16. Third-party API processing
  17. Webhook processing
  18. Workflow steps
  19. Batch processing
  20. Long-running operations

16. When Should You Use Azure Functions?

Functions are useful when you want code to run because something happened.

For example:

Blob uploaded
    ↓
Function
Service Bus message
    ↓
Function
Timer
 ↓
Function
HTTP request
    ↓
Function

So you can think:

Azure Function = "Run this code when this event happens."


17. Service Bus vs Azure Function

ServiceMain Responsibility
Azure Service BusStore and deliver messages
Azure FunctionExecute code when triggered
SignalRReal-time client communication
Blob StorageStore files
App ServiceHost web applications/APIs

They often work together, rather than replacing each other.


18. A Practical Document Processing Architecture

A real document workflow could look like this:

                User
                  |
                  ↓
              .NET API
                  |
                  | Upload
                  ↓
            Blob Storage
                  |
                  | Document reference
                  ↓
          Azure Service Bus
                  |
                  | Trigger
                  ↓
          Azure Function
                  |
        +---------+---------+
        |         |         |
        ↓         ↓         ↓
    PandaDoc   Database   Processing
        |
        ↓
   Processing Done
        |
        ↓
      SignalR
        |
        ↓
      Browser

The important design principle is:

Store the file in Blob Storage and put the file reference/metadata in Service Bus rather than putting a large file into the message.


19. The Simplest Mental Model

If you are completely new to Azure, remember this:

             SERVICE BUS
          "I have a message"
                 ↓
          +-------------+
          |    Queue    |
          +-------------+
                 ↓
         AZURE FUNCTION
          "I'll process it"
                 ↓
                WORK

Or even simpler:

Service Bus carries the message. Function does the work.


20. Final Takeaway

Azure Service Bus and Azure Functions are especially useful when your application needs background or event-driven processing.

Instead of:

API
 |
 +--> Do everything
 |
 +--> Wait
 |
 +--> Return response

you can use:

API
 |
 +--> Send message
 |
 +--> Return quickly
       |
       ↓
 Service Bus
       |
       ↓
 Azure Function
       |
       ↓
 Background Work

This approach can give you:

  • Better separation of responsibilities
  • Asynchronous processing
  • Reliable message delivery
  • Retry capabilities
  • Dead-letter handling
  • Better scalability
  • Looser coupling between services

The one sentence to remember

Azure Service Bus is the communication/waiting line; Azure Function is the worker that wakes up and processes the message.

Enjoyed this article? Share it with your network!