Orleans.EventSourcing.EventStore
7.1.2
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package Orleans.EventSourcing.EventStore --version 7.1.2
NuGet\Install-Package Orleans.EventSourcing.EventStore -Version 7.1.2
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Orleans.EventSourcing.EventStore" Version="7.1.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Orleans.EventSourcing.EventStore --version 7.1.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Orleans.EventSourcing.EventStore, 7.1.2"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Orleans.EventSourcing.EventStore as a Cake Addin #addin nuget:?package=Orleans.EventSourcing.EventStore&version=7.1.2 // Install Orleans.EventSourcing.EventStore as a Cake Tool #tool nuget:?package=Orleans.EventSourcing.EventStore&version=7.1.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
EventStore Provider for Microsoft Orleans EventSourcing
Silo Configuration
var eventStoreConnectionString = "esdb://123.60.184.85:2113?tls=false";
silo.AddEventStoreBasedLogConsistencyProvider(Constants.LogConsistencyStoreName,
options =>
{
options.ClientSettings = EventStoreClientSettings.Create(eventStoreConnectionString);
})
.AddMemoryGrainStorage(Constants.LogSnapshotStoreName);
Event sourcing samples:
Commands and events are immutable objects that can greatly improve efficiency in Orleans.
Commands:
[Immutable]
[GenerateSerializer]
public sealed record SnackInitializeCommand(string Name, Guid TraceId, DateTimeOffset OperatedAt, string OperatedBy)
: DomainCommand(TraceId, OperatedAt, OperatedBy);
[Immutable]
[GenerateSerializer]
public sealed record SnackChangeNameCommand(string Name, Guid TraceId, DateTimeOffset OperatedAt, string OperatedBy)
: DomainCommand(TraceId, OperatedAt, OperatedBy);
[Immutable]
[GenerateSerializer]
public sealed record SnackRemoveCommand(Guid TraceId, DateTimeOffset OperatedAt, string OperatedBy)
: DomainCommand(TraceId, OperatedAt, OperatedBy);
Events:
[Immutable]
[GenerateSerializer]
public sealed record SnackInitializedEvent(Guid Id, string Name, Guid TraceId, DateTimeOffset OperatedAt, string OperatedBy, int Version)
: SnackEvent(Id, TraceId, OperatedAt, OperatedBy, Version);
[Immutable]
[GenerateSerializer]
public sealed record SnackNameChangedEvent(Guid Id, string Name, Guid TraceId, DateTimeOffset OperatedAt, string OperatedBy, int Version)
: SnackEvent(Id, TraceId, OperatedAt, OperatedBy, Version);
[Immutable]
[GenerateSerializer]
public sealed record SnackRemovedEvent(Guid Id, Guid TraceId, DateTimeOffset OperatedAt, string OperatedBy, int Version)
: SnackEvent(Id, TraceId, OperatedAt, OperatedBy, Version);
Only by applying events can Grain State objects be modified, which is the basis of Event Sourcing.
Grain State:
[GenerateSerializer]
public sealed class Snack
{
public Snack(Guid id, string name, string? pictureUrl = null)
{
Id = Guard.Against.Empty(id, nameof(id));
Name = Guard.Against.NullOrEmpty(name, nameof(name));
PictureUrl = pictureUrl;
}
[Id(0)]
public Guid Id { get; set; }
[Id(1)]
public DateTimeOffset? CreatedAt { get; set; }
[Id(2)]
public string? CreatedBy { get; set; }
public bool IsCreated => CreatedAt != null;
[Id(3)]
public DateTimeOffset? LastModifiedAt { get; set; }
[Id(4)]
public string? LastModifiedBy { get; set; }
[Id(5)]
public DateTimeOffset? DeletedAt { get; set; }
[Id(6)]
public string? DeletedBy { get; set; }
[Id(7)]
public bool IsDeleted { get; set; }
[Id(8)]
public string Name { get; set; } = string.Empty;
[Id(9)]
public string? PictureUrl { get; set; }
public override string ToString()
{
return $"Snack with Id:{Id} Name:'{Name}'";
}
#region Apply
public void Apply(SnackInitializedEvent evt)
{
Id = evt.Id;
Name = evt.Name;
CreatedAt = evt.OperatedAt;
CreatedBy = evt.OperatedBy;
}
public void Apply(SnackRemovedEvent evt)
{
DeletedAt = evt.OperatedAt;
DeletedBy = evt.OperatedBy;
IsDeleted = true;
}
public void Apply(SnackNameChangedEvent evt)
{
Name = evt.Name;
LastModifiedAt = evt.OperatedAt;
LastModifiedBy = evt.OperatedBy;
}
#endregion
}
Grain Interface:
public interface ISnackGrain : IGrainWithGuidKey
{
[AlwaysInterleave]
Task<Result<Snack>> GetAsync();
[AlwaysInterleave]
Task<Result<ImmutableList<SnackEvent>>> GetEventsAsync(int fromVersion, int toVersion);
[AlwaysInterleave]
Task<bool> CanInitializeAsync();
Task<Result<bool>> InitializeAsync(SnackInitializeCommand cmd);
[AlwaysInterleave]
Task<bool> CanRemoveAsync();
Task<Result<bool>> RemoveAsync(SnackRemoveCommand cmd);
[AlwaysInterleave]
Task<bool> CanChangeNameAsync();
Task<Result<bool>> ChangeNameAsync(SnackChangeNameCommand cmd);
}
Grain:
[LogConsistencyProvider(ProviderName = Constants.LogConsistencyStoreName)]
[StorageProvider(ProviderName = Constants.LogSnapshotStoreName)]
public class SnackGrain : JournaledGrain<Snack, SnackEvent>, ISnackGrain
{
private readonly ILogger<SnackGrain> _logger;
/// <inheritdoc />
public SnackGrain(ILogger<SnackGrain> logger)
{
_logger = Guard.Against.Null(logger, nameof(logger));
}
/// <inheritdoc />
public Task<Result<Snack>> GetAsync()
{
var id = this.GetPrimaryKey();
return Task.FromResult(Result.Ok(State).Ensure(State.IsCreated, $"Snack {id} is not initialized."));
}
/// <inheritdoc />
public Task<Result<ImmutableList<SnackEvent>>> GetEventsAsync(int fromVersion, int toVersion)
{
return Result.Ok().MapTryAsync(() => RetrieveConfirmedEvents(fromVersion, toVersion)).MapTryAsync(list => list.ToImmutableList());
}
/// <inheritdoc />
public Task<bool> CanInitializeAsync()
{
return Task.FromResult(State.IsDeleted == false && State.IsCreated == false);
}
/// <inheritdoc />
public Task<Result<bool>> InitializeAsync(SnackInitializeCommand cmd)
{
var id = this.GetPrimaryKey();
return Result.Ok()
.Ensure(State.IsDeleted == false, $"Snack {id} has already been removed.")
.Ensure(State.IsCreated == false, $"Snack {id} already exists.")
.Ensure(State.Name.Length <= 100, $"The name of snack {id} is too long.")
.BindTryAsync(() => PublishPersistedAsync(new SnackInitializedEvent(id, cmd.Name, cmd.TraceId, DateTimeOffset.UtcNow, cmd.OperatedBy, Version)));
}
/// <inheritdoc />
public Task<bool> CanRemoveAsync()
{
return Task.FromResult(State.IsDeleted == false && State.IsCreated);
}
/// <inheritdoc />
public Task<Result<bool>> RemoveAsync(SnackRemoveCommand cmd)
{
var id = this.GetPrimaryKey();
return Result.Ok()
.Ensure(State.IsDeleted == false, $"Snack {id} has already been removed.")
.Ensure(State.IsCreated, $"Snack {id} is not initialized.")
.BindTryAsync(() => PublishPersistedAsync(new SnackRemovedEvent(id, cmd.TraceId, DateTimeOffset.UtcNow, cmd.OperatedBy, Version)));
}
/// <inheritdoc />
public Task<bool> CanChangeNameAsync()
{
return Task.FromResult(State.IsDeleted == false && State.IsCreated);
}
/// <inheritdoc />
public Task<Result<bool>> ChangeNameAsync(SnackChangeNameCommand cmd)
{
var id = this.GetPrimaryKey();
return Result.Ok()
.Ensure(State.IsDeleted == false, $"Snack {id} has already been removed.")
.Ensure(State.IsCreated, $"Snack {id} is not initialized.")
.Ensure(State.Name.Length <= 100, $"The name of snack {id} is too long.")
.BindTryAsync(() => PublishPersistedAsync(new SnackNameChangedEvent(id, cmd.Name, cmd.TraceId, DateTimeOffset.UtcNow, cmd.OperatedBy, Version)));
}
protected Task<Result<bool>> PublishPersistedAsync(SnackEvent evt)
{
return Result.Ok().MapTryAsync(() => RaiseConditionalEvent(evt));
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net7.0
- EventStore.Client.Grpc.Streams (>= 23.0.0)
- Google.Protobuf (>= 3.22.1)
- Grpc.Core.Api (>= 2.52.0)
- Grpc.Net.Client (>= 2.52.0)
- Microsoft.Orleans.EventSourcing (>= 7.1.1)
- Microsoft.Orleans.Sdk (>= 7.1.1)
- System.Threading.Tasks.Extensions (>= 4.5.4)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Orleans.EventSourcing.EventStore:
Package | Downloads |
---|---|
SiloX.Orleans.EventSourcing.EventStore
EventStore event-sourcing module that for Microsoft Orleans. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Add provider name to log consistent stream name. and upgraded to Orleans 7.1.1