DurableMediator.OutOfProcess.Testing
3.5.2
dotnet add package DurableMediator.OutOfProcess.Testing --version 3.5.2
NuGet\Install-Package DurableMediator.OutOfProcess.Testing -Version 3.5.2
<PackageReference Include="DurableMediator.OutOfProcess.Testing" Version="3.5.2" />
<PackageVersion Include="DurableMediator.OutOfProcess.Testing" Version="3.5.2" />
<PackageReference Include="DurableMediator.OutOfProcess.Testing" />
paket add DurableMediator.OutOfProcess.Testing --version 3.5.2
#r "nuget: DurableMediator.OutOfProcess.Testing, 3.5.2"
#:package DurableMediator.OutOfProcess.Testing@3.5.2
#addin nuget:?package=DurableMediator.OutOfProcess.Testing&version=3.5.2
#tool nuget:?package=DurableMediator.OutOfProcess.Testing&version=3.5.2
Durable Mediator
Durable Mediator is an extension to the Durable Task library which allows for running MediatR Requests as activities in orchestrations without any complex ceremony.
Variants
- Hosted service
- Azure Functions (out-of-process)
- Azure Functions (in-process)
Blog post
Getting started (Hosted service)
To get started with running orchestrations which call MediatR Requests as activities, which are called "Workflows", follow these steps:
First start by defining a workflow request:
public record WorkflowRequest(Guid SomeId) : IWorkflowRequest
{
public string WorkflowName => "Human readable workflow name";
public string InstanceId => SomeId.ToString();
};
Also, create a IRequest
that needs to be called from the workflow:
public record MediatorRequest(Guid SomeId) : IRequest;
Create a request handler that handles this MediatR request:
public class MediatorRequestHandler : IRequestHandler<MediatorRequest>
{
private readonly ILogger<MediatorRequestHandler> _logger;
public RequestAHandler(ILogger<MediatorRequestHandler> logger)
{
_logger = logger;
}
public Task<Unit> Handle(MediatorRequest request, CancellationToken cancellationToken)
{
_logger.LogInformation("Processing RequestA");
return Task.FromResult(Unit.Value);
}
}
Create a workflow that handles the WorkflowRequest
:
public class ExampleWorkflow : IWorkflow<WorkflowRequest>
{
public override async Task OrchestrateAsync(IWorkflowExecution<WorkflowRequest> execution)
{
var logger = execution.ReplaySafeLogger;
logger.LogInformation("Start with workflow");
await execution.SendAsync(new MediatorRequest(execution.Request.SomeId));
logger.LogInformation("Workflow done");
}
}
Create an ASP.NET endpoint that triggers this workflow:
app.MapPost("workflow", async ([FromServices] IWorkflowService workflowService) =>
{
var instanceId = await workflowService.StartWorkflowAsync(new WorkflowRequest(Guid.NewGuid()));
return Results.Accepted(null, instanceId);
});
In your asp.net host builder, add the required MediatR services by including
builder.Services.AddMediatR(config => config.RegisterServicesFromAssemblyContaining<WorkflowRequest>());
and register the workflow using builder.Services.AddWorkflow<ExampleWorkflow>();
.
Getting started (Azure Functions)
To get started with running orchestrations which call MediatR Requests as activities, which are called "Workflows", follow these steps:
First start by defining a workflow request:
public record WorkflowRequest(Guid SomeId) : IWorkflowRequest
{
public string WorkflowName => "Human readable workflow name";
public string InstanceId => SomeId.ToString();
};
Also, create a IRequest
that needs to be called from the workflow:
public record MediatorRequest(Guid SomeId) : IRequest;
Create a request handler that handles this MediatR request:
public class MediatorRequestHandler : IRequestHandler<MediatorRequest>
{
private readonly ILogger<MediatorRequestHandler> _logger;
public RequestAHandler(ILogger<MediatorRequestHandler> logger)
{
_logger = logger;
}
public Task<Unit> Handle(MediatorRequest request, CancellationToken cancellationToken)
{
_logger.LogInformation("Processing RequestA");
return Task.FromResult(Unit.Value);
}
}
Create a workflow that handles the WorkflowRequest
:
[DurableTask(nameof(ExampleWorkflow))]
public class ExampleWorkflow : Workflow<WorkflowRequest>
{
private readonly ILogger<ABCWorkflow> _logger;
public ExampleWorkflow(ILogger<ABCWorkflow> logger)
{
_logger = logger;
}
public override async Task OrchestrateAsync(IWorkflowExecution<WorkflowRequest> execution)
{
var logger = execution.OrchestrationContext.CreateReplaySafeLogger(_logger);
logger.LogInformation("Start with workflow");
await execution.SendAsync(new MediatorRequest(execution.Request.SomeId));
logger.LogInformation("Workflow done");
}
}
Create a Azure Function that triggers this workflow:
public static class WorkflowTrigger
{
[Function(nameof(WorkflowTrigger))]
public static async Task<IActionResult> TriggerOrchestratorAsync(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "workflow")] HttpRequestMessage req,
[DurableClient] DurableTaskClient client)
{
var startDetails = await client.ScheduleNewExampleWorkflowInstanceAsync(new WorkflowRequest(Guid.NewGuid()));
var response = req.CreateResponse(HttpStatusCode.Accepted);
response.WriteString(startDetails);
return response;
}
}
In your function app startup, add the required MediatR services by including
builder.Services.AddMediatR(config => config.RegisterServicesFromAssemblyContaining<WorkflowRequest>());
.
When running your function app you will see that next to the WorkflowTrigger Http Trigger function, an
Orchestration Trigger function called "WorkflowRequest" and a "DurableMediatorEntity" Entity Trigger
function are added. When http function triggers the start of the workflow, the orchestration function
will orchestrate the workflow and invoke ExampleWorkflow
. Each call to the execution.SendAsync
will trigger the durable mediator action to execute the MediatR Request in a separate activity after which
the orchestration resumes. No more calling context.CallActivity
and guessing what parameters to pass in.
The execution
exposes the TaskOrchestrationContext
from the Durable Task library, giving full access
to creating timers for durable delays, locking entities for critical sections, or wait for external events.
The execution
also exposes CallSubWorkflowAsync
, which allows workflows to initiate other workflows,
and even await their responses, making it easy to compose workflows.
Unit testing
See the HostedServiceWebapp.Tests or OutOfProcessFunctionApp.Tests in the example folder for how to test workflows using scenarios. A scenario looks like this:
public class ExampleWorkflowScenario : Scenario
{
private readonly Guid _requestId = Guid.NewGuid();
public override void Setup(IScenarioSetup scenarioSetup, Mock<TaskOrchestrationContext> taskOrchestrationContextMock)
{
}
public override IWorkflowRequest Request => new ExampleWorkflowRequest(_requestId);
public override IEnumerable<object> RunScenario(IScenarioRun scenarioRun)
{
yield return new MediatorRequest(_requestId);
}
}
Based on what the Setup configures and simulates, the RunScenario
should output what MediatR requests
the workflow should emit. Next to MediatR requests, things like delays, exceptions, calls to other workflows
and outputs can be completely unit tested.
Examples
See the OutOfProcessFunctionApp in the example folder for more examples.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- DurableMediator.OutOfProcess (>= 3.5.2)
- Moq (= 4.18.4)
- NUnit (>= 4.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated | |
---|---|---|---|
3.5.2 | 148 | 5/6/2025 | |
3.5.1 | 139 | 5/6/2025 | |
3.5.0 | 145 | 5/6/2025 | |
3.4.0 | 146 | 5/6/2025 | |
3.3.0 | 193 | 4/15/2025 | |
3.3.0-preview-1 | 188 | 4/15/2025 | |
3.2.0 | 161 | 4/8/2025 | |
3.1.0 | 165 | 4/16/2024 | |
3.1.0-preview-1 | 116 | 4/16/2024 | |
1.0.0 | 136 | 4/16/2024 |