This repository demonstrates practical implementations of Change Event Streaming (CES), a groundbreaking feature in SQL Server 2025 that enables real-time data synchronization between microservices through Azure Event Hubs.
Change Event Streaming allows SQL Server to continuously stream row-level changes from tables directly into Azure Event Hubs as CloudEvents. This enables event-driven architectures where multiple consumer applications can subscribe to data changes in real time, facilitating seamless microservice communication without tight coupling.
This solution consists of two independent microservices, each with its own database:
- Manages product inventory and warehouse operations
- Database: SQL Server (Warehouse DB)
- Publishes product changes via Change Event Streaming
- Subscribes to sales order integration events
- Handles sales orders using CQRS-ES pattern
- Database: SQL Server (Sales DB)
- Subscribes to product changes from Warehouse
- Publishes sales order events via Change Event Streaming
Flow:
- A new product is created through the Warehouse API
- Product data is persisted in the Warehouse SQL Server database
- Change Event Streaming automatically publishes a CloudEvent to Azure Event Hub (
producthub) - Sales microservice subscribes to the Event Hub
- Sales microservice receives the notification and updates its Product table in the Sales database
Key Technologies:
- SQL Server Change Event Streaming on
dbo.Producttable - Azure Event Hub as message broker
- CloudEvents standard for event format
Use Case: Ensures product catalog consistency across microservices without direct API calls or database coupling.
Flow:
- A new sales order is created through the Sales API
- Using CQRS-ES pattern, a
SalesOrderCreateddomain event is raised - Event is persisted in the EventStore table (SQL Server - Sales DB)
- Change Event Streaming publishes the event to Azure Event Hub (
eventstorehub) - Sales microservice subscribes to its own Event Hub to:
- Update the read model (SalesOrder table in Sales DB)
- Generate an integration event for Warehouse
- Warehouse microservice subscribes to the integration event and processes it
Key Technologies:
- CQRS-ES (Command Query Responsibility Segregation - Event Sourcing)
- SQL Server Change Event Streaming on
dbo.EventStoretable - Azure Event Hub for event distribution
- Event-driven integration between bounded contexts
Use Case: Implements event sourcing with automatic event distribution, enabling audit trails, temporal queries, and reliable cross-service communication.
┌─────────────────────────────────────────────────────────────────────┐
│ Azure Event Hubs │
│ ┌──────────────────────┐ ┌──────────────────────┐ │
│ │ producthub │ │ eventstorehub │ │
│ └──────────────────────┘ └──────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
▲ ▲ │
│ CloudEvents │ │ CloudEvents
│ │ │
┌──────────┴────────────┐ ┌───────────┴─────────▼───────────┐
│ Warehouse Service │ │ Sales Service (CQRS-ES) │
│ ───────────────── │ │ ───────────────────── │
│ • Product API │ │ • Sales Order API │
│ • SQL Server DB │ │ • EventStore (Write) │
│ - dbo.Product │ │ • SalesOrder (Read Model) │
│ [CES Enabled] │ │ • SQL Server DB │
│ │ │ - dbo.EventStore │
│ Publishes Product │ │ [CES Enabled] │
│ changes │ │ - dbo.SalesOrder │
└───────────────────────┘ │ - dbo.Product │
│ │
│ Subscribes to producthub │
└─────────────────────────────────┘
Scenario 1: Warehouse creates Product → CES → Event Hub → Sales subscribes
Scenario 2: Sales creates Order → EventStore → CES → Event Hub → Sales/Warehouse subscribe
Before starting with Change Event Streaming setup, ensure you have:
- Azure Subscription: Active subscription with appropriate permissions
- Azure Event Hubs: Namespace and Event Hub creation rights
- PowerShell Modules: Az and Az.EventHub modules (installation covered below)
- SQL Server 2025 (or later) with Change Event Streaming support
- SQL Server limitations
- .NET 8.0 SDK or later
- Visual Studio 2022 or VS Code
- Azure Storage Explorer (optional, for monitoring Event Hub checkpoints)
Navigate to Azure Portal and create two Event Hubs:
- producthub - for Warehouse product changes
- eventstorehub - for Sales event store changes
Create a new Entity:
Create a new Policy with Send and Listen permissions:
You'll need a Shared Access Signature (SAS) token for SQL Server authentication against Event Hubs.
Run PowerShell as an administrator:
Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force
Install-Module -Name Az.EventHub -Scope CurrentUser -ForceTwo scripts are provided in the sqlScripts folder:
Generate-SAS-Token.ps1- for eventstorehub (Sales)Generate-Warehouse-SAS-Token.ps1- for producthub (Warehouse)
Before executing:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy BypassThen run:
.\sqlScripts\Generate-SAS-Token.ps1
.\sqlScripts\Generate-Warehouse-SAS-Token.ps1The script will generate a SAS token and copy it to your clipboard.
Execute the following scripts in order for the Sales database:
-- sqlScripts/EnableChangeEventStream.sql
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'YourStrongPassword!';
CREATE DATABASE SCOPED CREDENTIAL SqlCesCredential
WITH
IDENTITY = 'SHARED ACCESS SIGNATURE',
SECRET = '<Your SAS Token for eventstorehub>';
EXEC sys.sp_enable_event_stream;
-- Verify
SELECT * FROM sys.databases WHERE is_event_stream_enabled = 1;-- sqlScripts/AddStreamGroupToEventStore.sql
EXEC sys.sp_create_event_stream_group
@stream_group_name = 'ces-wpc-2025',
@destination_location = 'wpc-eventhub.servicebus.windows.net/eventstorehub',
@destination_credential = SqlCesCredential,
@destination_type = 'AzureEventHubsAmqp';
EXEC sys.sp_add_object_to_event_stream_group
@stream_group_name = 'ces-wpc-2025',
@object_name = 'dbo.EventStore',
@include_old_values = 0,
@include_all_columns = 1;
-- Verify
EXEC sp_help_change_feed_table @source_schema = 'dbo', @source_name = 'EventStore';Execute the following scripts for the Warehouse database:
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'YourStrongPassword!';
CREATE DATABASE SCOPED CREDENTIAL SqlWarehouseCredential
WITH
IDENTITY = 'SHARED ACCESS SIGNATURE',
SECRET = '<Your SAS Token for producthub>';
EXEC sys.sp_enable_event_stream;-- sqlScripts/AddStreamGroupToProduct.sql
EXEC sys.sp_create_event_stream_group
@stream_group_name = 'warehouse-ces-2025',
@destination_location = 'wpc-eventhub.servicebus.windows.net/producthub',
@destination_credential = SqlWarehouseCredential,
@destination_type = 'AzureEventHubsAmqp';
EXEC sys.sp_add_object_to_event_stream_group
@stream_group_name = 'warehouse-ces-2025',
@object_name = 'dbo.Product',
@include_old_values = 1,
@include_all_columns = 1;
-- Verify
EXEC sp_help_change_feed_table @source_schema = 'dbo', @source_name = 'Product';Update the appsettings.json files in both microservices with your connection strings and Event Hub details.
Sales API (src/BrewUpSales/BrewUp.Rest/appsettings.json):
{
"ConnectionStrings": {
"SalesConnection": "Your SQL Server Connection String"
},
"EventHub": {
"ConnectionString": "Endpoint=sb://wpc-eventhub.servicebus.windows.net/...",
"EventHubName": "eventstorehub",
"ConsumerGroup": "$Default",
"BlobStorageConnectionString": "Your Blob Storage Connection String",
"BlobContainerName": "checkpoints"
}
}Warehouse API (src/BrewUpWarehouse/BrewUp.Rest/appsettings.json):
{
"ConnectionStrings": {
"WarehouseConnection": "Your SQL Server Connection String"
},
"EventHub": {
"ConnectionString": "Endpoint=sb://wpc-eventhub.servicebus.windows.net/...",
"EventHubName": "producthub",
"ConsumerGroup": "$Default",
"BlobStorageConnectionString": "Your Blob Storage Connection String",
"BlobContainerName": "checkpoints"
}
}Open the solutions in Visual Studio or use the command line:
# Terminal 1 - Sales API
cd src/BrewUpSales
dotnet run --project BrewUp.Rest
# Terminal 2 - Warehouse API
cd src/BrewUpWarehouse
dotnet run --project BrewUp.Rest- Create a product via Warehouse API:
POST http://localhost:5001/api/products
Content-Type: application/json
{
"productId": "prod-001",
"name": "Premium IPA",
"description": "Hoppy craft beer",
"unitPrice": 5.99,
"itemsInStock": 100
}- Verify the product appears in the Sales database
Producttable - Check Event Hub metrics in Azure Portal for messages received
- Create a sales order via Sales API:
Use the provided JSON file:
POST http://localhost:5000/api/sales/orders
Content-Type: application/json
# Use sqlScripts/CreateSalesOrder.json- Verify:
- Event is saved in
dbo.EventStore(Sales DB) - Read model updated in
dbo.SalesOrder(Sales DB) - Event appears in Event Hub
- Warehouse processes the integration event
- Event is saved in
Change Event Streaming publishes events in CloudEvents format. Example:
{
"specversion": "1.0",
"type": "com.microsoft.SQL.CES.DML.V1",
"source": "/",
"id": "cc3fcdca-09c0-4f46-a8d3-5d0c3c1eb85a",
"time": "2025-11-03T12:29:46.290Z",
"datacontenttype": "application/avro-json",
"operation": "INS",
"segmentindex": 1,
"finalsegment": true,
"data": {
"eventsource": {
"db": "WpcDemo",
"schema": "dbo",
"tbl": "Product",
"cols": [
{
"name": "ProductId",
"type": "int",
"index": 0
}
],
"pkkey": [
{
"columnname": "ProductId",
"value": "2"
}
],
"transaction": {
"commitlsn": "0000002C:00000730:0011",
"beginlsn": "0000002C:00000730:000C",
"sequencenumber": 2,
"committime": "2025-06-30T12:29:46.290Z"
}
},
"eventrow": {
"old": null,
"current": "{\"ProductId\": \"2\", \"Name\": \"Premium IPA\"}"
}
}
}Problem: Install-Module fails or takes too long
Install-Module : Access is denied
Solutions:
- Run PowerShell as Administrator
- Use
-Scope CurrentUserif you can't install system-wide - Check execution policy:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
Problem: Connect-AzAccount fails or wrong subscription
Connect-AzAccount : AADSTS50058: A silent sign-in request was sent but no user is signed in.
Solutions:
- Ensure you're logged into the correct Azure tenant
- Use
Connect-AzAccount -TenantId <tenant-id>for specific tenant - Verify subscription access:
Get-AzSubscription
Problem: SQL Server can't connect to Event Hub
Error: Failed to connect to Event Hub endpoint
Solutions:
- Verify SAS token is not expired (6-month limit)
- Check firewall rules allow outbound connections to
*.servicebus.windows.net - Ensure Event Hub namespace and hub names are correct
- Verify the authorization policy has "Send" permissions
Problem: sp_enable_event_stream fails
Msg 40001, Database 'YourDB' is not enabled for change feed
Solutions:
- Verify SQL Server 2025 version supports CES
- Check database compatibility level
- Ensure you have
db_ownerpermissions - Verify master key exists:
SELECT * FROM sys.symmetric_keys WHERE name = '##MS_DatabaseMasterKey##'
Problem: Cannot create event stream group
The operation failed because the database scoped credential does not exist
Solutions:
- Ensure credential was created successfully
- Verify SAS token format (should start with
SharedAccessSignature sr=) - Check credential exists:
SELECT * FROM sys.database_scoped_credentials
Problem: Tables added but no events appear in Event Hub
Solutions:
- Verify table is added to stream group:
EXEC sp_help_change_feed_table - Check stream group status:
SELECT * FROM sys.event_stream_groups - Perform DML operations on tracked tables to generate events
- Monitor for errors in SQL Server error log
-- Check if Change Event Streaming is enabled
SELECT name, is_event_stream_enabled
FROM sys.databases
WHERE name = DB_NAME();
-- List all event stream groups
SELECT * FROM sys.event_stream_groups;
-- Check tables in stream groups
SELECT * FROM sys.event_stream_group_tables;
-- Verify database scoped credentials
SELECT * FROM sys.database_scoped_credentials;
-- Check stream status for specific table
EXEC sp_help_change_feed_table
@source_schema = 'dbo',
@source_name = 'EventStore';
-- View all tables with change feed
EXEC sys.sp_help_change_feed_table_groups;- Loose Coupling: Microservices don't need direct knowledge of each other
- Real-time Synchronization: Changes are streamed immediately
- Audit Trail: Event sourcing provides complete history
- Scalability: Event Hub handles high-throughput scenarios
- Reliability: Built-in retry and checkpoint mechanisms
- Standard Protocol: CloudEvents ensures interoperability
- SQL Server Documentation: Change Event Streaming Overview
- Azure Event Hubs: Event Hubs Documentation
- CloudEvents: CloudEvents Specification
- CQRS-ES Pattern: Microsoft Architecture Guide
WPC-2025/
├── src/
│ ├── BrewUpSales/ # Sales Microservice
│ │ ├── BrewUp.Rest/ # API Layer
│ │ ├── Sales/ # Domain & Infrastructure
│ │ │ ├── BrewUp.Sales.Domain/
│ │ │ ├── BrewUp.Sales.Facade/
│ │ │ └── BrewUp.Sales.Infrastructure/
│ │ ├── BrewUp.Shared/ # Shared Components
│ │ └── Muflone.Persistence.Azure/ # Event Store
│ │
│ └── BrewUpWarehouse/ # Warehouse Microservice
│ ├── BrewUp.Rest/ # API Layer
│ ├── Warehouse/ # Domain & Infrastructure
│ │ ├── BrewUp.Warehouse.Domain/
│ │ ├── BrewUp.Warehouse.Facade/
│ │ └── BrewUp.Warehouse.ReadModel/
│ └── BrewUp.Shared/ # Shared Components
│
├── sqlScripts/ # SQL Setup Scripts
│ ├── EnableChangeEventStream.sql
│ ├── AddStreamGroupToEventStore.sql
│ ├── AddStreamGroupToProduct.sql
│ ├── Generate-SAS-Token.ps1
│ └── Generate-Warehouse-SAS-Token.ps1
│
└── images/ # Documentation Images
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
This demo was created to showcase SQL Server 2025 Change Event Streaming capabilities at WPC 2025.
Note: This is a demonstration project. For production use, implement proper error handling, monitoring, security practices, and consider using additional patterns like Saga for distributed transactions.


