0 purchases
dart container
Description #
This package provides a dependency injection solution for the Dart language, as well as a application server based on [dart_router_extended].
Features #
Simple injection: register an object instance. This will basically be treated as a Singleton object. Each injection call will return the same object
Lazy injection: register a builder function producing an object. This function will be called when the first injection will be executed, then the same object will be returned on any subsequent injections
Factory injection: register a factory function producing objects on each injection call
Qualified name injection: the container supports qualified injection so you can provide a name for your dependency
Injection profiles: you can register a certain object for a number of profiles, then inject or don't inject the value according to the selected profile. This feature is helpful if you want to run your application with different injection profiles
Value injection: inject simple named values into the container
Web server configuration
Web routes and controllers support
Web routes security using route guard
CORS configuration support
Scheduled tasks support
Eventing support
Usage #
Simple injection #
var myObject = MyClass();
var myProperty = "Prop value";
// Register an object with the container
$().generic(object: myObject)
// then register a value
.value("myProperty", myProperty)
// then register a named object. This also works with builders and factories
.generic(object: myObject, name: "alias");
// Retrieve object
MyClass injectedObject = $().get();
// Retrieved the qualified object
MyClass injectedObjectAlias = $().get(name: "alias");
// Retrieve object if present
MyClass? injectedObjectIfPresent = $().getIfPresent();
// Retrieve the qualified object
MyClass? injectedAliasObjectIfPresent = $().getIfPresent(name: "alias");
// You can also use shortcut methods
MyClass injectedObject = $get();
MyClass injectedObjectAlias = $get(name: "alias");
MyClass? injectedObjectIfPresent = $$get();
// Retreieve values
String property = $().getValue("myProperty");
String? propertyIfPresent = $().getValueIfPresent("myProperty");
//or use the shortcut methods
String property = $val("myProperty");
String? propertyIfPresent = $$val("myProperty");
copied to clipboard
Builder and factory injection #
Both the builder and the factories are practically methods that are used to build the container object, with the difference that with a factory, the method is called every time the object is retrieved from the container, while with the builder it is only built once, then the same instance returned, making it basically a lazy buildable singleton.
class SimpleObj {
final String timestamp;
SimpleObj(this.timestamp);
}
// Register with the container
$()
//Inject the builder function that will only be called once to create the container object
.generic(builder: () => MyClass())
.generic(factory: () => SimpleObj(DateTime.now().microsecondsSinceEpoch.toString()));
// Retrieve object
MyClass injectedObject = $().get();
// Produce object using the injected factory
SimpleObj injectedObjectIfPresent = $().getIfPresent();
// You can also use shortcut methods
MyClass injectedObject = $get();
SimpleObj injectedObjectIfPresent = $$get();
copied to clipboard
Conditional callbacks #
class SimpleObj {
final String timestamp;
SimpleObj(this.timestamp);
}
// Register with the container
$()
//Inject the builder function that will only be called once to create the container object
.generic(builder: () => MyClass())
.generic(factory: () => SimpleObj(DateTime.now().microsecondsSinceEpoch.toString()));
// Retrieve object
MyClass injectedObject = $().get();
// Produce object using the injected factory
SimpleObj? injectedObjectIfPresent = $().getIfPresent();
// You can also use shortcut methods
MyClass injectedObject = $get();
SimpleObj? injectedObjectIfPresent = $$get();
// Conditional callback, call some code only if an object is present in the container
Container().ifPresentThen<MyClass>((MyClass obj) {
print(obj);
});
// Or by using the shortcut method
$then<MyClass>((MyClass obj) {
print(obj);
});
// Conditional callback. Call some code only if a value is present in the container
$().ifValuePresentThen("valueKey", (value) {
print(value);
});
// Or by using the shortcut method
$valThen("valueKey", (value) {
print(value);
});
// Conditional callback with multiple dependencies. The container will invoke the callback
// only if all dependencies are found.
$().ifAllPresentThen([
Lookup.object(MyClass),
Lookup.object(SimpleObject),
Lookup.value("valueKey")
], (list) {
MyClass? myClass;
SimpleObject? simpleObject;
String? value;
[myClass, simpleObject, value] = list;
});
// Or by calling the shortcut method
$allThen([
$look(MyClass),
$look(SimpleObject),
$lookVal("valueKey")
], (list) {
MyClass? myClass;
SimpleObject? simpleObject;
String? value;
[myClass, simpleObject, value] = list;
});
copied to clipboard
Using profiles #
var myObject = MyClass();
var myProperty = "Prop value";
// Register with the container
$()
.generic(object: myObject, profiles: ["test", "run"])
.value("myProperty", myProperty, profiles: ["test", "run"])
// Setting the active profile
.profile("run");
// Retrieve object. The injection always uses the active profile when injecting any registered objects or provided values
// If the object is not present in the container for the active profile, this method will throw an exception
MyClass injectedObject = $().get();
// Retrieve object if present.
// If the object is not present in the container for the active profile, this method will return null
MyClass? injectedObjectIfPresent = $().getIfPresent();
// Retreieve values. If the value does not exist on the active profile, this method will throw an exception
String property = $().getValue("myProperty");
// If the value does not exist on the active profile, this method will return null
String? propertyIfPresent = $().getValueIfPresent("myProperty");
copied to clipboard
Injecting objects for interfaces #
class MyInterface {
void doSomething() {}
}
class MyClass implements MyInterface {
@override
void doSomething() {
print("Something");
}
}
var myObject = MyClass();
// Register with the container for the interface instead of the type
$().typed(MyInterface, object: myObject);
// If the object is not present in the container for the active profile, this method will throw an exception
MyInterface injectedObject = $().get();
// Retrieve object if present.
// If the object is not present in the container for the active profile, this method will return null
MyInterface? injectedObjectIfPresent = $().getIfPresent();
copied to clipboard
Autostartable objects #
Sometimes you might need to run some code, or start a webserver (the build in web server is also an AutoStart implementation). This iw why dart_container implements autostartable functionality.
class AutoStartMock implements AutoStart {
@override
void init() {
print("Init called");
}
@override
void run() {
print("Run called");
}
}
$().generic(builder: () => AutoStartMock(), autoStart: true)
// Once autostart is called, the init method is called first for the AutoStart objects,
// then the run method is called asynchronously, to avoid blocking the container and any other functionality
.autoStart();
copied to clipboard
Scheduled jobs #
Configuring the scheduler
// Sets the timer polling interval to the specified duration
// The polling interval is useful if you have scheduled tasks running at long periods
// of time. Longer periods will lessen the CPU load but will also reduce trigger time accuracy
// The default value, if not specified, is 10 seconds
$().schedulerPollingInterval(Duration(seconds: 1));
// Will delay all tasks from starting by the specified duration
$().schedulerInitialDelay(Duration(seconds: 10));
copied to clipboard
One time scheduled job
class OneTimeScheduledJob implements ScheduledJob {
bool hasRun = false;
@override
Duration? getDuration() => Duration(seconds: 1);
@override
ScheduledJobType getType() => ScheduledJobType.oneTime;
@override
void run() {
hasRun = true;
}
@override
DateTime? getStartTime() => null;
}
// Will run scheduled task after 1 second, as provided by the getDuration implementation
$().schedule(oneTime).autoStart();
copied to clipboard
Periodic scheduled job
class PeriodicScheduledJob implements ScheduledJob {
int runTimes = 0;
@override
Duration? getDuration() => Duration(seconds: 1);
@override
ScheduledJobType getType() => ScheduledJobType.periodic;
@override
DateTime? getStartTime() => null;
@override
void run() {
runTimes++;
}
}
// Will run immediately, then at every 1 second as specified by the getDuration implementation
PeriodicScheduledJob periodic = PeriodicScheduledJob();
$().schedule(periodic).autoStart();
copied to clipboard
At exact time scheduled job
class AtExactTimeScheduledJob implements ScheduledJob {
bool ran = false;
@override
Duration? getDuration() => null;
@override
DateTime? getStartTime() => DateTime.now().add(Duration(seconds: 3));
@override
ScheduledJobType getType() => ScheduledJobType.atExactTime;
@override
void run() {
ran = true;
}
}
AtExactTimeScheduledJob atTime = AtExactTimeScheduledJob();
// Will run after 3 seconds
$().schedulerPollingInterval(Duration(seconds: 1))
.schedule(atTime)
.autoStart();
copied to clipboard
At exact time repeating scheduled job
class AtExactTimeRepeatingScheduledJob extends ScheduledJob {
bool ran = false;
@override
Duration? getDuration() => Duration(seconds: 2);
@override
DateTime? getStartTime() => DateTime.now().add(Duration(seconds: 3));
@override
ScheduledJobType getType() => ScheduledJobType.atExactTime;
@override
void run() {
ran = true;
}
}
AtExactTimeScheduledJob atTime = AtExactTimeScheduledJob();
// Will run after 3 seconds, then run every other 2 seconds
$().schedulerPollingInterval(Duration(seconds: 1))
.schedule(atTime)
.autoStart();
copied to clipboard
Web server #
dart_container includes a built in webserver that can be easily configured using Controllers and Routes.
class StausController extends Controller {
StatusController()
: super(
// All the routes under a controller are mounted under the controller prefix
pathPrefix: "/status",
routes: [
GetStatusRoute(),
PostStatusRoute(),
],
// The guard allows secured access to routes. If you don't want anyone accessing a route or
// controller, you can implement a guard
guard: StatusGuard(),
);
}
class StatusGuard extends RouteGuard {
@override
bool isSecure(Request request) {
return true;
}
}
class GetStatusRoute extends AbstractRoute {
GetStatusRoute()
: super(
// All the route parsing is fully compatible with shelf_router since that is the actual library used
["/<key>"],
Method.get,
);
@override
Function buildHandler() {
return _respond;
}
Response _respond(Request req, String key) {
return JsonResponse.okJson({key: "requested"});
}
}
class PostStatusRoute extends AbstractRoute {
PostStatusRoute()
: super(
["/<key>"],
Method.post,
);
@override
Function buildHandler() {
return _respond;
}
Response _respond(Request req, String key) async {
return JsonResponse.ok({key: "posted"});
}
}
$().webServerConfig(
// First of all, we need a not found handler
(req) => Response.notFound(
"Route not found for ${req.method}:${req.requestedUri}"),
// the host
'localhost',
// and the port
env.httpPort,
shared: true,
profiles: ["test", "run"],
)
// Provide the list of controllers
.controllers([
StatusController();
])
// and/or provide a list of routes
.routes([
GetStatusRoute(),
PostStatusRoute(),
])
// set the active profile
.profile("run")
// the call autostart to boot up the web server
.autoStart();
// If you do not want to use the autostartables and still want to boot up the web server, you can
Future.delayed(Duration.zero, () async => $get<WebServer>().run());
.
copied to clipboard
Eventing #
With dart-container you get a simple publish/subscribe framework for passing along messages, and building reactive applications. For the time being, the support is limited to exact matching topics.
Simple topics
// First subscribe to the topic
$().subscribe("topic", (topic, event) {
print("Got message on topic $topic with event value $event");
});
// Then publish to the topic
$().publishEvent(["topic"], "newValue");
// You can also subscribe and publish to multiple topics
// Publishing to multiple subscribers
$().subscribe("topic1", (topic, event) {
print("Subscriber 1 : Got message on topic $topic with event value $event");
});
$().subscribe("topic2", (topic, event) {
print("Subscriber 2 : Got message on topic $topic with event value $event");
});
// or use the shortcut
// $sub("topic2", (topic, event) {
// print("Subscriber 2 : Got message on topic $topic with event value $event");
//});
// Publish a message to multiple topics.
// In this case, both subscribers will get the new message.
$().publishEvent(["topic1", "topic2"], "newValue");
// or use the shortcut
// $pub(["topic1", "topic2"], "newValue");
copied to clipboard
Wildcards and subtopics topics
$().subscribe("topic/*", (topic, event) {
// Will receive messages from both subtopics
});
// Publish message to first subtopic
$().publishEvent(["topic/subtopic1"], "newValue1");
// Publish message to second subtopic
$().publishEvent(["topic/subtopic2"], "newValue2");
$().subscribe("topic/*", (topic, event) {
// Will receive messages from both subtopics
});
// Publish message to first subtopic
$().publishEvent(["topic/subtopic1", "topic/subtopic1"], "newValue1");
// IMPORTANT: When publishing a value to multiple subtopics, the subscriber is only called once
// with the topic parameter having the value of the first matching topic from the publish list
copied to clipboard
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.