# Simple Saga Usage
## Introduction
This sample shows a simple saga to manage an order.
Once the project is started, press Enter to send a `StartOrder` message with a randomly assigned `OrderId`. This message starts a new instance of the `OrderSaga` saga as specified by the `IAmStartedByMessages` interface and mapping that [correlates](/nservicebus/sagas/message-correlation.md) `StartOrder.OrderId` property on the message with `OrderSagaData.OrderId` property on the saga data.
When processing the `StartOrder` message each saga instance requests a 30-second `CancelOrder` timeout that will [mark the saga as complete](/nservicebus/sagas/index.md#ending-a-saga) if the saga is not already complete.
The output to the console will be
```
Storage locations:
Learning Persister: SolutionDir\Sample\bin\Debug\.sagas
Learning Transport: SolutionDir\
Press 'Enter' to send a StartOrder message
Press any other key to exit
Sent StartOrder with OrderId 8d80b684-cc77-4ec6-867b-090bc38d914c.
OrderSaga StartOrder received with OrderId 8d80b684-cc77-4ec6-867b-090bc38d914c
OrderSaga Sending a CompleteOrder that will be delayed by 10 seconds
Stop the endpoint now to see the saga data in:
SolutionDir\Sample\bin\Debug\.sagas\OrderSaga\f5e7ea90-b866-16a0-c911-452f954b95da.json
OrderSaga Requesting a CancelOrder that will be executed in 30 seconds.
Stop the endpoint now to see the timeout data in the delayed directory
SolutionDir\.delayed\20170510054055
```
## Endpoint configuration
```cs
endpointConfiguration.UsePersistence();
endpointConfiguration.UseTransport(new LearningTransport());
endpointConfiguration.UseSerialization();
```
## The Saga
```cs
public class OrderSaga :
Saga,
IAmStartedByMessages,
IHandleMessages,
IHandleTimeouts
{
private readonly ILogger logger;
public OrderSaga(ILogger logger)
{
this.logger = logger;
}
protected override void ConfigureHowToFindSaga(SagaPropertyMapper mapper)
{
mapper.MapSaga(sagaData => sagaData.OrderId)
.ToMessage(message => message.OrderId)
.ToMessage(message => message.OrderId);
}
public async Task Handle(StartOrder message, IMessageHandlerContext context)
{
// Correlation property Data.OrderId is automatically assigned with the value from message.OrderId;
logger.LogInformation("StartOrder received with OrderId {OrderId}", message.OrderId);
logger.LogInformation("Sending a CompleteOrder that will be delayed by 10 seconds. Stop the endpoint now to see the saga data in: {SagaLocation}", LearningLocationHelper.GetSagaLocation(Data.Id));
var completeOrder = new CompleteOrder
{
OrderId = Data.OrderId
};
var sendOptions = new SendOptions();
sendOptions.DelayDeliveryWith(TimeSpan.FromSeconds(10));
sendOptions.RouteToThisEndpoint();
await context.Send(completeOrder, sendOptions);
var timeout = DateTimeOffset.UtcNow.AddSeconds(30);
logger.LogInformation($@"Requesting a CancelOrder that will be executed in 30 seconds.
Stop the endpoint now to see the timeout data in the delayed directory
{LearningLocationHelper.TransportDelayedDirectory(timeout)}");
await RequestTimeout(context, timeout);
}
public Task Handle(CompleteOrder message, IMessageHandlerContext context)
{
logger.LogInformation("CompleteOrder received with OrderId {OrderId}", message.OrderId);
MarkAsComplete();
return Task.CompletedTask;
}
public Task Timeout(CancelOrder state, IMessageHandlerContext context)
{
logger.LogInformation("CompleteOrder not received soon enough OrderId {OrderId}. Calling MarkAsComplete", Data.OrderId);
MarkAsComplete();
return Task.CompletedTask;
}
}
```
## Location Helper
This is a helper class used by the sample to derive the storage locations of the [Learning Transport](/transports/learning/index.md) and the [Learning Persistence](/persistence/learning/index.md).
```cs
public static class LearningLocationHelper
{
public static string TransportDirectory;
public static string SagaDirectory;
static LearningLocationHelper()
{
var location = Assembly.GetExecutingAssembly().Location;
var runningDirectory = Directory.GetParent(location).FullName;
SagaDirectory = Path.Combine(runningDirectory, ".sagas");
TransportDirectory = Path.GetFullPath(Path.Combine(runningDirectory, @"..\..\..\"));
}
public static string TransportDelayedDirectory(DateTimeOffset dateTime)
{
return Path.Combine(TransportDirectory, ".delayed", dateTime.UtcDateTime.ToString("yyyyMMddHHmmss"));
}
public static string GetSagaLocation(Guid sagaId)
where T : Saga
{
return Path.Combine(SagaDirectory, typeof(T).Name, $"{sagaId}.json");
}
}
```