{"id":13629135,"url":"https://github.com/pakrym/jab","last_synced_at":"2025-05-14T14:08:11.258Z","repository":{"id":37936476,"uuid":"320695592","full_name":"pakrym/jab","owner":"pakrym","description":"C# Source Generator based dependency injection container implementation.","archived":false,"fork":false,"pushed_at":"2025-02-06T15:37:00.000Z","size":497,"stargazers_count":1090,"open_issues_count":17,"forks_count":37,"subscribers_count":23,"default_branch":"main","last_synced_at":"2025-04-14T06:48:21.072Z","etag":null,"topics":["dependency-injection","microsoft-extensions","roslyn","roslyn-generator","singleton-service","source-generators"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pakrym.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-11T22:14:59.000Z","updated_at":"2025-04-13T18:21:28.000Z","dependencies_parsed_at":"2023-12-16T18:27:37.170Z","dependency_job_id":"2712f02d-4f6a-40a3-9feb-86ab0c87f7e0","html_url":"https://github.com/pakrym/jab","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pakrym%2Fjab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pakrym%2Fjab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pakrym%2Fjab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pakrym%2Fjab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pakrym","download_url":"https://codeload.github.com/pakrym/jab/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254159688,"owners_count":22024564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dependency-injection","microsoft-extensions","roslyn","roslyn-generator","singleton-service","source-generators"],"created_at":"2024-08-01T22:01:03.049Z","updated_at":"2025-05-14T14:08:11.213Z","avatar_url":"https://github.com/pakrym.png","language":"C#","readme":"# Jab Compile Time Dependency Injection\n\n[![Nuget](https://img.shields.io/nuget/v/Jab)](https://www.nuget.org/packages/Jab)\n\nJab provides a [C# Source Generator](https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/) based dependency injection container implementation.\n\n- Fast startup (200x faster than Microsoft.Extensions.DependencyInjection). [Details](#Startup-Time).\n- Fast resolution (7x faster than Microsoft.Extensions.DependencyInjection). [Details](#GetService).\n- No runtime dependencies.\n- AOT and linker friendly, all code is generated during project compilation.\n- Clean stack traces: \u003cbr\u003e ![stacktrace](https://raw.githubusercontent.com/pakrym/jab/main/doc/stacktrace.png)\n- Readable generated code: \u003cbr\u003e ![generated code](https://raw.githubusercontent.com/pakrym/jab/main/doc/generatedcode.png)\n- Registration validation. Container configuration issues become compiler errors: \u003cbr\u003e ![generated code](https://raw.githubusercontent.com/pakrym/jab/main/doc/errors.png)\n- Incremental generation, Modern .NET SDK support, .NET Standard 2.0 support, [Unity support](README.md#Unity-installation)\n\n## Example\n\nAdd Jab package reference:\n```xml\n\u003cItemGroup\u003e\n    \u003cPackageReference Include=\"Jab\" Version=\"0.11.0\" PrivateAssets=\"all\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\nDefine a service and implementation:\n\n``` C#\ninternal interface IService\n{\n    void M();\n}\n\ninternal class ServiceImplementation : IService\n{\n    public void M()\n    {\n    }\n}\n```\n\nDefine a composition root and register services:\n\n```C#\n[ServiceProvider]\n[Transient(typeof(IService), typeof(ServiceImplementation))]\ninternal partial class MyServiceProvider { }\n```\n\nUse the service provider:\n\n``` C#\nMyServiceProvider c = new MyServiceProvider();\nIService service = c.GetService\u003cIService\u003e();\n```\n\n## Features\n\n- No runtime dependency, safe to use in libraries\n- Transient, Singleton, Scoped service registration\n- Named registrations\n- Factory registration\n- Instance registration\n- `IEnumerable` resolution\n- `IDisposable` and `IAsyncDisposable` support\n- `IServiceProvider` support\n\nThe plan is to support the minimum feature set Microsoft.Extensions.DependencyInjection.Abstraction requires but *NOT* the `IServiceCollection`-based registration syntax as it is runtime based.\n\n### Singleton services\n\nSingleton services are created once per container lifetime in a thread-safe manner and cached.\nTo register a singleton service use the `SingletonAttribute`:\n\n```C#\n[ServiceProvider]\n[Singleton(typeof(IService), typeof(ServiceImplementation))]\ninternal partial class MyServiceProvider { }\n```\n\n### Singleton Instances\n\nIf you want to use an existing object as a service define a property in the container declaration and use the `Instance` property of the `SingletonAttribute` to register the service:\n\n```C#\n[ServiceProvider]\n[Singleton(typeof(IService), Instance = nameof(MyServiceInstance))]\ninternal partial class MyServiceProvider {\n    public IService MyServiceInstance { get;set; }\n}\n```\n\nThen initialize the property during the container creation:\n\n```C#\nMyServiceProvider c = new MyServiceProvider();\nc.MyServiceInstance = new ServiceImplementation();\n\nIService service = c.GetService\u003cIService\u003e();\n```\n\n### Named services\n\nUse the `Name` property to assign a name to your service registrations and `[FromNamedServices(\"...\")]` attribute to resolve a service using its name.\n\n```C#\n[ServiceProvider]\n[Singleton(typeof(INotificationService), typeof(EmailNotificationService), Name=\"email\")]\n[Singleton(typeof(INotificationService), typeof(SmsNotificationService), Name=\"sms\")]\n[Singleton(typeof(Notifier))]\ninternal partial class MyServiceProvider {}\n\nclass Notifier\n{\n    public Notifier(\n        [FromNamedServices(\"email\")] INotificationService email,\n        [FromNamedServices(\"sms\")] INotificationService sms)\n    {}\n}\n```\n\nNOTE: Jab also recognizes the `[FromKeyedServices]` attribute from `Microsoft.Extensions.DependencyInjection`.\n\n### Factories\n\nSometimes it's useful to provide a custom way to create a service instance without using the automatic construction selection.\nTo do this define a method in the container declaration and use the `Factory` property of the `SingletonAttribute` or `TransientAttribute` to register the service:\n\n```C#\n[ServiceProvider]\n[Transient(typeof(IService), Factory = nameof(MyServiceFactory))]\ninternal partial class MyServiceProvider {\n    public IService MyServiceFactory() =\u003e new ServiceImplementation();\n}\n\nMyServiceProvider c = new MyServiceProvider();\nIService service = c.GetService\u003cIService\u003e();\n```\n\nWhen using with `TransientAttribute` the factory method would be invoked for every service resolution.\nWhen used with `SingletonAttribute` it would only be invoked the first time the service is requested.\n\nSimilar to constructors, factories support parameter injection:\n\n```\n[ServiceProvider]\n[Transient(typeof(IService), Factory = nameof(MyServiceFactory))]\n[Transient(typeof(SomeOtherService))]\ninternal partial class MyServiceProvider {\n    public IService MyServiceFactory(SomeOtherService other) =\u003e new ServiceImplementation(other);\n}\n```\n\n### Scoped Services\n\nScoped services are created once per service provider scope. To create a scope use the `CreateScope()` method of the service provider.\nService are resolved from the scope using the `GetService\u003cIService\u003e()` call.\n\n```C#\n[ServiceProvider]\n[Scoped(typeof(IService), typeof(ServiceImplementation))]\ninternal partial class MyServiceProvider { }\n\nMyServiceProvider c = new MyServiceProvider();\nusing MyServiceProvider.Scope scope = c.CreateScope();\nIService service = scope.GetService\u003cIService\u003e();\n```\n\nWhen the scope is disposed all `IDisposable` and `IAsyncDisposable` services that were resolved from it are disposed as well.\n\n### Generic registration attributes \n\n\nYou can use generic attributes to register services if your project targets a framework compatible with C# 11 or greater. See [C# language versioning](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-versioning#defaults) for more details.\n\n\n\nGeneric attributes allow declaration to be more compact by avoiding the `typeof` calls:\n\n``` C#\n[ServiceProvider]\n[Scoped\u003cIService, ServiceImplementation\u003e]\n[Import\u003cIMyModule\u003e]\ninternal partial class MyServiceProvider { }\n```\n\n### Modules\n\nOften, a set of service registrations would represent a distinct set of functionality that can be included into arbitrary \nservice provider. Modules are used to implement registration sharing. To define a module create an interface and mark it with `ServiceProviderModuleAttribute`. Service registrations can be listed in module the same way they are in the service provider.\n\n```C#\n[ServiceProviderModule]\n[Singleton(typeof(IService), typeof(ServiceImplementation))]\npublic interface IMyModule\n{\n}\n```\n\nTo use the module apply the `Import` attribute to the service provider type:\n\n```C#\n[ServiceProvider]\n[Import(typeof(IMyModule))]\ninternal partial class MyServiceProvider\n{\n}\n\nMyServiceProvider c = new MyServiceProvider();\nIService service = c.GetService\u003cIEnumerable\u003cIService\u003e\u003e();\n```\n\nModules can import other modules as well.\n\n**NOTE**: module service and implementation types have to be accessible from the project where service provider is generated.\n\n## Root services\n\nBy default, `IEnumerable\u003c...\u003e` service accessors are only generated when requested by other service constructors. If you would like to have a root `IEnumerable\u003c..\u003e` accessor generated use the `RootService` parameter of the `ServiceProvider` attribute. The generator also scans all the `GetService\u003c...\u003e` usages and tries to all collected type arguments as the root service.\n\n``` C#\n[ServiceProvider(RootServices = new [] {typeof(IEnumerable\u003cIService\u003e)})]\n[Singleton(typeof(IService), typeof(ServiceImplementation))]\n[Singleton(typeof(IService), typeof(ServiceImplementation))]\n[Singleton(typeof(IService), typeof(ServiceImplementation))]\ninternal partial class MyServiceProvider\n{\n}\n\nMyServiceProvider c = new MyServiceProvider();\nIService service = c.GetService\u003cIEnumerable\u003cIService\u003e\u003e();\n```\n\n## Samples\n\n### Console application\n\nSample Jab usage in console application can be found in [src/samples/ConsoleSample](src/samples/ConsoleSample)\n\n## Performance\n\nThe performance benchmark project is available in [src/Jab.Performance/](src/Jab.Performance/).\n\n### Startup time\n\nThe startup time benchmark measures time between application startup and the first service being resolved.\n\n```\n| Method |        Mean |     Error |    StdDev |  Ratio | RatioSD |  Gen 0 |  Gen 1 | Gen 2 | Allocated |\n|------- |------------:|----------:|----------:|-------:|--------:|-------:|-------:|------:|----------:|\n|   MEDI | 2,437.88 ns | 14.565 ns | 12.163 ns | 220.91 |    2.72 | 0.6332 | 0.0114 |     - |    6632 B |\n|    Jab |    11.03 ns |  0.158 ns |  0.123 ns |   1.00 |    0.00 | 0.0046 |      - |     - |      48 B |\n```\n\n### GetService\n\nThe `GetService` benchmark measures the `provider.GetService\u003cIService\u003e()` call.\n\n```\n| Method |      Mean |     Error |    StdDev | Ratio | RatioSD |  Gen 0 | Gen 1 | Gen 2 | Allocated |\n|------- |----------:|----------:|----------:|------:|--------:|-------:|------:|------:|----------:|\n|   MEDI | 39.340 ns | 0.2419 ns | 0.2263 ns |  7.01 |    0.09 | 0.0023 |     - |     - |      24 B |\n|    Jab |  5.619 ns | 0.0770 ns | 0.0643 ns |  1.00 |    0.00 | 0.0023 |     - |     - |      24 B |\n```\n\n## Unity installation\n1. Navigate to the Packages directory of your project.\n2. Adjust the [project manifest file](https://docs.unity3d.com/Manual/upm-manifestPrj.html) manifest.json in a text editor.\n3. Ensure `https://registry.npmjs.org/` is part of `scopedRegistries`.\n4. Ensure `com.pakrym` is part of `scopes`.\n5. Add `com.pakrym.jab` to the dependencies, stating the latest version.\n\nA minimal example ends up looking like this:\n\n```\n{\n  \"scopedRegistries\": [\n    {\n      \"name\": \"npmjs\",\n      \"url\": \"https://registry.npmjs.org/\",\n      \"scopes\": [\n        \"com.pakrym\"\n      ]\n    }\n  ],\n  \"dependencies\": {\n    \"com.pakrym.jab\": \"0.11.0\",\n    ...\n  }\n}\n```\n\n\n## Debugging locally\n\nRun `dotnet build /t:CreateLaunchSettings` in the `Jab.Tests` directory would update the `Jab\\Properties\\launchSettings.json` file to include `csc` invocation that allows F5 debugging of the generator targeting the `Jab.Tests` project.\n","funding_links":[],"categories":["Content","Source Generators","Compile time dependency injection"],"sub_categories":["110. [jab](https://ignatandrei.github.io/RSCG_Examples/v2/docs/jab) , in the [DependencyInjection](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#dependencyinjection) category","Dependency Injection (IoC Container)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpakrym%2Fjab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpakrym%2Fjab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpakrym%2Fjab/lists"}