zcz527 / autofac

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

Generic module/extension for enabling global property injection #382

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
From the discussion here: 
https://groups.google.com/forum/?fromgroups#!topic/autofac/-SC8XzuzxHE

Creating a module for log4net (or other logging) integration that enables the 
logger to be injected via both constructor or property is a common thing. It 
also may not necessarily be a function connected only to logging - other object 
types may need to be registered as globally injectable property values.

Add a generic module or registration extension method that enables a registered 
type to be injected as a property value without every other consuming 
registration having to specify PropertiesAutowired().

For example:
builder.RegisterType<Foo>().As<IFoo>().EnableGlobalPropertyInjection();

or

public abstract class PropertyInjector<T> : Module
(like from this gist: https://gist.github.com/3066496)
builder.RegisterModule<MyPropertyInjector>();

Original issue reported on code.google.com by travis.illig on 9 Jul 2012 at 3:41

GoogleCodeExporter commented 8 years ago

Original comment by travis.illig on 21 Sep 2012 at 4:37

GoogleCodeExporter commented 8 years ago
This appears to overlap with issue #210. Not sure if it's a duplicate, though.

Original comment by travis.illig on 30 Nov 2012 at 7:31

GoogleCodeExporter commented 8 years ago
Seeing how a module for log4net injection is something I use all the time, I 
have created a module that does both ctor and property injection. I would love 
to add it to Autofac. In that case , I suppose it would be appropriate as a 
Extras.Log4net project

The module could easily be made more reusable to do the same injection for 
arbitrary services. Where such a module should live must be considered. How the 
global properties injection extension method should be made, I have not looked 
into yet.

Original comment by plillev...@gmail.com on 21 Feb 2013 at 1:46

GoogleCodeExporter commented 8 years ago
...and now I saw the mentioned gist :) it basically does the exact same thing 
as my module. Anyways, would be great to have this easily available as part of 
core Autofac plus logger-specific packages.

Original comment by plillev...@gmail.com on 21 Feb 2013 at 2:20

GoogleCodeExporter commented 8 years ago
I was looking at this and I can see where we may need to be a little more 
specific about how we want things to behave.

You can set up property injection on a reflection-based activator. This works:

  // Works
  builder.RegisterType<Consumer>().WithProperty("Prop", dependency);

You can't do that same thing with delegate activators. You can't provide 
parameters at all (it's not just the WithProperty extension method signature, 
it's consistent):

  // Doesn't work
  builder.Register(c => new Consumer()).WithProperty("Prop", dependency);
  builder
    .Register(c => new Consumer())
    .WithParameter(new NamedPropertyParameter("Prop", dependency));

Even if you try to pass the parameter during Resolve, it still doesn't work.

  // Doesn't work
  builder.Register(c => new Consumer());
  ...
  container.Resolve<Consumer>(new NamedPropertyParameter("Prop", new Dependency()))

Your delegate is actually supposed to look at the incoming parameters and "do 
the right thing":

  // Works
  builder.Register((c, p) =>
  {
    var consumer = new Consumer();
    consumer.Prop = (Dependency)p.OfType<NamedPropertyParameter>()
                                 .Where(prop => prop.Name =="Prop")
                                 .First()
                                 .Value;
    return consumer;
  });

Given that, would it still be correct to try to inject properties globally 
without doing some sort of "hook" into the appropriate activator? The current 
proposals don't seem to care about the activation type for the component, but 
that's somewhat inconsistent behavior with the rest of the framework.

Of course, maybe it's the rest of the framework that's inconsistent and the 
delegate activator SHOULD take parameters, at least for use inside the 
delegate, even if the delegate chooses to ignore them. (In which case we'd want 
a different issue filed to allow .WithParameter and .WithProperty to work on 
the delegate activator, too.)

The module approach is nice, and it's easy, but I just want to make sure it's 
the right approach prior to coding it up. I'm guessing there could be some 
slightly undesired effects with delegate activator interactions (properties 
getting set when they're not expected to be set).

Original comment by travis.illig on 10 Apr 2013 at 4:29

GoogleCodeExporter commented 8 years ago
I agree that global property injection is dangerous. After all, the default in 
Autofac is that properties are not injected unless you specify 
PropertiesAutowired on a specific registration. And as you say, otherwise 
properties may be set when they're not expected to be set.

Now, the main goal of the log4net module in particular is to enable injection 
of ILog instances across all types without the need to declare this explicitly 
in each registration. For ctor injected dependencies, I see no issues with 
using the module approach. 

For properties, what I would like to see is a combination of both: the module 
should property-inject ILog instances, but only on services that have 
explicitly stated PropertiesAutowired. 

Original comment by plillev...@gmail.com on 24 Apr 2013 at 12:52

GoogleCodeExporter commented 8 years ago
Moved issue to GitHub: https://github.com/autofac/Autofac/issues/382

Subsequent issue management will be held there; closing the issue on Google 
Code as "WontFix" because we will handle issue resolution on GitHub.

Original comment by travis.illig on 11 Feb 2014 at 12:05