Hasim.Injectify
0.1.6
dotnet add package Hasim.Injectify --version 0.1.6
NuGet\Install-Package Hasim.Injectify -Version 0.1.6
<PackageReference Include="Hasim.Injectify" Version="0.1.6" />
<PackageVersion Include="Hasim.Injectify" Version="0.1.6" />
<PackageReference Include="Hasim.Injectify" />
paket add Hasim.Injectify --version 0.1.6
#r "nuget: Hasim.Injectify, 0.1.6"
#:package Hasim.Injectify@0.1.6
#addin nuget:?package=Hasim.Injectify&version=0.1.6
#tool nuget:?package=Hasim.Injectify&version=0.1.6
Injectify
A modular dependency injection system for ASP.NET Core applications that eliminates manual service registration entirely.
Why Injectify?
The Problem
In traditional ASP.NET Core, each new service requires manual registration:
// Every single service needs manual registration π«
services.AddScoped<IUserService, UserService>();
services.AddScoped<IProductService, ProductService>();
services.AddScoped<IOrderService, OrderService>();
services.AddSingleton<ICacheService, CacheService>();
services.AddTransient<IEmailService, EmailService>();
// ... 50+ more services ...
The Injectify Solution
Implement a marker interface β automatically registered β¨
// Just inherit the marker interface β that's it!
public interface IUserService : IAddScoped { }
public class UserService : IUserService { }
public interface ICacheService : IAddSingleton { }
public class CacheService : ICacheService { }
// Everything is auto-discovered and registered with just:
builder.InjectifyApplication();
Concept
Each project in your solution (Application, Core, EF Core, UI, etc.) defines its own module that registers its own dependencies. The host project (UI) discovers and initializes all modules automatically with just two calls:
// Program.cs β that's literally all you need
var builder = WebApplication.CreateBuilder(args);
builder.InjectifyApplication(); // Auto-discovers modules + auto-registers all services
var app = builder.Build();
app.InjectifyInitializer(); // Configures app pipeline
app.Run();
No manual service registration. No configuration files. Just implement marker interfaces.
Core Features
| Feature | Description | Impact |
|---|---|---|
| π Zero Manual Registration | Implement marker interfaces β services auto-register. No services.Add*() calls needed. |
Eliminates ~70% of boilerplate |
| π¦ Auto-Discovery | Recursively scans all assemblies, discovers all IModule implementations automatically |
One call: builder.InjectifyApplication() |
| π― Marker-based Auto DI | IAddSingleton, IAddScoped, IAddTransient on your service β auto-registered by lifetime |
No more manual .AddScoped<I, T>() |
| π Module Lifecycle | OnInit β ConfigureService β ConfigureApplication β OnStart β OnStop |
Full control over initialization order |
| π Dependency Graph | Topological sort, cycle detection, dependency validation | Fail-fast on misconfiguration |
| π·οΈ Module Metadata | [ModuleInfo], [ModuleOrder], [DependsOn] for organization |
Self-documenting modules |
| β‘ Conditional Loading | Load modules based on environment, config, or custom predicates | Feature flags, environment-specific modules |
Installation
dotnet add package Injectify
Quick Start
1. Create a module in each project (optional for DI-only services)
using Injectify.Modules;
[ModuleInfo("My Module", "1.0.0", "Description of the module")]
[ModuleOrder(10)]
public class MyModule : BaseInjectifyModule
{
public override void ConfigureService(IServiceCollection services, IConfiguration configuration)
{
services.AddScoped<IMyService, MyService>();
}
public override void ConfigureApplication(WebApplication app)
{
app.Logger.LogInformation("MyModule initialized");
app.UseMiddleware<MyMiddleware>();
}
}
2. In the UI project β 2 lines (discovers modules + auto-registers services)
var builder = WebApplication.CreateBuilder(args);
builder.InjectifyApplication(); // Scans all assemblies, discovers all IModule + auto-registers IAddSingleton/IAddScoped/IAddTransient
var app = builder.Build();
app.InjectifyInitializer(); // Calls ConfigureApplication on each module
app.Run();
3. Auto-Register Services with Marker Interfaces (Zero Boilerplate!)
This is the killer feature. Instead of manual registration, just inherit a marker interface:
Traditional approach (verbose):
// Your Program.cs requires THIS for every single service
services.AddScoped<IUserService, UserService>();
services.AddScoped<IProductService, ProductService>();
services.AddScoped<IOrderService, OrderService>();
services.AddSingleton<ICacheService, CacheService>();
services.AddSingleton<IConfigService, ConfigService>();
services.AddTransient<IEmailService, EmailService>();
// ... repeat 50+ times for a real app π©
Injectify approach (automatic):
using Injectify.Abstractions;
// **That's it.** Just add the marker interface.
// Automatically registered as Scoped
public interface IUserService : IAddScoped { }
public class UserService : IUserService { }
// Automatically registered as Singleton
public interface ICacheService : IAddSingleton { }
public class CacheService : ICacheService { }
// Automatically registered as Transient
public interface IEmailService : IAddTransient { }
public class EmailService : IEmailService { }
One line in Program.cs does it all:
builder.InjectifyApplication(); // Discovers + auto-registers every IAddSingleton/Scoped/Transient
Benefits:
- β No boilerplate registration code
- β Services are self-documenting (lifetime is in the interface name)
- β New developers can't forget to register a service
- β Scales from 10 to 1000+ services without friction
4. Module lifecycle
public class MyModule : BaseInjectifyModule
{
public override void OnInit(IServiceCollection services) { /* before registration */ }
public override void OnStart(WebApplication app) { /* after build, before run */ }
public override void OnStop() { /* on shutdown */ }
}
5. Module dependencies
[DependsOn(typeof(CoreModule))]
[DependsOn(typeof(EFCoreModule))]
public class UIModule : BaseInjectifyModule { }
6. Conditional Module Loading
Load modules conditionally based on environment, configuration, or custom logic.
A) Environment-based loading
Load a module only in specific environments (Production, Development, Staging, etc.):
using Injectify.Attributes;
using Injectify.Modules;
// Load only in Production
[ConditionalModule(Environments = "Production")]
public class ProductionAnalyticsModule : BaseInjectifyModule
{
public override void ConfigureService(IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IAnalyticsService, ProductionAnalyticsService>();
}
}
// Load in Production OR Staging (semicolon-separated)
[ConditionalModule(Environments = "Production;Staging")]
public class MonitoringModule : BaseInjectifyModule
{
public override void ConfigureService(IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IMonitoringService, MonitoringService>();
}
}
How it works:
Environments = "Production"β loads only whenIHostEnvironment.EnvironmentName == "Production"Environments = "Production;Staging"β loads if environment is Production OR Staging- Multiple environments separated by
;or,
B) Configuration-based loading
Load a module if a configuration setting is enabled:
// appsettings.json or appsettings.Development.json
{
"Features": {
"Analytics": {
"Enabled": true
},
"Authentication": {
"OAuth": {
"Enabled": false
}
}
}
}
// Load only if Features:Analytics:Enabled is true
[ConditionalModule(ConfigurationPath = "Features:Analytics:Enabled")]
public class AnalyticsModule : BaseInjectifyModule
{
public override void ConfigureService(IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IAnalyticsEngine, AnalyticsEngine>();
}
}
// OAuth module loads only if the config key is true
[ConditionalModule(ConfigurationPath = "Features:Authentication:OAuth:Enabled")]
public class OAuthModule : BaseInjectifyModule
{
public override void ConfigureService(IServiceCollection services, IConfiguration configuration)
{
services.AddScoped<IOAuthService, OAuthService>();
}
}
How it works:
ConfigurationPath = "Features:Analytics:Enabled"β loads if config["Features:Analytics:Enabled"] == "true"- Configuration value must be a boolean-parseable string ("true" or "false")
- If the key is missing, the module is skipped
C) Custom predicate loading
Load a module based on custom logic:
using Injectify.Abstractions;
using Injectify.Attributes;
using Injectify.Modules;
// Define a custom condition
public class IsLicensedCondition : IModuleCondition
{
private readonly ILicenseService _licenseService;
public IsLicensedCondition(ILicenseService licenseService)
{
_licenseService = licenseService;
}
public async Task<bool> IsSatisfiedAsync()
{
// Custom logic: check if premium license is active
return await _licenseService.IsActivePremiumLicenseAsync();
}
}
// Load only if the condition is satisfied
[ConditionalModule(ConditionType = typeof(IsLicensedCondition))]
public class PremiumFeaturesModule : BaseInjectifyModule
{
public override void ConfigureService(IServiceCollection services, IConfiguration configuration)
{
services.AddScoped<IAdvancedReportingService, AdvancedReportingService>();
services.AddScoped<ICustomBrandingService, CustomBrandingService>();
}
}
How it works:
- Create a class implementing
IModuleCondition - Implement
IsSatisfiedAsync()β return true to load the module, false to skip it - Can be async (e.g., call a database or API to decide)
- Dependencies are resolved via DI container
D) Hybrid conditions (combine multiple types)
Combine environment + configuration + custom conditions β module loads if ANY condition is satisfied (OR logic):
// Load in Production, OR if config enables debug mode, OR if custom condition is satisfied
[ConditionalModule(
Environments = "Production",
ConfigurationPath = "Features:DebugMode:Enabled",
ConditionType = typeof(IsAdminUserCondition)
)]
public class DiagnosticsModule : BaseInjectifyModule
{
public override void ConfigureService(IServiceCollection services, IConfiguration configuration)
{
services.AddSingleton<IDiagnosticsService, DiagnosticsService>();
}
}
This module loads if:
- Environment is Production, OR
- Config key "Features:DebugMode:Enabled" is true, OR
- Custom condition IsAdminUserCondition is satisfied
Complete example: Environment + Feature flags
// appsettings.Development.json
{
"Features": {
"Development": {
"HotReload": true
}
}
}
// In your module
[ConditionalModule(
Environments = "Development",
ConfigurationPath = "Features:Development:HotReload"
)]
public class HotReloadModule : BaseInjectifyModule
{
public override void ConfigureApplication(WebApplication app)
{
app.Logger.LogInformation("Hot reload enabled in Development");
// Configure hot reload middleware
}
}
Performance Benchmarks
Baseline performance metrics measured with BenchmarkDotNet on .NET 8.0 (Intel Core i5-6300U).
Key Metrics
| Scenario | Time | Memory |
|---|---|---|
| Discovery + Registration (current assembly) | 5.67 ΞΌs | 4.28 KB |
| Discovery + Registration (Injectify assembly) | 9.52 ΞΌs | 4.83 KB |
| Singleton Registration | 3.83 ΞΌs | 3.78 KB |
| Scoped Registration | 4.96 ΞΌs | 3.78 KB |
| Transient Registration | 4.38 ΞΌs | 3.78 KB |
| Single Assembly Startup | 5.34 ΞΌs | 4.28 KB |
| Multiple Assemblies Startup | 13.13 ΞΌs | 5.60 KB |
Injectify vs Manual Registration
| Method | Time | Memory | Overhead |
|---|---|---|---|
| Injectify Auto-Registration | 5.11 ΞΌs | 4.28 KB | +28% time |
| Manual Registration | 3.98 ΞΌs | 3.95 KB | baseline |
Analysis: Injectify's auto-discovery and registration adds ~1.1 microseconds of overhead per operation, with slightly higher memory footprint (330 bytes). For typical applications, this represents negligible performance impact compared to the boilerplate elimination benefit.
Packages
| Package | Description |
|---|---|
Injectify |
Module system with DI registration, pipeline config, and module lifecycle |
Project structure
Injectify/
βββ Abstractions/ # Public contracts: IModule, IModuleLifecycle, IModuleLoader, DI markers
βββ Attributes/ # [DependsOn], [ModuleInfo], [ModuleOrder]
βββ Exceptions/ # InjectifyException, DependencyCycleException
βββ Extensions/ # Fluent DI extensions (InjectifyApplication, InjectifyInitializer, DependencyInjectionExtensions)
βββ Modules/ # BaseInjectifyModule
βββ Setup/ # ModuleLoader, ModuleDependencySorter (assembly scanning, topological sort)
βββ Injectify.Tests/ # Unit tests (xUnit)
Documentation
- README.fr.md β Documentation en franΓ§ais
- AUDIT.md β Audit findings & technical debt
- docs/architecture.md β Architecture and dependency flow
License
MIT
| Product | Versions 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 was computed. 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. |
-
net8.0
- Microsoft.Extensions.Configuration.Abstractions (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Hosting.Abstractions (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Hasim.Injectify:
| Package | Downloads |
|---|---|
|
Hasim.Auditify
A lightweight, pluggable audit-trail library for EF Core 8+. Automatically captures entity changes (Added/Modified/Deleted), supports sensitive data masking, soft-delete patterns, and timestamp tracking. |
|
|
Hasim.EntityFrameworkCore
A customizable ASP.NET Core Identity entities library providing reusable base identity models and common abstractions for modern .NET applications. |
|
|
Hasim.Infrastructure
Todo Description. |
GitHub repositories
This package is not used by any popular GitHub repositories.