Skip to content
/ Space Public
forked from salihcantekin/Space

High-performance, source-generator powered mediator / messaging framework for .NET. Eliminates runtime reflection, minimizes boilerplate, and provides an extensible module + pipeline model for cross-cutting concerns (e.g., caching, auditing).

License

Notifications You must be signed in to change notification settings

sametuca/Space

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Space

High-performance, source-generator powered mediator / messaging framework for .NET. Eliminates runtime reflection, minimizes boilerplate, and provides an extensible module + pipeline model for cross-cutting concerns (e.g., caching, auditing).


Status & Packages

CI Branch Status
Prod (Stable Publish) master Prod CI
Dev (Preview Publish) dev Dev CI
Validation (PR / Feature) PRs -> dev / master Validation Build

NuGet Packages

Package Stable Preview Downloads Description
Space.Abstraction NuGet NuGet (pre) Downloads Core abstractions + Source Generator analyzer (attributes, contexts, contracts)
Space.DependencyInjection NuGet NuGet (pre) Downloads DI extensions & runtime implementations (ISpace)
Space.Modules.InMemoryCache NuGet NuGet (pre) Downloads In-memory caching module + attribute integration

Breaking Change (Packaging)

Old behavior: Space.DependencyInjection implicitly brought abstractions + source generator. New behavior: Source generator analyzer ships with Space.Abstraction. You must reference BOTH packages for full DI usage.

Migration:

  1. Add Space.Abstraction to all projects that use Space attributes.
  2. Add Space.DependencyInjection only where you need ISpace and registration extensions.
  3. Remove any direct Space.SourceGenerator references; they are now unnecessary.

Install (Minimal DI Usage)

dotnet add package Space.Abstraction

dotnet add package Space.DependencyInjection

Optional module:

dotnet add package Space.Modules.InMemoryCache

If you only need compile-time generation (e.g., custom runtime) reference just Space.Abstraction.


Quick Start

using Microsoft.Extensions.DependencyInjection;
using Space.Abstraction;
using Space.Abstraction.Attributes;
using Space.Abstraction.Context;
using Space.Abstraction.Contracts;

var services = new ServiceCollection();
services.AddSpace(opt =>
{
    opt.NotificationDispatchType = NotificationDispatchType.Parallel; // or Sequential
});

services.AddSpaceInMemoryCache(); // if caching module needed

var provider = services.BuildServiceProvider();
var space = provider.GetRequiredService<ISpace>();

public sealed record UserLoginRequest(string UserName) : IRequest<UserLoginResponse>;
public sealed record UserLoginResponse(bool Success);

public class UserHandlers
{
    [Handle]
    public ValueTask<UserLoginResponse> Login(HandlerContext<UserLoginRequest> ctx)
        => ValueTask.FromResult(new UserLoginResponse(true));
}

// Interface-based (optional, for method signature hint only - [Handle] attribute is still required)
public class UserHandlersInterface : IHandler<UserLoginRequest, UserLoginResponse>
{
    [Handle]
    public ValueTask<UserLoginResponse> Handle(HandlerContext<UserLoginRequest> ctx)
        => ValueTask.FromResult(new UserLoginResponse(true));
}

var response1 = await space.Send<UserLoginResponse>(new UserLoginRequest("demo"));
var response2 = await space.Send<UserLoginRequest, UserLoginResponse>(new UserLoginRequest("demo"));

Named Handlers

public class PricingHandlers
{
    [Handle(Name = "Default")] public ValueTask<PriceResult> GetDefault(HandlerContext<PriceQuery> ctx) => ...;
    [Handle(Name = "Discounted")] public ValueTask<PriceResult> GetDiscounted(HandlerContext<PriceQuery> ctx) => ...;
}
var discounted = await space.Send<PriceResult>(new PriceQuery(...), name: "Discounted");

Pipelines

public class LoggingPipeline
{
    [Pipeline(Order = 100)]
    public async ValueTask<UserLoginResponse> Log(PipelineContext<UserLoginRequest> ctx, PipelineDelegate<UserLoginRequest, UserLoginResponse> next)
    {
        var result = await next(ctx);
        return result;
    }
}

Notifications

public sealed record UserLoggedIn(string UserName);
public class LoginNotifications
{
    [Notification]
    public ValueTask Log(NotificationContext<UserLoggedIn> ctx) => ValueTask.CompletedTask;
}
await space.Publish(new UserLoggedIn("demo"));

Caching Module Example

public class UserQueries
{
    [Handle]
    [CacheModule(Duration = 60)]
    public ValueTask<UserProfile?> GetUser(HandlerContext<UserId> ctx) => ...;
}

[CacheModule] (from Space.Modules.InMemoryCache) inserts caching logic before user pipelines.


Multi-Project Setup

Space supports handlers, pipelines, notifications, and modules across multiple projects through a root aggregator model. This enables modular solutions where feature libraries can contain their own handlers without manual DI wiring.

Configuration

Set exactly one project as the root aggregator (typically your host/composition root):

<PropertyGroup>
  <SpaceGenerateRootAggregator>true</SpaceGenerateRootAggregator>
</PropertyGroup>

All other handler libraries should either omit this property or set it to false:

<PropertyGroup>
  <SpaceGenerateRootAggregator>false</SpaceGenerateRootAggregator>
</PropertyGroup>

How It Works

  • Root project generates DependencyInjectionExtensions.g.cs with automatic assembly discovery
  • Satellite libraries generate lightweight SpaceAssemblyRegistration_<Assembly>.g.cs files
  • At runtime, the root automatically discovers and registers handlers from all referenced assemblies

Example Structure

/MySolution
  src/AppHost/               (root: SpaceGenerateRootAggregator=true)
  src/Features/Users/        (satellite: handlers, pipelines)
  src/Features/Billing/      (satellite: handlers, modules)
  src/Infrastructure/        (satellite: notifications)

For complete details, migration guidance, and troubleshooting, see MultiProjectSetup.md.


Key Features

  • Zero runtime reflection for discovery (Roslyn source generator)
  • Minimal boilerplate: annotate methods directly with [Handle], [Pipeline], [Notification]
  • Named handlers (multiple strategies for same request/response)
  • Orderable pipelines + early system module execution
  • Extensible module model (e.g., cache) before user pipelines
  • High-performance async signatures (ValueTask)
  • Parallel or sequential notification dispatch
  • Multi-project root aggregator property <SpaceGenerateRootAggregator>
  • Multi-targeting (netstandard2.0 + modern .NET)

Performance Philosophy

Space front-loads cost at build time to reduce runtime overhead:

  • Compile-time metadata (registrations, maps)
  • No reflection-based runtime scanning
  • Low allocation pathways (current & planned pooling)

Benchmarks compare against other mediator libraries in tests/Space.Benchmarks.


Documentation

Primary docs in docs/:

Topic Link
Project Overview ProjectDoc.en.md
Handlers Handlers
Pipelines Pipelines
Notifications Notifications
Modules Modules
Multi-Project Setup MultiProjectSetup
Developer Recommendations DeveloperRecommendations
Known Issues KnownIssues
Planned Improvements PlannedImprovements

Per-package:


Roadmap & Issues

See GitHub Issues for:

  • Planned improvements (attribute parameters, global defaults, Options pattern)
  • Known issues (initial Lazy ISpace null, module scoping bugs)

Contributions welcome via issues & PRs.


Versioning & Releases

  • master: tagged semantic versions (vX.Y.Z) ? stable NuGet
  • dev: preview releases (X.Y.Z-preview)
  • Feature branches: validation build only

License

MIT.


Disclaimer

APIs may evolve while early preview features stabilize. Track releases for changes.


Space (Short)

Space is a high-performance, source-generator powered mediator/messaging framework for .NET.

Quick links

  • Handlers: docs/Handlers.md
  • Pipelines: docs/Pipelines.md
  • Notifications: docs/Notifications.md
  • Known Issues: docs/KnownIssues.md
  • Developer Recommendations: docs/DeveloperRecommendations.md

Build

See .github/copilot-instructions.md for environment and common commands.

About

High-performance, source-generator powered mediator / messaging framework for .NET. Eliminates runtime reflection, minimizes boilerplate, and provides an extensible module + pipeline model for cross-cutting concerns (e.g., caching, auditing).

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C# 100.0%