Skip to content
New issue

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

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

Already on GitHub? # 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.

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

No branches or pull requests

2 participants