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

Optional string parameter causing resolution exception when AnyConcreteTypeNotAlreadyRegisteredSource added #728

Closed
alexmg opened this issue Mar 15, 2016 · 4 comments
Labels

Comments

@alexmg
Copy link
Member

alexmg commented Mar 15, 2016

From Google Group:

https://groups.google.com/forum/#!topic/autofac/lUZ6KAT7xXM

Hi there

I need to use the AnyConcreteTypeNotAlreadyRegisteredSource, to avoid having to explicitly register every concrete type we use.
Unfortunately, I'm having a real issue attempting to use it when we have classes with optional string constructor parameters.

e.g.

    public class TypeWithCtorParam : IInterface
    {
        public TypeWithCtorParam(string stringParam = "MyString") {}
    }

It throws an error

Autofac.Core.DependencyResolutionException: Cannot choose between multiple constructors with equal length 1 on type 'System.String'. Select the constructor explicitly, with the UsingConstructor() configuration method, when the component is registered.

I've attached an nunit test class repro-ing the issue, but basically, to cut it down to the bare bones

  • If the class is registered AsSelf or against its interface, it is resolved fine
builder.RegisterType<TypeWithCtorParam>();
...
scope.Resolve<TypeWithCtorParam>();  // Fine. Yay!
  • If the class is registered AsSelf and/or against its interface, and AnyConcreteTypeNotAlreadyRegisteredSource is used, it throws the error. I would expect this to not be a problem - I mean, it's already explicitly registered, surely it should be excluded from the registration source!
builder.RegisterType<TypeWithCtorParam>();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
...
scope.Resolve<TypeWithCtorParam>();  // Error! Boo!
  • If the class is not explicity registered, and AnyConcreteTypeNotAlreadyRegisteredSource is used, it throws the error.
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
...
scope.Resolve<TypeWithCtorParam>();  // Error! Boo!

I can exclude the types that aren't working, but it'd be nicer not to have to. Bug? Or am I missing something?

Thanks much

@alexmg
Copy link
Member Author

alexmg commented Mar 15, 2016

Unit tests mentioned in post:

using Autofac;
using Autofac.Features.ResolveAnything;
using NUnit.Framework;

namespace AutofacTester
{
    [TestFixture]
    public class AutofacTests
    {
        public class TypeWithCtorParam
        {
            public TypeWithCtorParam(string stringParam = "MyString") {}
        }

        [Test]
        public void ExplicitRegistration_ResolvesOptionalParams()
        {
            var builder = new ContainerBuilder();

            builder.RegisterType<TypeWithCtorParam>();

            var resolver = builder.Build();
            Assert.IsInstanceOf(typeof(TypeWithCtorParam), resolver.Resolve<TypeWithCtorParam>());
        }

        [Test]
        public void AllConcreteTypesSource_ResolvesOptionalParams()
        {
            var builder = new ContainerBuilder();

            builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());

            var resolver = builder.Build();
            Assert.IsInstanceOf(typeof(TypeWithCtorParam), resolver.Resolve<TypeWithCtorParam>());
        }

        [Test]
        public void AllConcreteTypesSource_AlreadyRegistered_ResolvesOptionalParams()
        {
            var builder = new ContainerBuilder();

            // Concrete type is already registered, but still errors
            builder.RegisterType<TypeWithCtorParam>();
            builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());

            var resolver = builder.Build();
            Assert.IsInstanceOf(typeof(TypeWithCtorParam), resolver.Resolve<TypeWithCtorParam>());
        }

        [Test]
        public void AllConcreteTypesSource_WhenExcludedFromSource_ResolvesOptionalParams()
        {
            var builder = new ContainerBuilder();

            // Trying to exclude it, still errors
            builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(t => t.IsAssignableTo<TypeWithCtorParam>()));

            var resolver = builder.Build();
            Assert.IsInstanceOf(typeof(TypeWithCtorParam), resolver.Resolve<TypeWithCtorParam>());
        }
    }
}

@alexmg
Copy link
Member Author

alexmg commented Mar 15, 2016

The AllConcreteTypesSource_WhenExcludedFromSource_ResolvesOptionalParams tests can be made to pass by changing:

builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(t => t.IsAssignableTo<TypeWithCtorParam>()));

To:

builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(t => !t.IsAssignableTo<string>()));

The same issue is not present with an optional int value. The optional string parameter is being treated differently.

@tillig
Copy link
Member

tillig commented Sep 13, 2016

Fixed by PR #785. Woohoo!

@tillig
Copy link
Member

tillig commented Sep 22, 2016

Fix included in v4.1.1, pushed 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