Stashbox.AspNetCore.Hosting 4.2.2

.NET Standard 2.1 .NET Framework 4.6.1
Install-Package Stashbox.AspNetCore.Hosting -Version 4.2.2
dotnet add package Stashbox.AspNetCore.Hosting --version 4.2.2
<PackageReference Include="Stashbox.AspNetCore.Hosting" Version="4.2.2" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Stashbox.AspNetCore.Hosting --version 4.2.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Stashbox.AspNetCore.Hosting, 4.2.2"
#r directive can be used in F# Interactive, C# scripting and .NET Interactive. Copy this into the interactive tool or source code of the script to reference the package.
// Install Stashbox.AspNetCore.Hosting as a Cake Addin
#addin nuget:?package=Stashbox.AspNetCore.Hosting&version=4.2.2

// Install Stashbox.AspNetCore.Hosting as a Cake Tool
#tool nuget:?package=Stashbox.AspNetCore.Hosting&version=4.2.2
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

stashbox-extensions-dependencyinjection

Appveyor build status GitHub Workflow Status Tests Sourcelink

This repository contains Stashbox integrations for ASP.NET Core, .NET Generic Host and simple ServiceCollection based applications.

Package Version
Stashbox.Extensions.Dependencyinjection NuGet Version
Stashbox.Extensions.Hosting NuGet Version
Stashbox.AspNetCore.Hosting NuGet Version
Stashbox.AspNetCore.Multitenant NuGet Version

Options turned on by default:

  • Automatic tracking and disposal of IDisposable and IAsyncDisposable services.
  • Lifetime validation for Developement environments, but can be extended to all environment types.

Table of Contents

ASP.NET Core

The following example shows how you can integrate Stashbox (with the Stashbox.Extensions.Hosting package) as the default IServiceProvider implementation into your ASP.NET Core application:

ASP.NET Core 5
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(String[] args)
    {
        return Host.CreateDefaultBuilder(args)
            .UseStashbox(container => // Optional configuration options.
            {
                // This one enables the lifetime validation for production environments too.
                container.Configure(config => config.WithLifetimeValidation());
            })
            .ConfigureContainer<IStashboxContainer>((context, container) =>
            {
                // Execute a dependency tree validation.
                if (context.HostingEnvironment.IsDevelopment())
                    container.Validate();
            })
            .ConfigureWebHostDefaults(
                webBuilder => webBuilder
                    .UseStartup<Startup>());
    }
}

You can also use the ConfigureContainer() method in your Startup class to use further configuration options:


public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Your service configuration.
    }

    public void ConfigureContainer(IStashboxContainer container)
    {
        // Your container configuration.
        container.Configure(config => config.WithLifetimeValidation());
    }

    public void Configure(IApplicationBuilder app)
    {
        // Your application configuration.
    }
}
ASP.NET Core 6
var builder = WebApplication.CreateBuilder(args);

builder.Host.UseStashbox(container => // Optional configuration options.
{
    // This one enables the lifetime validation for production environments too.
    container.Configure(config => config.WithLifetimeValidation());
});

builder.Host.ConfigureContainer<IStashboxContainer>((context, container) =>
{
    // Execute a dependency tree validation.
    if (context.HostingEnvironment.IsDevelopment())
        container.Validate();
});

Controller / View activation

By default the ASP.NET Core framework uses the DefaultControllerActivator to instantiate controllers, but it uses the ServiceProvider only for instantiating their constructor dependencies. This behaviour could hide important errors Stashbox would throw in case of a misconfiguration, so it's recommended to let Stashbox activate your controllers and views.

You can enable this by adding the following options to your service configuration:

ASP.NET Core 5
public void ConfigureServices(IServiceCollection services)
{
    // For controllers only.
    services.AddControllers()
            .AddControllersAsServices();
    
    // For controllers and views.
    services.AddControllersWithViews()
            .AddControllersAsServices()
            .AddViewComponentsAsServices();
}
ASP.NET Core 6
// For controllers only.
builder.Services.AddControllers()
    .AddControllersAsServices();
    
// For controllers and views.
builder.Services.AddControllersWithViews()
    .AddControllersAsServices()
    .AddViewComponentsAsServices();

Multitenant

The Stashbox.AspNetCore.Multitenant package provides support for multitenant applications with a component called TenantDistributor. It's responsible for the following tasks:

  1. Create / maintain the application level Root Container. This container is used to hold the default service registrations for your application.
  2. Configure / maintain tenant specific containers. These containers are used to override the default services with tenant specific registrations.
  3. Tenant identification. Determines the tenant Id based on the current context. To achieve that, you have to provide an ITenantIdExtractor implementation.
// The type used to extract the current tenant identifier.
// This implementation shows how to extract the tenant id from a HTTP header.

public class HttpHeaderTenantIdExtractor : ITenantIdExtractor
{
    public Task<object> GetTenantIdAsync(HttpContext context)
    {
        if (!context.Request.Headers.TryGetValue("TENANT-ID", out var value))
            return Task.FromResult<object>(null);

        return Task.FromResult<object>(value.First());
    }
}
ASP.NET Core 5
public static IHostBuilder CreateHostBuilder(String[] args)
{
    return Host.CreateDefaultBuilder(args)
        .UseStashboxMultitenant<HttpHeaderTenantIdExtractor>(
            distributor => // The tenant distributor configuration options.
        {
            // The default service registration.
            // It also could be registered into the default 
            // service collection through the ConfigureServices() api.
            distributor.RootContainer.Register<IDependency, DefaultDependency>();

            // Configure tenants.
            distributor.ConfigureTenant("TenantA", container => 
                // Register tenant specific service override
                container.Register<IDependency, TenantASpecificDependency>());

            distributor.ConfigureTenant("TenantB", container => 
                // Register tenant specific service override
                container.Register<IDependency, TenantBSpecificDependency>());
        })
        .ConfigureContainer<TenantDistributor>((context, distributor) =>
        {
            // Validate the root container and all the tenants.
            if (context.HostingEnvironment.IsDevelopment())
                distributor.Validate();
        })
        .ConfigureWebHostDefaults(
            webBuilder => webBuilder
                .UseStartup<Startup>());
    }
ASP.NET Core 6
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseStashboxMultitenant<HttpHeaderTenantIdExtractor>(
    distributor => // The tenant distributor configuration options.
{
    // The default service registration.
    // It also could be registered into the default 
    // service collection through the ConfigureServices() api.
    distributor.RootContainer.Register<IDependency, DefaultDependency>();

    // Configure tenants.
    distributor.ConfigureTenant("TenantA", container => 
        // Register tenant specific service override
        container.Register<IDependency, TenantASpecificDependency>());

    distributor.ConfigureTenant("TenantB", container => 
        // Register tenant specific service override
        container.Register<IDependency, TenantBSpecificDependency>());
});

builder.Host.ConfigureContainer<TenantDistributor>((context, distributor) =>
{
    // Validate the root container and all the tenants.
    if (context.HostingEnvironment.IsDevelopment())
        distributor.Validate();
});

With this example setup, you can differentiate tenants in a per-request basis identified by a HTTP header, where every tenant gets their overridden services.

.NET Generic Host

The following example adds Stashbox (with the Stashbox.Extensions.Hosting package) as the default IServiceProvider implementation into your .NET Generic Host application:

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = Host.CreateDefaultBuilder(args)
            .UseStashbox(container => // Optional configuration options.
            {
                // This one enables the lifetime validation for production environments too.
                container.Configure(config => config.WithLifetimeValidation());
            })
            .ConfigureContainer<IStashboxContainer>((context, container) =>
            {
                // Execute a dependency tree validation.
                if (context.HostingEnvironment.IsDevelopment())
                    container.Validate();
            })
            .ConfigureServices((context, services) =>
            {
                services.AddHostedService<Service>();
            }).Build();

        await host.RunAsync();
    }
}

ServiceCollection Based Applications

With the Stashbox.Extensions.Dependencyinjection package you can replace Microsoft's built-in dependency injection container with Stashbox. This package contains the core functionality used by the Stashbox.Extensions.Hosting, Stashbox.AspNetCore.Hosting and Stashbox.AspNetCore.Multitenant packages.

The following example shows how you can use this integration:

public class Program
{
    public static async Task Main(string[] args)
    {
        // Create the service collection.
        var services = new ServiceCollection();

        // Configure your service collection.
        services.AddLogging();
        services.AddOptions();

        // Add your services.
        services.AddScoped<IService, Service>();

        // Integrate Stashbox with the collection and grab your ServiceProvider.
        var serviceProvider = services.UseStashbox(container => // Optional configuration options.
        {
            container.Configure(config => config.WithLifetimeValidation());
        });

        // Start using the application.
        using (var scope = serviceProvider.CreateScope())
        {
            var service = scope.ServiceProvider.GetService<IService>();
            await service.DoSomethingAsync();
        }
    }
}

Or you can use your own StashboxContainer to integrate with the ServiceCollection:

public class Program
{
    public static async Task Main(string[] args)
    {
        // Create your container.
        var container = new StashboxContainer(config => // Optional configuration options.
        {
            config.WithLifetimeValidation();
        });

        // Create the service collection.
        var services = new ServiceCollection();

        // Configure your service collection.
        services.AddLogging();
        services.AddOptions();

        // Add your services.
        services.AddScoped<IService, Service>();

        // Or add them through Stashbox.
        container.RegisterScoped<IService, Service>();

        // Integrate Stashbox with the collection.
        services.UseStashbox(container);

        // Execute a dependency tree validation.
        container.Validate();

        // Start using the application.
        await using (var scope = container.BeginScope())
        {
            var service = scope.Resolve<IService>();
            await service.DoSomethingAsync();
        }
    }
}

Additional IServiceCollection Extensions

Most of Stashbox's service registration functionalities are available as extension methods of IServiceCollection.

  • Named service registration:

    class Service2 : IService2
    {
        private readonly IService service;
    
        public Service2(IService service) 
        {
            this.service = service;
        }
    }
    
    var services = new ServiceCollection();
    services.AddTransient<IService, Service>(); // Name-less registration.
    services.AddTransient<IService, AnotherService>("serviceName"); // Register dependency with name.
    services.AddTransient<IService2, Service2>(config => 
      // Inject the named service as dependency.
      config.WithDependencyBinding<IService>(
          "serviceName" // Name of the dependency.
      ));
    
  • Service configuration with Stashbox's Fluent Registration API:

    var services = new ServiceCollection();
    services.AddTransient<IService, Service>(config => 
      config.WithFactory<IDependency>(dependency => new Service(dependency)).AsImplementedTypes());
    
  • Service decoration:

    class ServiceDecorator : IService
    {
        private readonly IService decorated;
    
        public ServiceDecorator(IService service)
        {
            this.decorated = service;
        }
    }
    
    var services = new ServiceCollection();
    services.AddTransient<IService, Service>();
    services.Decorate<IService, ServiceDecorator>();
    
  • Assembly registration:

    var services = new ServiceCollection();
    services.ScanAssemblyOf<IService>(
      // Set a filter for which types should be excluded/included in the registration process.
      // In this case, only the publicly available types are selected from the assembly.
      type => type.IsPublic, 
      // The service type selector. Used to filter which interface or base types the implementation should be mapped to.
      // In this case, we are registering only by interfaces.
      (implementationType, serviceType) => serviceType.IsInterface,
      false, // Do not map services to themselves. E.g: Service -> Service.
      config =>
      {
          // Register IService instances as scoped.
          if (config.ServiceType == typeof(IService))
              config.WithScopedLifetime();
      }
    );
    
  • Composition root:

    class CompositionRoot : ICompositionRoot
    {
        public void Compose(IStashboxContainer container)
        {
            container.Register<IService, Service>();
        }
    }
    
    var services = new ServiceCollection();
    services.ComposeBy<CompositionRoot>();
    
    // Or let Stashbox find all composition roots in an assembly.
    services.ComposeAssembly(typeof(CompositionRoot).Assembly);
    
Product Versions
.NET net5.0 net5.0-windows net6.0 net6.0-android net6.0-ios net6.0-maccatalyst net6.0-macos net6.0-tvos net6.0-windows
.NET Core netcoreapp3.0 netcoreapp3.1
.NET Standard netstandard2.1
.NET Framework net461 net462 net463 net47 net471 net472 net48
MonoAndroid monoandroid
MonoMac monomac
MonoTouch monotouch
Tizen tizen60
Xamarin.iOS xamarinios
Xamarin.Mac xamarinmac
Xamarin.TVOS xamarintvos
Xamarin.WatchOS xamarinwatchos
Compatible target framework(s)
Additional computed target framework(s)
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
4.2.2 95 6/2/2022
4.2.1 90 5/16/2022
4.2.0 75 5/3/2022
4.1.2 103 4/10/2022
4.1.1 95 3/12/2022
4.1.0 82 3/7/2022
4.0.1 85 2/10/2022
4.0.0 78 2/9/2022
3.2.1 99 1/30/2022
3.2.0 232 12/5/2021
3.1.1 122 11/22/2021
3.1.0 119 11/22/2021
3.0.0 278 11/22/2021
2.11.4 293 5/26/2021
2.11.3 282 3/16/2021
2.11.2 788 1/31/2021
2.11.1 491 11/16/2020
2.11.0 340 11/15/2020
2.10.1 268 11/5/2020
2.10.0 318 11/2/2020
2.9.9 248 11/2/2020
2.9.8 347 10/19/2020
2.9.7 244 10/16/2020
2.9.6 269 10/16/2020
2.9.5 299 10/14/2020
2.9.4 590 7/21/2020
2.9.3 485 7/9/2020
2.9.2 383 6/29/2020
2.9.1 323 6/22/2020
2.9.0 304 6/8/2020
2.8.6 964 1/15/2020
2.8.5 563 11/11/2019
2.8.4 355 10/4/2019
2.8.3 528 9/12/2019
2.8.1 827 9/11/2019
2.7.1 560 6/10/2019
2.6.8 4,194 3/21/2019
2.6.7 669 1/13/2019
2.6.5 521 12/27/2018
2.6.4 467 12/26/2018
2.6.3 1,113 10/24/2018
2.6.2 881 7/3/2018
2.6.1 744 6/15/2018
2.6.0 818 3/20/2018
2.5.9 677 2/8/2018
2.5.8 750 2/5/2018
2.5.7 695 11/24/2017
2.5.6 681 11/24/2017
2.5.5 704 8/27/2017
2.5.4 693 8/7/2017
2.5.3 707 6/28/2017
2.5.2 710 6/9/2017
2.5.1 723 5/17/2017
2.4.8 699 5/16/2017
2.4.7 734 5/10/2017
2.4.6 744 5/10/2017
2.4.5 762 5/9/2017
2.4.3 709 5/3/2017
2.4.1 705 5/3/2017
2.3.1 708 3/24/2017
2.2.4 706 3/18/2017
2.2.3 691 3/17/2017
2.2.2 713 3/14/2017
2.2.1 718 3/11/2017
2.2.0 713 3/2/2017
2.1.2 731 2/21/2017
2.1.1 712 2/18/2017
2.1.0 724 2/18/2017
1.0.15 730 2/9/2017
1.0.14 723 2/9/2017
1.0.13 703 1/27/2017
1.0.12 769 1/26/2017
1.0.11 718 1/26/2017