How can I amend context at runtime?
I need to support runtime configuration of RL / dependency injection, how can I do that? Say that I've got logging service that logs to a remote service and with a hidden switch somewhere in the app, I need to change the logging target to a simple trace console as the app is running. Also note that I'll possibly need to switch between service implementations many times during the application run time.
Comments are currently closed for this discussion. You can start a new one.
Keyboard shortcuts
Generic
? | Show this help |
---|---|
ESC | Blurs the current field |
Comment Form
r | Focus the comment reply box |
---|---|
^ + ↩ | Submit the comment |
You can use Command ⌘
instead of Control ^
on Mac
1 Posted by Stray on 25 Jan, 2011 11:56 AM
Two options:
1) Wrap the service location in a model - ie
[Inject]
public var loggingServiceLocator:ILoggingServiceLocator
instead of injecting the service directly. And then pull the actual service from the service locator. Eg - in an UpdateLogCommand
public override function execute():void
{
var loggingService:ILoggingService = loggingServiceLocator.activeService;
// then use it as normal
}
2) Use dynamic mappings - probably via injector.mapValue
// original mapping
injector.mapValue(ILoggingService, RemoteLoggingService);
injector.unmap(ILoggingService);
// new mapping
injector.mapValue(ILoggingService, TraceLoggingService);
Personally I would go with 1, because it means that long-lived injections are supported. Approach 2 would only affect injections that occur after the mapping has been changed.
2 Posted by borekb on 25 Jan, 2011 12:22 PM
Thanks. Will mapValue reinject the new instance to all existing commands, mediators etc.? (I not too keen on the service locator pattern.)
3 Posted by Stray on 25 Jan, 2011 12:39 PM
That's exactly what I said at the bottom of my message...
"Approach 2 would only affect injections that occur after the mapping has been changed."
So - a Command, yes, because it's a new instance.
You shouldn't be injecting services into mediators anyway, so if you've stuck to the purist approach - services and models only accessed through Commands - then yes, your new mapping will be honoured. If you've injected into mediators and they're on stage already, they'll still have the old mapping.
If you have used mediator injection then you'll definitely need to use the service locator pattern. I don't know why you'd be 'unkeen' on that pattern though - models are for storing dynamic parts of the system. If this part is dynamic then why not model it? Seems sensible and much easier to understand and trace problems in code that uses this approach than dynamic mappings.
4 Posted by Paul Robertson on 25 Jan, 2011 04:06 PM
Another approach I've used is this (it's conceptually similar to what
Stray recommends, but implemented differently):
- create an event that triggers the logging, i.e. LogEvent(message)
- for each logging output, create a separate command that expects a
LogEvent and calls a particular logging service, e.g. LogToFileCommand,
LogToConsoleCommand, etc.
- at startup, only map the default logging mechanism to the event:
commandMap.mapEvent(LogEvent.LOG, LogToFileCommand...)
- when you want to switch to a different logging mechanism, do that in
another command, e.g.:
EnableConsoleLoggingCommand
override public function execute():void
{
commandMap.unmapEvent(LogEvent.LOG, LogToFileCommand...)
commandMap.mapEvent(LogEvent.LOG, LogToConsoleCommand...)
}
Of course you don't necessarily have to unmap the one type; you could
just add an additional logging mechanism, or do whatever you like for
your app.
And obviously I've left out lots of details like the events that trigger
the enabling commands. Hopefully this is enough to communicate the idea.
Paul
5 Posted by borekb on 25 Jan, 2011 09:30 PM
Thanks guys.
Stray closed this discussion on 11 Feb, 2011 11:17 PM.