I want to subscribe an global event which is invoked after a registration has been added.
I don't want to manually subscribe to an event for every registered service/component, because that's boilerplate code and it's easy to forget it when adding new registrations.
When the event fires I want do some checks on the already registered registrations and if a condition is met, e.q it's a named registration and it's a reference type then I want to add additional/new registrations, this should happen before the container is built.
What's the right way to achieve this?
Can I do it in a CustomModule that derives from Module?
Br
Autofac doesn't support "registration events" or anything like that - only resolution events. What you might be able to do is:
Use the OnlyIf extensions for conditional registration (here are the unit tests showing examples)
Register your conditional thing last so everything else is registered and OnlyIf will work.
Possibly use the Properties dictionary on the ContainerBuilder to your advantage, such that when the important things get registered they add something to the properties dictionary that you can check for.
I think some combination of those things should get you what you're looking for. But, unfortunately, there's no event. The reason is that registrations aren't just a simple collection of objects the way they are in Microsoft.Extensions.DependencyInjection - registrations are all callback methods that don't actually execute until you call Build. The final set of registrations is only really available then; and when Build is called, you can't modify that list of callbacks post-facto to add or change registrations.
That architecture is not likely to change because it's pretty baked into the core of the builder syntax for registrations. The above options are about it.
Related
I am trying to use MediatR to set up generic notifications, but the notification handler is being called multiple times.
https://github.com/smartaypants/MediatR/blob/master/test/MediatR.Tests/CustomNotificationTests.cs
The test publishes a CustomNotification which implements ICustomNotification. The CustomNotificationHandler is constrained to accept TNotification which must implement ICustomNotification.
I would expect this to only be called once but the handler is being called 3 times - where TNotification is CustomNotification, CustomNotificationBase and ICustomNotification - but they are all the same instance... should that happen?
If I remove the ContravariantRegistrationSource line from the Autofac registration then it works as expected. Similarly if I use the StructureMap registration it works fine.
I don't entirely understand why I need to enable contravariance. I am only using this line because it is included on the MediatR wiki and almost every example I can find.
Please can someone explain why this is happening and if I am doing something wrong, or is it a bug in Autofac. Thanks.
When designing an application's back-end you will often need to abstract the systems that do things from the systems that actually do them.
There are elements of this in the CQRS and PubSub design patterns.
By way of example:
A new user submits a registration form
Your application receives that data and pushes out a message saying “hey i have some new user data, please do something with this”
A listener / handler / service grabs the data and processes it
(please let me know if that makes no sense)
In my applications I would usually:
Fire a new Event that a Listener is set up to process Event::fire('user.new', $data)
Create a new Command with the data, which is bound to a CommandHandler new NewUserCommand($data)
Call a method in a Service and pass in the data UserService::newUser($data)
While these are nearly exactly the same, I am just wondering - how do you go about deciding which one to use when you are creating the architecture of your applications?
Fire a new Event that a Listener is set up to process
Event::fire('user.new', $data)
Event pattern implies that there could be many handlers, subscribing to the same event and those handlers are disconnected form the sender. Also event handlers usually do not return information to the sender (because there can be actually many handlers and there is a confusion about whose information to return).
So, this is not your case.
Create a new Command with the data, which is bound to a CommandHandler
new NewUserCommand($data)
Commands are an extended way to perform some operation. They can be dispatched, pipelined, queued etc. If you don't need all that capabilities, why to complicate things?
Call a method in a Service and pass in the data
UserService::newUser($data)
Well, this is the most suitable thing for your case, isn't it?
While these are nearly exactly the same, I
am just wondering - how do you go about deciding which one to use when
you are creating the architecture of your applications?
Easy. From many solutions choose only those, which:
metaphorically suitable (do not use events, where your logic does not look like an event)
the simplest (do not go too deep into the depths of programming theories and methods. Always choose solution, that lowers your project development complexity)
When to use command over event?
Command: when I have some single isolated action with few dependencies which must be called from different application parts. The closest analogue is some editor command, which is accessible both from toolbar and menu.
Event: when I have several (at least in perspective) dependent actions, which may be called before/after some other action is executed. For example, if you have a number of services, you can use events to perform cache invalidation for them. Service, that changes a particular object emits "IChangedObject" event. Other services subscribe to such events and respond to them invalidating their cache.
Does the Zend 2 event manager have the ability to fire listeners in classes that are not loaded?
If I understand you correctly, then I believe that you can register listeners using the StaticEventManager (see Event Manager Quick Start).
In this case, you do not need to have an instance of the target class (just the name), but you can register listeners for events (typically methods) on future instances of that target class that may occur.
Of course, in order to be useful, the target class should actually compose an EventManager instance (probably via an events() method, as described on the same Quick Start page) and actually fire the events.
I confess that I am still trying to wrap my own head around the ZF2 EventManager, so if I have totally boned it up here, please feel free to correct me.
I have a GWT MVP application using Activities and Places. This is inspired by Mauro Bertapelle's sample (in this thread), apparently based on some of Thomas Broyer's work.
Here's the problem: I have LoginActivity make an RPC call, which for a successful login, returns a User. This user has a role (e.g., admin, regular user, guest). Several Views and Activities, including a NavigatorView, depend on this role for what they show or do. How do I get this User instance to the other Activities?
I do not have a ClientFactory; injection (Gin) is used for instantiating the Views in the ActivityProviders which provide my Activities/Presenters, and the ActivityProviders are injected into my ActivityMapper. So this may reduce to a Gin question: how do I get the user reference where it's needed? This seems to be similar to this SO question about global references in MVP.
Consider me a Gin newbie, this is my first attempt at using it. I'm guessing there is a "Gin way" to make this happen, but I don't know Gin well enough to know the best way to do this (if Gin should be used at all).
Much thanks.
Edit 1: Despite my best efforts searching SO for a similar question, I just found this question which is pretty much identical to mine (is the SO algorithm for finding "Related" links better than the search?). I'm thinking that the Gin answer by David is on the right track.
I don't think that an EventBus solution is possible. I'm following the Google guidelines which involve instantiating Activity at every Place change, so a single Event by itself will not suffice.
Something that I'm using on the server-side with Guice, and would work just as well on the client-side, is to bind to a custom Provider. In your case though, you'd have to make the provider a singleton and push the value into it from your RPC callback (rather than pulling it from some context).
You'd first need a specific provider:
#Singleton
public class CurrentUserProvider implements Provider<User> {
private User currentUser;
public User get() { return currentUser; }
public void setCurrentValue(User currentUser) {
this.currentUser = currentUser;
}
}
You'd bind User to the provider: bind(User.class).toProvider(CurrentUserProvider.class)
In your RPC callback you'd inject a CurrentUserProvider so you can setCurrentValue but everywhere else you'd inject Provider<User> to keep CurrentUserProvider as an implementation detail. For very short-lived objects, you could directly inject a User value rather than a Provider<User>.
If you need to notify objects of the value change, you could dispatch an event on the global event bus.
Alternately, you could always use the concrete CurrentUserProvider type (which wouldn't have to implement Provider anymore) and possibly make it a HasValueChangeHandlers so you could register listeners on it rather than on the event bus (but you'd have to clean-up after yourself in your activities' onStop and onCancel to avoid memory leaks, whereas it's taken care of automatically if you register handlers on the event bus in onStart).
(if you ask me, I'd rather go away with authenticating from within the app whenever possible)
I had similar requirements on a recent project.
When I get a reply from login (or logout) RPC I send a custom AuthenticationEvent on EventBus. All activities that are interested in this listen for this event. AuthenticationEvent has a reference to AppUser object which is null if user just logged out. AppUser contains all necessary data (privileges, groups, etc..) so that activities can inspect it and act upon it.
About global references: you can have a class with static methods providing data that you need. This class internally holds singleton references to needed instances. In my example I have static method AppUtils.getCurrentUser(). Internally it holds a reference to AppUser and also listens to AuthenticationEvent to set/reset this field.
As a side note: don't rely on client side to enforce access restrictions - you should separate your RPC servlets into two groups: public and private. Public can be accessed by anybody (this is basically login/logout RPC and some other public info RPC), while private RPC requires user to be authenticated. Access restrictions can be set per path/servlet: http://code.google.com/appengine/docs/java/config/webxml.html#Security_and_Authentication
Update:
As you noted, class with static methods is not advisable in this setup, because it is not replaceable and this prevents testing (which is the whole point of using GIN).
The solution is to inject a utility class holding globals (AppUtils) into activities that need the globals. AppUtils should be declared singleton in GIN configuration as one instance is enough for the whole app.
To use Provider or not is just a question if you want to delay the initialization of dependencies (AppUtil is dependency). Since AppUtils is a singleton for the whole app it makes no sense to have it lazy initialized.
Sometimes you will have a situation where you have multiple Activities shown on screen (in my case it was MenuBar and InfoBar). In this case, when user logs in you will need a way to notify them of the change. Use EventBus.
I'm collaborating on a large Kynetx app with another developer. To make it easier to split up the work, I'd like to have multiple rulesets so we can work on them separately without stepping on each other's toes.
Is there a way to raise an event (explicit or otherwise) in another ruleset? Something like this in a postlude:
raise explicit event next_section in a163x50
I know it's possible to do with JavaScript in the browser, but I'd like to do this from the KRL on the server side.
You can raise events in the postlude, and you use with [appid] instead of in. Check out the Explicit Events section of the Postlude Documentation.
Here is an example postlude, raising an event to a new app with some context:
fired {
raise explicit event "something" for a163x50 with cheese = "swiss";
}
For a really complete walkthrough of loosely coupled rulesets, see Phil Windley's post called Tweeting from KBlog.
Don't forget about modules for code reuse. Wrapping functionality in a module makes it much easier to test that code, and enable use within multiple rulesets.