Magnus Mårtensson
Microsoft Regional Director, Azure MVP, CEO Loftysoft
Avirag Jain
Director & CTO R Systems
Mahesh Chand
Founder C# Corner, CEO Mindcracker
Chris Gali
CEO & Co-Founder Graphite
Subinder Khurana
Chief Architect StoryProcess, Founder NASSCOM DeepTech Club
Bryan Rishforth
Investor, Chairman Graphite
Bryn Everson
Director Biz Dev Graphite
Raj Tiwari
Digital Transformation Leader, Futurist and Visionary
Joseph Guadagno
Microsoft MVP, Lead Quicken Loans
Nikita Sachdev
Entrepreneur, Blockchain Enthusiast & Advisor, Social Media Influencer
Doug Wagner
COO & Founder Adapt Technical Group
Ritesh Modi
Architect, Senior Evangelist, Cloud Architect
Crystal Wenrick
Director Communications Mindcracker
Allen O’Neill
Microsoft MVP, Consulting Engineer/Architect
Praveen Kumar
CEO MCN Solutions
Chris Love
Founder Love2Dev, Microsoft MVP, Author
Sanjay Vyas
Microsoft Regional Director, Microsoft MVP, Founder & CEO SkillLabs Technologies
Veena Sarda
Deep Learning Consultant, Author
Sekhar Srinivasan
C# Corner MVP, Microsoft Certified Trainer, Pluralsight Author
Lalit Bansal
Founder & CEO - EIY SYS
Navdeep Garg
CEO Revinfotech
Prakash Tripathi
Tech Manager/Leader, Microsoft MVP, Blogger
Bhavna Jain
Breakthrough Consultant
Naveen Sharma
Enterprise Architect, Leadership Coach, Author
Vidya Vrat Agarwal
Principal Architect, Microsoft MVP, Author
Sheetal Agarwal
Founder Clownselors, Medical Clown, Trainer
Abhishek Kant
Founder GTM Catalyst
Vishnu Saran
Founder & CEO VoiceQube
Sandeep Soni
Founder & CEO Deccansoft, Microsoft Certified Trainer
Parveen Malik
AVP InfoSec & Vulnerability Management, Information Security Expert
Nitin Pandit
Microsoft MVP, Developer Evangelist, Author
Niloshima Srivastava
C# Corner MVP, Tech Architect, Trainer, Blogger
Bala Chirtsabesan
Senior Software Engineer at Microsoft, Author
Manoj Mittal
Sr. Technical Architect, C# Corner MVP, Author
Chandni Di
Co-Founder Voice of Slum
Vithal Wadje
Technical Lead, Microsoft MVP, Author
Shivam Ahuja
Founder SkillCircle, Business Mentor
Chervine Bhiwoo
Solution Architect, Microsoft MVP, Author
Saurabh Jain
Vice President Paytm, Founder Fun2Do Labs, Author
Vinay Solanki
Head IoT at Lenovo, Founder IoT-NCR
Anshu kumari
Founder Blockchainkids, Inventor, Trainer
Amit Singal
CEO Startup Buddy
Dev Pratap
Co-Founder & CEO Voice of Slum
Amey Vartak
Technology Consultant, Full Stack Developer, C# Corner MVP, Author
Viswanatha Swamy
Principal Software Engineer, C# Corner MVP, Author
Sanket Verma
Research Engineer @ Ballistics (Forensics) and Chair, PyData Delhi
Sourabh Somani
Lead Developer, Microsoft MVP, Author
Abhishek Mishra
Software Architect, C# Corner MVP, Author
Siddharth Vaghasia
Technical Consultant, C# Corner MVP, Blogger
Bassam Alugili
Senior Software Specialist, Database Expert
S Ravi Kumar
Solution Architect, C# Corner MVP, Author
Sundaram Subramanian
Full Stack Developer, C# Corner MVP, Speaker
Deepesh Somani
Solution Architect, Microsoft MVP, Author
Debasis Saha
Technical Project Manager, C# Corner MVP, Blogger, Author
Vipul Jain
Software Architect, C# Corner MVP, Author
Akshay Patel
Technical Architect, Microsoft Certified Trainer, C# Corner MVP, Author
Stephen Simon
RPA Developer, Evangelist, Author
Vivek Sharma
Founder Kingster636, AR/VR Specialist
Jeetendra Gund
Technical Lead, C# Corner MVP, Author
Sujal Beniwal
AI Enthusiast, Student
M Viknaraj
Microsoft MVP, Azure Architect, Author
Prasham Sabadra
Software Architect, C# Corner MVP, Trainer, Author
Aakash Maurya
Senior Developer, C# Corner MVP, Speaker
Ankit Sharma
Senior Software Engineer, C# Corner MVP, Author
Mangesh Gaherwar
Team Lead, C# Corner MVP, Author
Viral Jain
Technical Consultant, C# Corner MVP, Author
Bhasker Das
Solution Architect, Evangelist
Manish Dwivedi
Associate Project Manager
Ck Nitin
Programmer, Author
Rohit Gupta
Technical Trainer, Author
Manish Tewatia
Full-stack Marketer, UX Designer
Bhavya Gaur
Technical Illustrator
Rohit Tomar
SEO/SMO Expert
Web Track
Cloud & Data Track
Dev Track
Registration & Breakfast
Future of Desktop Apps with JS (ElectronJs)
Nitin Pandit
Building Serverless Microservices Using Microsoft Azure
Vithal Wadje
Innovating RPA: A Robot for Every Person
Stephen Simon
Managing Cloud Storage Accounts using Logic Apps
Viknaraj Manogararajah
Data visualization using Python
Sekhar Srinivasan
Going Cross platform with AR Foundation
Vivek Sharma
Keynote
Managing your Azure dependencies in ASP.NET Core apps using VS
Bala Chirtsabesan
Securing Applications on Intelligent Azure
Abhishek Mishra
Getting started with Blazor the Framework of Future
S Ravi Kumar
Lunch
Build Progressive Web Apps using Angular 9
Debasis Saha
Build and deploy to any platform using Azure DevOps
Chervine Bhiwoo
Deep Dive in Azure Service Bus
Akshay Patel
Build a Native Mobile Application using React Native and JavaScript
Joseph Guadagno
Making sense of Web Job, Web Job SDK and Functions in Azure
Prakash Tripathi
CloudFront Distribution in AWS
Viral Jain
Tea Break
Introduction to PowerBI
Aakash Maurya
Build Advanced SPFx solutions with React and Graph API
Siddharth Vaghasia
Build Business Intelligence Analyst (BIA) Skills
Sundaram Subramanian
Deep dive of Power Platform – AI BUILDER
Prasham Sabadra
Panel 1
What's new in SharePoint development
Vipul Jain
Build a SSO (Single Sign On) based Native JavaScript application with Microsoft Identity within 10 minutes
Manoj Mittal
Panel 2
Applications and working of AI
Veena Sarda
Deploying serverless API's with .Net core 3.0 on AWS & Azure
Amey Vartak
Panel 3
Blockchain with .NET Core (Ark)
Anshu Kumari
Closing Note & Prize Distribution
Dev Track
Cloud Track
Architecture Track
Emerging Tech Track
Registration & Breakfast
Creating Full-Stack Web Apps Using Server-Side Blazor
Ankit Sharma
Real time face recognition with MS Cognitive Services
Niloshima Srivastava
Building Scalable APIs with GraphQL
Jeetendra Gund
Future of development with AI and Blockchain
Navdeep Garg
Debugging Tips and Tricks with Visual Studio 2019
Joseph Guadagno
Azure Containers
Abhishek Kant
Enterprise Architecture
Naveen Sharma
Bot Framework - learn it fast and look like a boss!
Allen O’Neill
Keynote
.Net Core & C# 8 Performance
David McCarter
Working with Azure kubernetes services
Ritesh Modi
Becoming an Architect
Vidyavrat Agarwal
Why Techies Need to Learn Product Management
Saurabh Jain
Lunch
Build a rules engine in .Net Core
Sanjay Vyas
Building CI and CD Pipeline using Azure DevOps
Sandeep Soni
Entity Framework Core - Tips and Tricks, Performance Optimization, and Tuning
Bassam Alugili
Hacking your way into Data Science
Sanket Verma
Speed up your .Net Core Website
Sourabh Somani
Azure
Magnus Mårtensson
Demystifying Open Distro for Elasticsearch
Suman Debnath
Future of Data
Shivam Ahuja
Tea Break
gRPC with C# and .Net Core
Mangesh Gaherwar
Panel 1
Essentials of Cloud security
Parveen Malik
Power platform and Dynamics 365
Deepesh Somani
Microservices - the gRPC Way
Viswanatha Swamy
Panel 2
Reserved
Reserved
Closing Note & Prize Distribution
Reliable Event Publishing With the Outbox Pattern in .NET
A modern Australian e-commerce platform built on ASP.NET Core can chew through thousands of orders during a Melbourne peak trading hour, and every confirmed order is supposed to trigger a downstream integration event. The order lives in SQL Server, the event is supposed to fly out over Azure Service Bus, and somewhere between those two destinations things inevitably drift. A network blip on the NBN, a throttled Service Bus namespace, or a pod recycling mid-deploy can leave a confirmed purchase with no corresponding message in the broker, and the warehouse, the loyalty engine, and the analytics warehouse all quietly disagree about what was actually sold.
The classic symptom is a row in the database that nobody downstream has heard about, and developers in Sydney and Brisbane meetups have spent years trading war stories about reconciling these gaps with cron jobs. The outbox pattern solves the dual-write dilemma by storing the intent to publish a message inside the same database transaction that mutates the aggregate, then handing the actual transmission off to a separate process that reads from that store.
The Dual Write Problem and How Outbox Solves It
When a service needs to update its own state and notify the rest of the world at the same time, it almost never has a tool that does both atomically. SQL Server guarantees atomicity across rows in a single database, but it has no idea what is happening inside Azure Service Bus, RabbitMQ, or Kafka. Developers reach for a TransactionScope, wrap the database commit and the message send inside it, and convince themselves that this is two-phase. It is not. The broker call is not enlisted in the database transaction, so a failure between the commit and the send leaves the system inconsistent, and a failure between the send and the commit sends a message about state that was never persisted.
The outbox pattern sidesteps this trap by collapsing the two writes into one. Inside the aggregate's transaction, alongside the change to the order row, the domain code appends a row to an OutboxMessages table describing what should be published. The database transaction commits, and from that moment the business state and the pending notification are guaranteed to move together. A separate worker process polls the table, ships each row to the broker, and only then marks the row as dispatched. If the worker crashes, the row is still there on the next pass. If the broker is down, the row waits patiently. The contract between the two sides becomes at-least-once delivery rather than a hopeful guess.
Anatomy of an Outbox Implementation in C#
A clean implementation has three moving parts. First, the aggregate raises domain events during its command handlers, just like in any well-modelled DDD codebase. Second, an IUnitOfWork or SaveChangesAsync interceptor captures those events, serialises them to JSON, and inserts an OutboxMessage row for each one within the same DbContext.SaveChanges call. Third, a hosted background service, often an IHostedService registered through HostBuilder.ConfigureServices, periodically queries the outbox table, publishes the payloads to the chosen broker, and updates a status column once the broker confirms receipt.
The interesting design choices sit in the seams between those parts. How are events serialised so that schema evolution does not break older rows? How long is the polling interval, and should it be a polling loop, a change feed, or a SqlTableDependency trigger? How are partial failures batched so that one poison message does not stall every other order sitting behind it? The pattern itself is small, but the production-grade version of it deserves attention to each of those seams, which is exactly the kind of deep dive that the annual C# conference sessions tend to land on.
Comparing Messaging Strategies
Teams often weigh three approaches before settling on the outbox. The table below captures the trade-offs in plain terms so the choice is easier to defend in an architecture review.
| Approach | Atomicity with business write | Failure recovery | Throughput ceiling | Operational complexity |
|---|---|---|---|---|
| Direct broker call after commit | None, classic dual write | Manual reconciliation jobs | High, single hop | Low at first, painful later |
| Distributed transaction (DTC, XA) | Strong, true two-phase | Broker recovery via transaction | Moderate, slower commits | High, fragile coordinators |
| Transactional outbox + relay | Strong via shared database tx | Replay from outbox table | High, batched and parallel | Moderate, one extra worker |
| Change Data Capture stream | Strong via log tail | Replay from log position | Highest, near real-time | High, Debezium or similar tooling |
The outbox sits in the sweet spot for most .NET teams because it does not require a DTC coordinator, fits naturally on top of Entity Framework Core, and degrades gracefully when the broker is unavailable. Teams running on Azure tend to pair it with Service Bus sessions or Kafka topics, while shops with stricter data residency requirements, common in healthcare and finance across Australia, often keep the relay inside the same region as the primary database.
Modelling the Outbox Table and Entity Framework
The OutboxMessages table is intentionally dull. A typical schema carries an identifier, an aggregate type and identifier, a message type name, a JSON payload, a creation timestamp, a status flag, and a dispatched timestamp. The status flag distinguishes pending rows from completed ones and makes the relay query trivial. Adding an AttemptCount and a NextAttemptAt column turns the relay into a polite retry engine that respects exponential backoff without flooding the broker during a partial outage.
In Entity Framework Core, the outbox entity can be configured with ToTable("OutboxMessages") and a global query filter that hides dispatched rows by default, which keeps the change tracker lean. The interceptor that fills the table usually hooks the SavingChangesAsync event, walks every tracked entity, asks each one for its pending IDomainEvent collection through a small interface like IHasDomainEvents, and inserts an outbox row per event before the save actually executes. The aggregate never calls the broker, which keeps domain code blissfully unaware of messaging concerns and makes the pattern easy to retrofit into existing services that were built before message-driven architecture became fashionable.
Capturing Domain Events Inside a Transaction
The discipline that makes the pattern work is that domain events are raised inside the aggregate method, captured by a property on the entity, and only flushed to the outbox by the unit of work. A common implementation uses a base class like AggregateRoot with a private List<IDomainEvent> _events and a RaiseDomainEvent method. The command handler invokes order.Confirm(), which mutates state and raises OrderConfirmed, then calls await _unitOfWork.SaveChangesAsync(). The interceptor reads _events from the aggregate, clears the list, and writes them as outbox rows.
This shape has a nice side effect. Because events are persisted before the commit completes, they become part of the audit trail and can be replayed into a new environment during a disaster recovery exercise, which is a frequent requirement for APRA-regulated workloads. A Sydney fintech rebuilding its payments service after a regional outage can repopulate downstream systems simply by walking the outbox table from a point-in-time snapshot, which beats the alternative of squinting at logs and hoping nobody noticed the gap.
Building a Background Relay for At-Least-Once Delivery
The relay is a hosted service that runs a loop, picks up a batch of pending outbox rows ordered by creation time, and publishes them through an IMessagePublisher abstraction. After a successful publish it updates the row's status, and after a failure it bumps the attempt counter and schedules the next try. The loop runs forever, sleeps for a short interval when there is nothing to do, and uses a SemaphoreSlim or a CancellationTokenSource to shut down cleanly when the host stops. Most teams wrap the relay in its own deployment slot so that scaling the relay does not scale the API.
Concurrency deserves a real answer. Two relay pods competing on the same outbox table can publish the same message twice, which is acceptable as long as consumers are idempotent. If the team wants stronger ordering, an OUTPUT clause or a SELECT ... WITH (UPDLOCK, ROWLOCK) hint can serialise the claim so only one process owns a batch at a time. On Azure SQL, this is usually cheaper than reaching for Service Bus sessions, and it plays nicely with elastic pools common in Australian SMB deployments where the same SQL tier hosts dozens of small services.
Idempotency, Retries and Observability
At-least-once delivery means consumers will occasionally see the same event twice, and the contract must allow for that. Every payload should carry a stable identifier, usually the outbox row's primary key, and consumers should treat it as a deduplication key. A simple ProcessedMessages table, a Redis SETNX, or a Cosmos Upsert with a deterministic id all work, and the choice usually follows whatever the consumer already runs.
Retries need a ceiling. An outbox row that has failed fifty times probably points to a bug, a malformed schema, or a downstream system that has changed its contract, and the relay should mark it as poison and move on so the rest of the queue keeps flowing. Observability then becomes a matter of logging the move to poison state, raising a metric on attempt counts, and wiring a dashboard that shows the depth of the outbox table. A backlog that grows for more than a minute or two is a signal, and a backlog that grows for an hour is an incident. Australian teams that operate across AEDT and AWST timezones find that a 24-hour rolling dashboard is far more useful than a real-time chart, because the slow drift is what catches people out during the morning hand-over.
1, CBD, Maharaj Surajmal Road, Near Yamuna Sports Complex, Delhi, 110032
GENERAL QUERIES
Manish Tewatia
manish@csharpcon.com
+91-9718-431-042
TICKET QUERIES
Atul Gupta
conference@csharpcon.com
+91-9910-125-804