NSaga - Getting started
使用 NSaga 來做 Saga pattern,需先透過 NuGet 安裝 NSaga 套件。
PM> Install-Package NSaga
接著要定義 Transaction 中的每一個動作,也就是 NSaga 中的 Message。
這邊要注意 NSaga 必須特別定義 Transaction 中的第一個 Message,定義的方式就是造一個專屬的 Message Class,並實作 IInitiatingSagaMessage 介面。
public class StartSagaMessage: IInitiatingSagaMessage
{
public Guid CorrelationId { get; set; }
}
IInitiatingSagaMessage 介面只有一個屬性 CorrelationId,用來接 Transaction Id 用,可用來識別這次觸發的 Transaction。除了介面定義的屬性外,若是需要額外的資料也可以自己附加。
第一個 Message 定義完其它後面的 Message 定義方式就一樣了,只要造專屬的 Message Class,並實作 ISagaMessage 介面即可。
public class SagaMessage: ISagaMessage
{
public Guid CorrelationId { get; set; }
}
接著要定義 Transaction 要儲存的資訊,簡單造個 Model 類別即可。
public class SagaData
{
public List<string> Executed { get; } = new List<string>();
}
再來要定義 Transaction,也就是 NSaga 中的 Saga。造一個專屬的 Saga Class,實作 ISaga、InitatedBy、ConsumerOf 介面。
public class Saga: ISaga<SagaData>, InitiatedBy<StartSagaMessage>, ConsumerOf<SagaMessage>
{
...
}
Transaction 的 Message 由 InitatedBy、ConsumerOf 介面實作去定義,Transaction的第一個 Message 用 InitatedBy 去實作,其他的 Message 都用 ConsumerOf 介面去實作,對應的實作方法用來定義執行對應 Message 時所要做的動作。
...
public OperationResult Initiate(StartSagaMessage message)
{
Console.WriteLine(message.GetType().Name);
SagaData.Executed.Add(message.GetType().Name);
return new OperationResult();
}
...
像是下面這樣:
public class Saga: ISaga<SagaData>, InitiatedBy<StartSagaMessage>, ConsumerOf<SagaMessage>
{
public Guid CorrelationId { get; set; }
public Dictionary<string, string> Headers { get; set; }
public SagaData SagaData { get; set; }
public OperationResult Initiate(StartSagaMessage message)
{
Console.WriteLine(message.GetType().Name);
SagaData.Executed.Add(message.GetType().Name);
return new OperationResult();
}
public OperationResult Consume(SagaMessage message)
{
Console.WriteLine(message.GetType().Name);
SagaData.Executed.Add(message.GetType().Name);
return new OperationResult();
}
}
最後開始實際運行,取得 mediator 與 repository。
...
var builder = Wireup.UseInternalContainer();
var mediator = builder.ResolveMediator();
var repository = builder.ResolveRepository();
...
透過 mediator 依序調用 Message 即可。
...
mediator.Consume(new StartSagaMessage()
{
CorrelationId = correlationId,
});
...
若有需要可從 repository 取出儲存的資料。
...
var saga = repository.Find<Saga>(correlationId);
...
像是下面這樣:
using System;
namespace NSaga.Demo
{
class Program
{
static void Main(string[] args)
{
var builder = Wireup.UseInternalContainer();
var mediator = builder.ResolveMediator();
var repository = builder.ResolveRepository();
var correlationId = Guid.NewGuid();
mediator.Consume(new StartSagaMessage()
{
CorrelationId = correlationId,
});
mediator.Consume(new SagaMessage()
{
CorrelationId = correlationId
});
var saga = repository.Find<Saga>(correlationId);
Console.WriteLine(string.Join(", ", saga.SagaData.Executed.ToArray()));
}
}
}