When developing microservices locally using the Aspire framework, it’s often convenient to emulate Azure services like Blob Storage, Table Storage, Cosmos DB and Event Hubs. While the Blob Storage emulator started successfully in my environment, I ran into a puzzling issue with the EventHub emulator — it simply didn’t start, and the system failed without any clear diagnostics at first glance.

The Initial Symptom: A Silent Failure

The only visible symptom during startup was a terse error message:

System.Threading.Tasks.TaskCanceledException: A task was canceled.

Alt

While unhelpful on the surface, digging deeper into the console logs revealed the actual root cause buried in a more descriptive exception:

 Unhandled exception. FluentAssertions.Execution.AssertionFailedException: Expected collection not to be <null> because EventHubs entities list cannot be null or empty, and should contain at least one EventHub.
    at FluentAssertions.Execution.FallbackTestFramework.Throw(String message)
    at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message)
    at FluentAssertions.Execution.DefaultAssertionStrategy.HandleFailure(String message)
    at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
    at FluentAssertions.Execution.AssertionScope.FailWith(Func`1 failReasonFunc)
    at FluentAssertions.Execution.AssertionScope.FailWith(String message)
    at FluentAssertions.Primitives.ReferenceTypeAssertions`2.NotBeNull(String because, Object[] becauseArgs)
    at FluentAssertions.Collections.GenericCollectionAssertions`3.NotBeNullOrEmpty(String because, Object[] becauseArgs)
    at a.D.aDK.a.A(NamespaceConfig)
    at System.Collections.Generic.List`1.ForEach(Action`1 action)
    at a.D.aDK.A(EmulatorEventhubConfig)
    at a.D.aDL.A(EmulatorEventhubConfig)
    at a.D.aDL.A(String[])
    at a.D.aDL.<Main>(String[])

This gave me a critical hint: the emulator expected at least one EventHub to be defined, similar to how Blob and Table Storage emulators require containers or tables to be added for them to be useful.

Expected collection not to be because EventHubs entities list cannot be null or empty, and should contain at least one EventHub.

Root Cause: Missing Hub Configuration

The FluentAssertions error indicated that the EventHubs configuration was missing a required sub-resource: the EventHub itself. Although I had set up the EventHub emulator, I hadn’t actually defined a hub.

var eventHubs = builder.ExecutionContext.IsPublishMode 
    ? builder.AddConnectionString("event-hubs")
    : builder.AddAzureEventHubs("event-hubs")
        .RunAsEmulator()
        .AddHub("hub");

This change created the necessary internal structure, allowing the EventHub emulator to initialize properly.

Next Problem: EventProcessorClient Requires Storage

With the EventHub emulator now properly configured, I ran into another issue when wiring up the EventProcessorClient:

System.InvalidOperationException: ‘An EventProcessorClient could not be configured. Ensure a valid ‘BlobServiceClient’ is available in the ServiceProvider or provide the service key of the ‘BlobServiceClient’ in the ‘Aspire:Azure:Messaging:EventHubs:EventProcessorClient:BlobClientServiceKey’ configuration section, or use the settings callback to configure it in code.’

This exception made it clear that the EventProcessorClient depends on Blob Storage to store checkpoints. Without a configured BlobServiceClient, it couldn’t function.

Provide a Blob Storage Reference for Checkpoints

To address this, I explicitly added a Blob Storage emulator instance with a named container for checkpoints:

var ehBlobStorage = builder.ExecutionContext.IsPublishMode
    ? builder.AddConnectionString("ehstorage")
    : builder.AddAzureStorage("ehstorage")
    .RunAsEmulator()
    .AddBlobs("checkpoints");

Then, I passed this into the microservice along with the EventHubs reference:

builder.AddProject<Projects.Microsoft_Sovereign_ImmutableLedger_BlobSink>("blob-sink")
    .WithReference(eventHubs) // EventHubs Consumer`
    .WaitFor(eventHubs) 
    .WithReference(ehBlobStorage); // Blob Storage for storage

Inside the microservice’s Program.cs, I loaded both dependencies as expected:

builder.AddAzureBlobClient("checkpoints");
builder.AddAzureEventProcessorClient("messages");

This provided the necessary pieces for the EventProcessorClient to function correctly: an EventHub to consume from, and a Blob Storage container to persist checkpoint state.

Conclusion

Running the EventHub emulator locally requires more than just spinning up the emulator itself. You must:

  1. Define at least one EventHub using .AddHub(“hub”).
  2. Provide a Blob Storage resource and explicitly add a container for EventHub checkpoints if you plan on using EventProcessorClient.
  3. Ensure that both the EventHub and Blob Storage services are referenced by your microservice and loaded correctly in the application startup.

By carefully wiring these resources together, you can emulate EventHub-based messaging locally, with checkpointing and resiliency mechanisms intact — mimicking the real Azure experience within your development environment.

Aspire documentation was light on details about the additional requirement of Blob Storage when using the EventProcessorClient so don’t take it for granted that the Aspire documentation will tell you the whole story, you might run into service specific issues that require technical domain knowledge in the target service.