zcz527 / autofac

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

Wrapper around IStartable to make a component implicitly activated #388

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
I have services in the system which are not direct dependencies of any other 
component. Yet I want to force them into existence.
To do so I seem to only have two options:

* register the type and do a lifetime.Resolve<..>
This is leaking module configuration details into the unrelated lifetime of the 
application, not cool

* RegisterInstance()
Unfortunately does not give me a way to have the ctor dependencies of the class 
resolved via Reflection

What I'd like is a way to Register an instance but resolve ctor dependencies 
from the context, similar to what Register(c=>...) gives me.

Not sure where this feature would exactly make sense, I can see a few ways 
(from a pure users point of view).

EXAMPLES

// similar to SingleInstance() et al
builder.RegisterType<Blah>().ForceInstance()...

or

// from within a callback when the container is completely configured
// RegisterCallback does not give me a context...
builder.RegisterType<Blah>().OnContainerConfigured(c => c.Resolve<Blah>())

or

// a hybrid between Register(c=>...) and RegisterInstance()
builder.RegisterInstance(c => new Blah(c.Resolve<..>))...

Original issue reported on code.google.com by estrada.raphael on 2 Oct 2012 at 1:46

GoogleCodeExporter commented 8 years ago
I just realized that I can probably work around that problem using IStartable

I really don't want to leak the Autofac DLL throughout my system though - 
trying to hide it in an extension method...

will post update

Original comment by estrada.raphael on 2 Oct 2012 at 2:02

GoogleCodeExporter commented 8 years ago
I successfully worked around this. Here is the code I used to emulate this 
feature in Autofac.
https://gist.github.com/3819481

I think it would be neat if Autofac did this out-of-the-box.

Original comment by estrada.raphael on 2 Oct 2012 at 2:17

GoogleCodeExporter commented 8 years ago
OK, so now I'm using an extra AutofacExtensions DLL next to Autofac to use this 
functionality. Would it be feasible to include this in a future version of 
Autofac?

Original comment by estrada.raphael on 2 Oct 2012 at 3:10

GoogleCodeExporter commented 8 years ago
I fear I may be missing something in the use here.

For example, I see this...

// a hybrid between Register(c=>...) and RegisterInstance()
builder.RegisterInstance(c => new Blah(c.Resolve<..>))...

...and I think "that's what SingleInstance lifetime scope already does."

I also see you mention that you have two object types and you want to force 
instances to be created but nothing depends on them. I'm not sure what the use 
case is there. The instance gets created, but no one ever resolves it?

If you're trying to get away from Autofac-specific behavior, have you 
considered a wrapper like the ASP.NET MVC "IDependencyResolver" or EntLib 
common service locator?

Like I said, I may be missing something. More than happy to consider new 
features, just want to make sure there isn't already a way to do what you're 
looking to do and that it's something that would be generally appealing.

Original comment by travis.illig on 8 Oct 2012 at 10:02

GoogleCodeExporter commented 8 years ago
Sorry I only now saw your response.

The use case here is that I want a service to be activated without another 
service depending on it. I can do that by manually creating it and registering 
the instance with with RegisterInstance, but that does not help me resolve the 
service's dependencies through the container.

Actual example:
I have a framework that has a producer/consumer situation at it's core. You can 
plug into the framework as a consumer, and via a messaging system will receive 
data from various sources on the network. Point being that you as a framework 
user will not and should not know which producers are sourcing the data and 
piping it into the system. The producers need to be activated automagically.

I know that this goes against the "composition root" idea that effectively your 
launching (exe) project at some point forces all the required services into 
existence, i.e. by resolving them "manually". But that's a really bad solution 
here where I precisely do not want the launching code to have to know which 
producers exist in the system. All they do is include one of the framework's 
modules, and it registers those producers so that they are activated behind the 
scenes.

Btw here's the implementation I use in my project:
https://github.com/galaktor/autofac-extensions/

My implementation might have a few rough edges when it comes to integrating it 
into the "official" autofac world, I am sure of that. But the tldr of what I 
think is missing is the ability to have a service be activated by the container 
without the composition root or some other service explicitly requesting it.

My example pretty much only makes sense for Singleton lifetime services since 
there might not be much point in activated a factory lifetime component once 
and disposing it immediately (I can probably come up with some useful examples 
for that too, though).

Original comment by estrada.raphael on 6 Nov 2012 at 7:57

GoogleCodeExporter commented 8 years ago
I like your solution to the issue and I know we've seen a few other requests 
for sort of a "warm start" mechanism for components like that. I'm not sure I 
personally agree with the pattern - that the container is "multi-purposed" into 
also being an activator - but we do have the IStartable thing and this seems 
like a natural extension of that.

I see that your code has an MIT license on it, but just to be sure... if we 
implement something like this, do you mind if we use some of the stuff you 
wrote as a starting point?

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

GoogleCodeExporter commented 8 years ago

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

GoogleCodeExporter commented 8 years ago
Issue 390 has been merged into this issue.

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

GoogleCodeExporter commented 8 years ago
sure, you're free to use it according to the MIT license, which really just 
means "mention me somewhere". i license virtually all my OSS code like that.
if that's a problem for you, I might let you use it anyway given that I'm happy 
to contribute anything to this project which has been very useful to me.

that said, I'm sure there's probably nicer ways to do the same thing, better 
integrated with the existing framework.

particularly, enforcing it's usage together with the .AsSingleton() would seem 
reasonable.

Original comment by estrada.raphael on 13 Dec 2012 at 6:59

GoogleCodeExporter commented 8 years ago

Original comment by travis.illig on 14 Dec 2012 at 8:34

GoogleCodeExporter commented 8 years ago

Original comment by travis.illig on 14 Dec 2012 at 9:02

GoogleCodeExporter commented 8 years ago
It turned out I couldn't quite do it the way you did because sometimes things 
are registered "as themselves," sometimes it's keyed, sometimes it's typed... I 
ended up doing a little modification to ContainerBuilder to locate "flagged" 
components and resolve the component proper rather than resolving the component 
through a specific registered service.

Think
builder.RegisterType<A>().As<IFoo>().As<IBar>()
...which thing to I resolve?

Instead, I did a little internal workings and now you can do:
builder.RegisterType<A>().As<IFoo>().AutoStart();

That should be committed soon.

Original comment by travis.illig on 14 Dec 2012 at 10:08

GoogleCodeExporter commented 8 years ago
This issue was closed by revision 8b37a1c59f46.

Original comment by travis.illig on 14 Dec 2012 at 10:11

GoogleCodeExporter commented 8 years ago
Thanks! Perhaps AutoActivate is more consistent with OnActivated and 
OnActivating? Also I hope it works with RegisterInstance.

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