Skip to content

Instantly share code, notes, and snippets.

View egil's full-sized avatar

Egil Hansen egil

View GitHub Profile
@egil
egil / DelayedStreamProviderStarter.cs
Created November 4, 2025 15:54
Delay stream ingestion start example for Orleans
using Microsoft.Extensions.Logging;
using Orleans.Providers.Streams.Common;
// ReSharper disable once CheckNamespace
namespace Orleans.Providers.Streams;
internal sealed partial class DelayedStreamProviderStarter(
string name,
IControllable streamProvider,
TimeSpan delayedStart,
@egil
egil / Using-IStreamFilter-in-Orleans.md
Last active November 23, 2025 22:23
This document provides comprehensive guidance on using `IStreamFilter` in Orleans based on research of the Orleans GitHub repository and official documentation. Created by Claude Sonnet 4.5..

Using IStreamFilter in Orleans

This document provides comprehensive guidance on using IStreamFilter in Orleans based on research of the Orleans GitHub repository and official documentation.

Disclaimer: Created by Claude Sonnet 4.5 - AI makes mistakes, etc., not validated info. The prompt was as follows:

Investigate how to use IStreamFilter (need to check the dotnet/orleans codebase on github) to filter out specific events from certain stream providers. there is no documentation of the feature, so you need to go look at the source code in the orleans github repo and look at test cases that uses the feature to understand how it works. provide some sample code for me to look at

@egil
egil / ExampleTest.cs
Last active September 25, 2025 13:09
How to create stable tests that waits for an stream message has been handled by the grain that is being tested, before proceeding.
public class ExampleTest(SiloFixture fixture) : IClassFixture<SiloFixture>
{
[Fact]
public async Task Sending_data_to_stream()
{
var message = "foo bar baz";
var stream = fixture.GetStream<string>("grainId1");
await stream.OnNextAsync(message);
@egil
egil / UserGrain.cs
Created September 24, 2025 13:48
Orleans Event Sourcing + CQRS + Outbox
/// <summary>
/// Example implementation of an event-sourced grain that manages user state.
/// This grain demonstrates the key concepts of event sourcing:
/// 1. State is derived from a sequence of events rather than stored directly
/// 2. Each method that modifies state creates events that are processed
/// 3. The projection (User) is rebuilt by applying events through handlers
/// 4. Events can be processed individually or in batches with different transactional scopes
/// </summary>
public sealed class UserGrain(TimeProvider timeProvider) : EventGrain<UserGrain, User>(), IUserGrain
{
@egil
egil / ExampleGrain.cs
Created August 26, 2025 07:20
Activate grain on silo startup
public interface IExampleGrain : IStartupGrain, IGrainWithIntegerKey { }
public class ExampleGrain : Grain, IExampleGrain
{
public override Task OnActivateAsync(CancellationToken cancellationToken)
{
// do things
}
}
@egil
egil / ExampleTest.cs
Last active September 24, 2025 23:24
Orleans test set up for xUnit 3 using class fixture, stream support, observable storage writing, service injection
public class ExampleTest(SiloFixture fixture) : IClassFixture<SiloFixture>
{
[Fact]
public async Task Sending_data_to_stream()
{
var message = "foo bar baz";
var stream = fixture.GetStream<string>("grainId1");
await stream.OnNextAsync(message);
@egil
egil / StorageObserver.cs
Last active February 14, 2025 08:16
Make any Orleans grain storage observable during testing
using Orleans.Storage;
using R3;
namespace Egil.Orleans.Storage.Testing;
public sealed class StorageObserver(string storageName, IGrainStorage observableTarget) : IGrainStorage
{
private readonly Subject<StorageOperation> operationsFeed = new();
public Observable<StorageOperation> StorageOperationFeed => operationsFeed.AsObservable();
@egil
egil / ObservableMemoryStorage.cs
Created February 13, 2025 15:56
A fake/observable implementation of Orleans IGrainStorage that can be used during testing
using System.Collections.Concurrent;
using System.Globalization;
using Orleans.Storage;
// https://www.nuget.org/packages/R3
using R3;
using Xunit.Sdk;
namespace Egil.Orleans.Storage.Testing;
public sealed class ObservableMemoryStorage : IGrainStorage
@egil
egil / Program.cs
Last active November 18, 2025 14:21
Custom "Import database" and "Import BacPac" Aspire commands for a SQL Server Database resource. The first will create a bacpac from a source database and import that bacpac into the Aspire SQL Database resource. The latter will use an existing bacpac file and import that.
var builder = DistributedApplication.CreateBuilder(args);
var sqlPassword = builder.AddParameter("sql-password", secret: true);
var sqlserver = builder
.AddSqlServer("sqlserver", password: sqlPassword)
.WithDataVolume()
.WithLifetime(ContainerLifetime.Persistent);
var importSourceConnectionString = "Server=[REPLACE].database.windows.net;Authentication=Active Directory Interactive;Database=[REPLACE];Encrypt=True;"
var db = sqlserver
@egil
egil / RecordList.cs
Last active March 22, 2024 11:37
RecordList - a List<T> that supports deep equality and hashing that include items in the list. The equality is does not take order of items into consideration. Useful in combination with C# record types.
public sealed class RecordList<T> : List<T>, IEquatable<RecordList<T>>
where T : IEquatable<T>
{
private static readonly int EmptyRecordListHashCode = typeof(RecordList<T>).FullName!.GetHashCode(StringComparison.Ordinal);
public RecordList()
{
}
public RecordList(IEnumerable<T> collection)