Orbitra.DependencyInjection.Microsoft 1.0.0

dotnet add package Orbitra.DependencyInjection.Microsoft --version 1.0.0
                    
NuGet\Install-Package Orbitra.DependencyInjection.Microsoft -Version 1.0.0
                    
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="Orbitra.DependencyInjection.Microsoft" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Orbitra.DependencyInjection.Microsoft" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Orbitra.DependencyInjection.Microsoft" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Orbitra.DependencyInjection.Microsoft --version 1.0.0
                    
#r "nuget: Orbitra.DependencyInjection.Microsoft, 1.0.0"
                    
#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.
#:package Orbitra.DependencyInjection.Microsoft@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Orbitra.DependencyInjection.Microsoft&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Orbitra.DependencyInjection.Microsoft&version=1.0.0
                    
Install as a Cake Tool

Orbitra.DependencyInjection.Microsoft

License: Apache-2.0 NuGet - Orbitra.DependencyInjection.Microsoft

Orbitra.DependencyInjection.Microsoft provides a first-class adapter between Orbitra (Core) and Microsoft.Extensions.DependencyInjection (IServiceCollection).
It bundles the Core dispatcher & pipeline engine and runtime abstractions so you can wire Orbitra with one line into ASP.NET Core

This package includes:

  • Orbitra (Core) — dispatcher + pipeline engine
  • Orbitra.Abstractions — request, handler, pipeline, and dispatcher contracts

What this package adds

  • Source-generated DI extensions for IServiceCollection:
    • AddDispatcher() → registers IDispatcher, pipeline registry, and returns a IDispatcherConfigurator
    • AddHandlers(TypeLifetime?) → auto-registers discovered request handlers
  • Fluent pipeline builder on top of the Core engine
  • A minimal IServiceCollection adapter that binds open-generic pipeline behaviours with the requested lifetime

Install

dotnet add package Orbitra.DependencyInjection.Microsoft

You do not need to install Orbitra.Core or Orbitra.Abstractions separately — they’re included transitively.


Typical usage

using Orbitra.Abstractions.Dispatching;
using Orbitra.Abstractions.Requests;
using Orbitra.DependencyInjection.Microsoft.Generated; // generator adds the DI extensions

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddDispatcher() // IDispatcher + PipelineBehaviourRegistry
    .AddHandlers();  // discovered handlers (default: Transient)

var app = builder.Build();

app.MapGet("/users/{id:int}", async (int id, IDispatcher dispatcher, CancellationToken ct) =>
{
    return await dispatcher.DispatchAsync(new GetUserQuery(id), ct);
});

app.MapPost("/users", async (CreateUserCommand cmd, IDispatcher dispatcher, CancellationToken ct) =>
{
    return await dispatcher.DispatchAsync(cmd, ct);
});

app.Run();

// Example request/handler contracts live in Orbitra.Abstractions
public sealed record GetUserQuery(int Id) : IQuery<UserDto>;
public sealed record UserDto(int Id, string Name);

internal sealed class GetUserQueryHandler : IQueryHandler<GetUserQuery, UserDto>
{
    public Task<UserDto> HandleAsync(GetUserQuery req, CancellationToken token = default)
    {
        return Task.FromResult(new UserDto(req.Id, "Alice"));
    }
}

public sealed record CreateUserCommand(string UserName) : ICommand<string>;
internal sealed class CreateUserCommandHandler : ICommandHandler<CreateUserCommand, string>
{
    public Task<string> HandleAsync(CreateUserCommand cmd, CancellationToken token = default)
    {
        return Task.FromResult($"User {cmd.UserName} created!");
    }
}

Handler lifetime control

Global default (overrides the generator’s default):

// Register all handlers as Scoped, unless a handler class has [HandlerLifetime(...)]
builder.Services
    .AddDispatcher()
    .AddHandlers(TypeLifetime.Scoped);

Per-handler override with attribute:

using Microsoft.Extensions.DependencyInjection;
using Orbitra.Core;

// Will override global default TypeLifetime
[HandlerLifetime(TypeLifetime.Singleton)]
internal sealed class CreateUserCommandHandler
    : ICommandHandler<CreateUserCommand, string>
{
    public Task<string> HandleAsync(CreateUserCommand cmd, CancellationToken token = default)
    {
        return Task.FromResult($"User {cmd.UserName} created!");
    }
}

Pipelines (cross-cutting behaviours)

Define once, then target where and when they run via the fluent builder API.

Behaviour example

public sealed class LoggingBehaviour<TRequest, TResult>
    : IPipelineBehaviour<TRequest, TResult>
    where TRequest : IRequest<TResult>
{
    public async Task<TResult> HandleAsync(
        TRequest request,
        DispatchHandlerDelegate<TResult> next,
        CancellationToken token = default)
    {
        Console.WriteLine($"Handling {typeof(TRequest).Name}");
        var result = await next();
        Console.WriteLine($"Handled {typeof(TRequest).Name}");
        return result;
    }
}

Common recipes

Cache queries only when feature flag is on:

builder.Services
    .AddDispatcher()
    .AddHandlers()
    .AddPipelineBehaviour(typeof(QueryCachingBehaviour<,>))
        .EnabledWhen(_ => FeatureFlags.CachingEnabled);
        .IncludeQueries()

Metrics everywhere except health checks:

builder.Services
    .AddDispatcher()
    .AddHandlers()
    .AddPipelineBehaviour(typeof(MetricsBehaviour<,>))
        .UnlessRequestIs<GetServiceHealthQuery>();

Audit commands; during incidents audit everything (OtherwiseAll fallback):

builder.Services
    .AddDispatcher()
    .AddHandlers()
    .AddPipelineBehaviour(typeof(AuditBehaviour<,>))
        .IncludeCommands()
        .When(_ => !Ops.IncidentMode)
        .OtherwiseAll();

Rate-limit only heavy report queries:

builder.Services
    .AddDispatcher()
    .AddHandlers()
    .AddPipelineBehaviour(typeof(RateLimitBehaviour<,>))
        .WhenRequest<GenerateReportQuery>(static q => q.RangeDays > 7);

Rule primitives

Rule Meaning
EnabledWhen(predicate) Enable / disable entire chain. If this is false, nothing in that chain runs regardless of other rules.
Include<TRequest>() / Include(typeof(...), ...) Run only for selected requests
Exclude<TRequest>() / Exclude(typeof(...), ...) Run for all except selected requests
IncludeCommands() / IncludeQueries() Category-based includes
ExcludeCommands() / ExcludeQueries() Category-based excludes
When(predicate) Conditional activation
Unless(predicate) Conditional skip

And extensions: | Extension | Use case | |----------------------|----------| | WhenRequestIs<T> | Run only for one specific type. | | WhenRequest<T> | Run only for one type when the predicate is true. | | UnlessRequestIs<T> | Run for all except this one type. | | UnlessRequest<T> | Run for all except when request is this type and predicate is true. | | OtherwiseAll | Fallback to run on everything |

Predicates receive (Type requestType) => bool, (Type requestType, object request, IServiceProvider services) => bool or a simplified _ => bool, and async variances of these as well.


The generated extensions (what the generator emits)

The exact content varies per project; this is representative output.

// <auto-generated/>
#nullable enable
using Microsoft.Extensions.DependencyInjection;
namespace Orbitra.DependencyInjection.Microsoft.Generated;

internal static class ServiceCollectionExtensions
{
    public static global::Orbitra.Core.Pipelines.Abstractions.IDispatcherConfigurator AddDispatcher(this IServiceCollection services)
    {
        services.AddScoped<global::Orbitra.Abstractions.Dispatching.IDispatcher, global::Orbitra.Generated.Dispatcher>();

        var registry = new global::Orbitra.Core.Pipelines.PipelineBehaviourRegistry();
        services.AddSingleton<global::Orbitra.Core.Pipelines.Abstractions.IPipelineBehaviourRegistry>(registry);

        return new global::Orbitra.Core.Pipelines.Builders.DispatcherConfigurator(
            new global::Orbitra.DependencyInjection.Microsoft.MsDiServiceRegistrator(services),
            registry
        );
    }

    public static global::Orbitra.Core.Pipelines.Abstractions.IDispatcherConfigurator AddHandlers(
        this global::Orbitra.Core.Pipelines.Abstractions.IDispatcherConfigurator builder,
        global::Orbitra.Core.TypeLifetime typeLifetime = global::Orbitra.Core.TypeLifetime.Transient)
    {
        // Example registrations; the generator emits your project’s concrete handlers:
        // builder.Services.Add<IRequestHandler<CreateUserCommand, string>, CreateUserCommandHandler>(typeLifetime);
        // builder.Services.Add<IRequestHandler<GetUserQuery, UserModel>, GetUserQueryHandler>(typeLifetime);
        return builder;
    }
}

Under the hood: the IServiceCollection adapter

The adapter binds open generic behaviour families (e.g., IPipelineBehaviour<,>) with the requested lifetime:

using Microsoft.Extensions.DependencyInjection;
using Orbitra.Core;
using Orbitra.Core.Pipelines.Abstractions;

namespace Orbitra.DependencyInjection.Microsoft;

public sealed class MsDiServiceRegistrator(IServiceCollection services) : IServiceRegistrator
{
    public void AddOpenGeneric(Type serviceOpenGeneric, Type implementation, TypeLifetime lifetime)
    {
        services.Add(new ServiceDescriptor(serviceOpenGeneric, implementation, MapLifetime(lifetime)));
    }

    private static ServiceLifetime MapLifetime(TypeLifetime lifetime)
    {
        return lifetime switch
        {
            TypeLifetime.Scoped => ServiceLifetime.Scoped,
            TypeLifetime.Transient => ServiceLifetime.Transient,
            TypeLifetime.Singleton => ServiceLifetime.Singleton,
            _ => ServiceLifetime.Singleton
        };
    }
}

This is all that’s needed to bridge Orbitra’s Core pipeline engine with Microsoft’s DI container.


Package Description
Orbitra The runtime dispatcher and pipeline engine. Required for actual dispatching and pipeline execution.
Orbitra.Abstractions Lightweight runtime contracts for requests, handlers, and pipeline behaviours

License

Code © 2025 Robin Hörnkvist
Licensed under Apache License 2.0 — see LICENSE
Third-party notices — see NOTICE

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 159 10/31/2025