Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The AnyConcreteTypeNotAlreadyRegisteredSource throws an exception when tries to Resolve unregistered Meta<T> types #495

Closed
nemesv opened this issue Feb 14, 2014 · 6 comments
Labels

Comments

@nemesv
Copy link

nemesv commented Feb 14, 2014

If the AnyConcreteTypeNotAlreadyRegisteredSource is used then resolving any non registered Meta types throws an exception.

Here is some testcases demonstating the problem

    [TestFixture]
    public class AnyConcreteTypeNotAlreadyRegisteredSourceTest
    {
        public class ScreenAppender : ILogAppender { }
        public interface ILogAppender { }

        //passes
        [Test]
        public void Test()
        {
            var builder = new ContainerBuilder();
            builder.Register(c => new ScreenAppender())
                   .As<ILogAppender>()
                   .WithMetadata("AppenderName", "screen");
            builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
            var container = builder.Build();
            var meta = container.Resolve<IEnumerable<Meta<ILogAppender>>>();
            Assert.AreEqual(1, meta.Count());
        }

        //passes
        [Test]
        public void Test2()
        {
            var builder = new ContainerBuilder();
            var container = builder.Build();
            var meta = container.Resolve<IEnumerable<Meta<ILogAppender>>>();
            Assert.AreEqual(0, meta.Count());
        }

        //fails
        [Test]
        public void Test3()
        {
            var builder = new ContainerBuilder();
            builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
            var container = builder.Build();
            var meta = container.Resolve<IEnumerable<Meta<ILogAppender>>>();
            Assert.AreEqual(1, meta.Count());
        }
    }

The thrid test throws the following exeption

Autofac.Core.DependencyResolutionException : None of the constructors found with 'Public binding flags' on type Autofac.Features.Metadata.Meta1[ClassLibrary.AnyConcreteTypeNotAlreadyRegisteredSourceTest+ILogAppender]
can be invoked with the available services and parameters:
Cannot resolve parameter 'ILogAppender value' of constructor 'Void .ctor(ILogAppender, System.Collections.Generic.IDictionary`2[System.String,System.Object])'.

See this question on SO for more context : http://stackoverflow.com/questions/21743262/autofac-mvc-5-registerwebapifilterprovider-causes-unresolveable-ioverridefilter

@tillig
Copy link
Member

tillig commented Oct 26, 2016

This appears to affect all generated relationship sources - Owned<T>, Meta<T>, and Lazy<T> are all affected. It looks like Func<T> gets ignored by virtue of it being a delegate (which we already check for and reject in ACTNARS).

An ideal solution would not hardcode all the relationships in ACTNARS but would instead somehow not provide stuff that's already provided. Hmmm.

@tillig
Copy link
Member

tillig commented Oct 26, 2016

It's almost like the registration lookup process needs to behave like an event, like when a lookup takes place in a registration source, not only would you return a (potentially empty) list of registrations, but also something to indicate "stop processing, it's been handled." That way the MetaRegistrationSource or other sources would be able to say, "I'm the system of record for Meta<T> and there is no registration for the thing you asked for, full stop."

I'll have to think about how to deal with that. In the meantime, I'll add the unit test (skipped for now) to the repo so we can work through it.

@tillig
Copy link
Member

tillig commented Oct 26, 2016

OK, I think I figured it out.

For generic types we need to not only check to see if the whole generic is registered, but also see if we can handle the thing in the generic. I'm working through tests now.

That said, I think the bottom test will still fail:

        [Test]
        public void Test3()
        {
            var builder = new ContainerBuilder();
            builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
            var container = builder.Build();
            var meta = container.Resolve<IEnumerable<Meta<ILogAppender>>>();
            Assert.AreEqual(1, meta.Count());
        }

If no ILogAppender is registered, you won't get any elements back in the IEnumerable<Meta<ILogAppender>> resolution. ACTNARS doesn't search for concrete types that implement ILogger, it just creates concrete types. So IEnumerable<Meta<ScreenAppender>> would get you a single element back, but IEnumerable<Meta<ILogAppender>> would not.

Here's a test I have passing with the updated code:

       [Fact]
        public void DoesNotInterfereWithMetadata()
        {
            // Issue #495: Meta<T> not correctly handled with ACTNARS.
            var cb = new ContainerBuilder();
            cb.RegisterType<RegisteredType>().WithMetadata("value", 1);
            cb.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
            var container = cb.Build();

            var regType = container.Resolve<Meta<RegisteredType>>();
            Assert.Equal(1, regType.Metadata["value"]);

            var nonRegType = container.Resolve<Meta<NotRegisteredType>>();
            Assert.False(nonRegType.Metadata.ContainsKey("value"));

            var interfaceMeta = container.Resolve<IEnumerable<Meta<IInterfaceType>>>();
            Assert.Equal(0, interfaceMeta.Count());

            var classMeta = container.Resolve<IEnumerable<Meta<NotRegisteredType>>>();
            Assert.Equal(1, classMeta.Count());
        }

tillig pushed a commit that referenced this issue Oct 26, 2016
@tillig
Copy link
Member

tillig commented Oct 26, 2016

The fix for this is in v4.2.0-354 on the MyGet feed and will eventually be pushed to NuGet as 4.2.0.

@nemesv
Copy link
Author

nemesv commented Oct 27, 2016

Cool! Thanks for the fix!

@tillig
Copy link
Member

tillig commented Nov 3, 2016

Published as 4.2.0 to NuGet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants