zcz527 / autofac

Automatically exported from code.google.com/p/autofac
Other
0 stars 0 forks source link

IStartable is too cumbersome #390

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
IStartable should be an option when registering the component, not an 
interface, especially not an interface with a method.

Compare the steps of declaring IStartable:
   Inherit from IStartable
   Create (usually empty) Start method
   Call As<IStartable>() during registration

vs an option when registering:
   Call (eg) Autostart() when registering

The start() method is unnecessary, when there is already an OnActivating (which 
the doc recommends to use and which is consistent across all components).

My biggest gripe, though, is that I've implemented an Attribute-based interface 
to Autofac, and implementing an interface with a method is too much work to do 
using reflection.

Original issue reported on code.google.com by adubin...@almson.net on 10 Nov 2012 at 6:21

GoogleCodeExporter commented 8 years ago

Original comment by travis.illig on 16 Nov 2012 at 8:10

GoogleCodeExporter commented 8 years ago
The point of IStartable is to execute some sort of startup logic one time for 
specific services. That is, not just resolve the service and its relative 
dependencies, but also execute some logic on it.

If all you need to do is make sure you have a singleton instance, you can use 
the .SingleInstance() lifetime.

If you don't have any logic that actually needs to be run, registering the 
service as .SingleInstance() will do the same thing as IStartable the first 
time you resolve the service.

OnActivating runs every time a service is resolved. If your service is 
SingleInstance, then yes, IStartable is roughly the equivalent of applying an 
OnActivating handler. On the other hand, if your service is NOT single 
instance, then IStartable handles a use case that can't necessarily be handled 
by OnActivating.

If you are trying to "warm start" your app, there may be other ways to go about 
it - from rolling your own "scan-for-types-and-resolve-from-container" sort of 
method to registering a single IStartable implementation that does all the warm 
starting for you.

If we were to have something like "Autostart()" it would effectively end up 
being an OnActivating handler, in which case... just use OnActivating (or wrap 
your own extension method around it). We couldn't really provide something that 
doesn't know about some interface like IStartable because we have to be able 
to...
* Search all the registrations for some... "criteria." Right now we search for 
IStartable. How would you define the criteria to search for? A complex lambda 
expression may be just as difficult (if not more) than just throwing " : 
IStartable" on the end of a class definition.
* Execute... something. Again, the point is that IStartable is doing some 
one-time logic, not just warm-starting single instance services. How would we 
know what to execute?

I'm not sure how we could accommodate for that level of flexibility. 
Implementing a simple interface may be cumbersome, but the alternative is 
pretty error-prone and difficult to work with from an end developer standpoint. 
It would also be kind of hard to test and maintain from a framework perspective.

For now I'm going to mark this "won't fix." I'm happy to reopen it if you can 
maybe provide a patch or some additional insight as to how this would work in 
the more general form (something the Autofac team can maintain and something 
that is easily usable). We're also open to contributions - this sounds like a 
great Autofac.Extras idea.

Original comment by travis.illig on 5 Dec 2012 at 10:22

GoogleCodeExporter commented 8 years ago
All I want is, as you say, a warm start mechanism, without having to do a bunch 
of extra work. I think this is pretty simple for you and a common use case. (So 
common that Spring starts all singletons automatically.)

I still don't understand the need for IStartable, especially having a 
non-singleton that has an instance method run exactly once (if this is somehow 
necessary just check a static IsInitialized flag in the OnActivated 
callback--though whatever task is being done there probably should be 
encapsulated in a singleton), but that's for you to decide.

Original comment by adubin...@almson.net on 7 Dec 2012 at 3:20

GoogleCodeExporter commented 8 years ago
Btw, you say that the main use case for IStartable is to run code at the start. 
So why does it also force activation? Aren't they two unrelated concerns?

Original comment by adubin...@almson.net on 7 Dec 2012 at 6:31

GoogleCodeExporter commented 8 years ago
While I personally disagree with the pattern, it seems to be a common request 
and another person filing a related/duplicate issue has also provided some more 
concrete examples illustrating what they're looking for. We'll see if we can 
implement something based on that code (Issue 388).

Original comment by travis.illig on 13 Dec 2012 at 4:12

GoogleCodeExporter commented 8 years ago
looks like you implemented this in the comments on the other issue. yay! To 
assuage your guilt, I'll explain the use cases i have for this. In silverlight, 
i display popups and childwindows in certain situations. who launches them? a 
singleton that listens to events in the model. sure, i can inject this 
singleton into a view model just so it would exist, but why? I'm not a devout 
MVVMer. Again, in a silverlight application i have a model with a list of 
intersting things. in the view, i have a control that works without a viewmodel 
to display them. this control is registered as a component via registerinstance 
and is autowired. this its all done via some custom annotations in. it offers 
no services and must be auto activated. (again, i'm not using a vm because it's 
unnecessary work. first, the vm would just pass the model's collection 
unaltered, second the vm has to be wired to the view manually when there's this 
thing called dependency injection that i heard got invented). lastly, in a java 
spring web service i have a singleton that launches a background thread that 
queries the database looking for work units. here there is definitely nothing 
that could resolve it.

using dependency injection with xaml is a whole thing unto itself. I've got it 
down to a science. the trick is you need to make a special panel that hosts the 
container, can load a mock container when examining the control in the 
designer, will inherit the container from a parent when the control is part of 
a page, and builds the container on the first layoutupdated so all xaml 
components are ready to both use and provide services. (my ui is not a 
simple.business app and some ui controls provide critical services for other ui 
controls)

Original comment by adubin...@almson.net on 15 Dec 2012 at 5:01