A services dependency provider, like dependency inject, easy to learn and easy to use.
Provide services life time control with singleton, scoped, transient.
void main() {
final services = ServiceCollection()
// add the default logging services
..addLogging()
..addSingleton<IMySingletonService, MySingletonService>((_) => MySingletonService())
..addScoped<IMyScopedService, MyScopedService>((_) => MyScopedService())
..addTransient<IMyTransientService, MyTransientService>((_) => MyTransientService())
..addScoped<MyScopedDependencyService, MyScopedDependencyService>(
(p) =>
MyScopedDependencyService(
singletonService: p.getRequiredService<IMySingletonService>(),
scopedService: p.getRequiredService<IMyScopedService>(),
transientService: p.getRequiredService<IMyTransientService>(),
),
);
final serviceProvider = services.buildServiceProvider();
final singletonService = serviceProvider.getRequiredService<IMySingletonService>();
final transientService = serviceProvider.getRequiredService<IMyTransientService>();
// Scoping
final scope = serviceProvider.createScope();
final singletonService2 = scope.serviceProvider.getRequiredService<IMySingletonService>();
assert(identical(singletonService, singletonService2));
final scopedService = scope.serviceProvider.getRequiredService<IMyScopedService>();
final scopedService2 = scope.serviceProvider.getRequiredService<IMyScopedService>();
assert(identical(scopedService, scopedService2));
final transientService2 = scope.serviceProvider.getRequiredService<IMyTransientService>();
assert(!identical(transientService, transientService2));
// Always dispose the scope when you don't need it anymore.
// This will cleanup any resources use by this scope and the services in this scope.
// There is a `disposeAsync()` method for asynchronous calls.
// Note that: `dispose` method from interface `IDisposable` and `disposeAsync` from interface `IAsyncDisposable`
// Any services that it implements `IDisposable` or `IAsyncDisposable` and constructed by `IServiceProvider` will be disposed when its life is end automatically.
scope.dispose();
// Always dispose the ServiceProvider when you don't need it anymore.
// There also is a `disposeAsync()` method
serviceProvider.dispose();
}
abstract interface class IMySingletonService implements IDisposable {}
class MySingletonService implements IMySingletonService {
MySingletonService() {
print("MySingletonService $hashCode constructing");
}
@override
void dispose() {
print("MySingletonService $hashCode disposing");
}
}
abstract interface class IMyScopedService implements IAsyncDisposable {}
class MyScopedService implements IMyScopedService {
MyScopedService() {
print("MyScopedService $hashCode constructing");
}
@override
Future<void> disposeAsync() {
print("MyScopedService $hashCode disposing asynchronous");
return Future<void>.value();
}
}
abstract interface class IMyTransientService implements IDisposable {}
class MyTransientService implements IMyTransientService {
MyTransientService() {
print("MyTransientService $hashCode constructing");
}
@override
void dispose() {
print("MyTransientService $hashCode disposing");
}
}
class MyScopedDependencyService {
final IMySingletonService singletonService;
final IMyScopedService scopedService;
final IMyTransientService transientService;
MyScopedDependencyService(
{required this.singletonService, required this.scopedService, required this.transientService}) {
print("MyDependencyService $hashCode constructing with "
"IMySingletonService ${singletonService.hashCode}, "
"IMyScopedService ${scopedService.hashCode}, "
"IMyTransientService ${transientService.hashCode}");
}
}
void main() {
final services = ServiceCollection();
services.addSingleton<MyService, MyService>((_) => MyService());
final rootProvider = services.buildServiceProvider();
final myService = rootProvider.getRequiredService<MyService>();
// myService.foo()
}
class MyService {}
final services = ServiceCollection()
// add the default logging services
..addLogging();
final services = ServiceCollection()
// add the default logging services
..addLogging((loggingBuilder) {
// Custom your logging services
});
How to custom logging services:
- Implement
ILoggerFactory
interface, then calladdLogging
extension method onServiceCollection
, Specify theconfig
argument. - Optional implement
ILogger
andILogger4
interfaces, implementILogger4
is recommended. - If you implementations does not need
LoggerOptions
service, please call theLoggingBuilderExtensions.removeOptions
extension method to delete it.
Provide environment service.
void main() {
final services = ServiceCollection();
// Add environment service
services.addEnvironment<Evironment>(Environment(name: Environments.production));
final provider = services.buildServiceProvider();
final env = provider.getRequiredService<IEnvironment>();
print(env.isProduction); // true
}
You can detect the environment and change the application behavior at runtime.
After any service that implements IConfigurable
is created from the service container (including
singleton services that specify instances), the service container will look for its corresponding
ServiceConfigure<TService>
and ServicePostConfigure<TService>
services to configure these
service instances.
Use the serviceCollection.configure<TService>
method or the
serviceCollection.postConfigure<TService>
method to add a configuration service for a configurable
service.
If you have any issues or suggests please redirect to repo or send an email to me.
In flutter, you can use flutter_service_provider.