Autofac: cannot resolve dependency using factory after ContainerBuilder.Update() -
my problem want use func<> factory resolve dependency. , in if use containerbuilder update() (i need mocking services in integration tests), factories still resolve outdated instances.
i created simple scenario reproduce problem:
class program { static void main(string[] args) { var containerbuilder = new containerbuilder(); containerbuilder.registertype<test>().as<itest>(); containerbuilder.registertype<test1factory>().as<itestfactory>(); containerbuilder.registertype<testconsumer>().asself(); var container = containerbuilder.build(); var tc1 = container.resolve<testconsumer>(); var cbupdater = new containerbuilder(); cbupdater.registertype<test2>().as<itest>(); cbupdater.registertype<test2factory>().as<itestfactory>(); cbupdater.update(container); var tc2 = container.resolve<testconsumer>(); console.readline(); } } public interface itest { int id { get; set; } } public class test : itest { public test() { id = 1; } public int id { get; set; } } public class test2 : itest { public test2() { id = 2; } public int id { get; set; } } public interface itestfactory { itest create(); } public class test1factory : itestfactory { public itest create() { return new test(); } } public class test2factory : itestfactory { public itest create() { return new test2(); } } public class testconsumer { public testconsumer(func<itest> testfactory, itest test, itestfactory customfactory) { console.writeline("factory: " + testfactory().id); console.writeline("direct: " + test.id); console.writeline("mycustomfactory: " + customfactory.create().id); console.writeline("*************"); console.writeline(); } }
the output is:
factory: 1 direct: 1 mycustomfactory: 1
factory: 1 direct: 2 mycustomfactory: 2
notice "factory: 1" in both cases.
am missing or have create cusom factory in scenario?
p.s.
autofac 3.5.2 or 4.0 beta 8-157 .net 4.5.1
that's design unfortunately, reasons, don't know. looking @ autofac code gives better insight on how register items same interface definition, in short, registrations maintained last registration wins (ref). wait...that's not all, weirdly, fun<...>, them in order. can test changing constructor of testconsumer class to:
public testconsumer(func<itest> testfactory, ienumerable<func<itest>> testfactories, ienumerable<itest> tests, itest test, itestfactory customfactory) { // ... }
note funcs , itest registration. lucky resolving itest directly resolves test2.
now, having said of above, there way described here. have create container without registration want override, therefore:
/// <summary> /// has not been tested requirements /// </summary> private static icontainer removeoldcomponents(icontainer container) { var builder = new containerbuilder(); var components = container.componentregistry.registrations .where(cr => cr.activator.limittype != typeof(lifetimescope)) .where(cr => cr.activator.limittype != typeof(func<itest>)); foreach (var c in components) { builder.registercomponent(c); } foreach (var source in container.componentregistry.sources) { builder.registersource(source); } return builder.build(); }
and can change main method following:
static void main(string[] args) { var containerbuilder = new containerbuilder(); containerbuilder.registertype<test>().as<itest>(); containerbuilder.registertype<test1factory>().as<itestfactory>(); containerbuilder.registertype<testconsumer>().asself(); var container = containerbuilder.build(); var tc1 = container.resolve<testconsumer>(); container = removeoldcomponents(container); var cbupdater = new containerbuilder(); cbupdater.registertype<test2>().as<itest>(); cbupdater.registertype<test2factory>().as<itestfactory>(); cbupdater.update(container); var tc2 = container.resolve<testconsumer>(); console.readline(); }
ps: wouldn't great have method exact opposite of preserveexistingdefaults()
Comments
Post a Comment