diff --git a/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs b/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs index 84b3fc46d..3dd6f8467 100644 --- a/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs +++ b/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs @@ -290,12 +290,24 @@ private string GetBindingFailureMessage(BoundConstructor[] constructorBindings) reasons.Append(invalid.Description); } - return string.Format( - CultureInfo.CurrentCulture, - ReflectionActivatorResources.NoConstructorsBindable, - ConstructorFinder, - _implementationType, - reasons); + if (ConstructorFinder is DefaultConstructorFinder) + { + // Simplify the text for the common default finder case (to make the message easier to understand). + return string.Format( + CultureInfo.CurrentCulture, + ReflectionActivatorResources.NoConstructorsBindableDefaultBinder, + _implementationType, + reasons); + } + else + { + return string.Format( + CultureInfo.CurrentCulture, + ReflectionActivatorResources.NoConstructorsBindable, + ConstructorFinder, + _implementationType, + reasons); + } } private void InjectProperties(object instance, IComponentContext context) diff --git a/src/Autofac/Core/Activators/Reflection/ReflectionActivatorResources.Designer.cs b/src/Autofac/Core/Activators/Reflection/ReflectionActivatorResources.Designer.cs index e010e10bc..8af4ef8ef 100644 --- a/src/Autofac/Core/Activators/Reflection/ReflectionActivatorResources.Designer.cs +++ b/src/Autofac/Core/Activators/Reflection/ReflectionActivatorResources.Designer.cs @@ -86,5 +86,16 @@ internal static string NoConstructorsBindable { return ResourceManager.GetString("NoConstructorsBindable", resourceCulture); } } + + /// + /// Looks up a localized string similar to None of the constructors found on type '{0}' can be invoked with the available services and parameters:{1} + /// + ///See https://autofac.rtfd.io/help/no-constructors-bindable for more info.. + /// + internal static string NoConstructorsBindableDefaultBinder { + get { + return ResourceManager.GetString("NoConstructorsBindableDefaultBinder", resourceCulture); + } + } } } diff --git a/src/Autofac/Core/Activators/Reflection/ReflectionActivatorResources.resx b/src/Autofac/Core/Activators/Reflection/ReflectionActivatorResources.resx index 4cac50c7f..120f587f3 100644 --- a/src/Autofac/Core/Activators/Reflection/ReflectionActivatorResources.resx +++ b/src/Autofac/Core/Activators/Reflection/ReflectionActivatorResources.resx @@ -126,4 +126,9 @@ None of the constructors found with '{0}' on type '{1}' can be invoked with the available services and parameters:{2} - \ No newline at end of file + + None of the constructors found on type '{0}' can be invoked with the available services and parameters:{1} + +See https://autofac.rtfd.io/help/no-constructors-bindable for more info. + + diff --git a/test/Autofac.Test/Core/Activators/Reflection/ReflectionActivatorTests.cs b/test/Autofac.Test/Core/Activators/Reflection/ReflectionActivatorTests.cs index b4641e76d..42ebc72b2 100644 --- a/test/Autofac.Test/Core/Activators/Reflection/ReflectionActivatorTests.cs +++ b/test/Autofac.Test/Core/Activators/Reflection/ReflectionActivatorTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Autofac Project. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. +using System.Reflection; using Autofac.Core; using Autofac.Core.Activators.Reflection; using Autofac.Test.Scenarios.ConstructorSelection; @@ -180,7 +181,7 @@ public void NonPublicConstructorsIgnored() var dx = Assert.Throws(() => invoker(Factory.CreateEmptyContainer(), Factory.NoParameters)); - Assert.Contains(typeof(DefaultConstructorFinder).Name, dx.Message); + Assert.Contains(typeof(InternalDefaultConstructor).Name, dx.Message); } [Fact] @@ -338,6 +339,20 @@ public void ConstructorSelectorCannotReturnInvalidBinding() Assert.Throws(() => invoker(container, Factory.NoParameters)); } + [Fact] + public void CustomBinderNameIncludedInErrorMessage() + { + var target = Factory.CreateReflectionActivator(typeof(InternalDefaultConstructor), new SimpleConstructorFinder()); + + // Constructor finding happens at pipeline construction; not when the pipeline is invoked. + var invoker = target.GetPipelineInvoker(Factory.CreateEmptyComponentRegistry()); + + var dx = Assert.Throws(() => + invoker(Factory.CreateEmptyContainer(), Factory.NoParameters)); + + Assert.Contains(typeof(SimpleConstructorFinder).Name, dx.Message); + } + private class MisbehavingConstructorSelector : IConstructorSelector { public BoundConstructor SelectConstructorBinding(BoundConstructor[] constructorBindings, IEnumerable parameters) @@ -346,6 +361,11 @@ public BoundConstructor SelectConstructorBinding(BoundConstructor[] constructorB } } + private class SimpleConstructorFinder : IConstructorFinder + { + public ConstructorInfo[] FindConstructors(Type targetType) => targetType.GetDeclaredPublicConstructors(); + } + public class AcceptsIntParameter { public AcceptsIntParameter(int i) diff --git a/test/Autofac.Test/Factory.cs b/test/Autofac.Test/Factory.cs index 9acd09277..b0d41257f 100644 --- a/test/Autofac.Test/Factory.cs +++ b/test/Autofac.Test/Factory.cs @@ -82,6 +82,16 @@ public static ReflectionActivator CreateReflectionActivator(Type implementation, properties); } + public static ReflectionActivator CreateReflectionActivator(Type implementation, IConstructorFinder customFinder) + { + return new ReflectionActivator( + implementation, + customFinder, + new MostParametersConstructorSelector(), + NoParameters, + NoProperties); + } + public static ReflectionActivator CreateReflectionActivator(Type implementation, IConstructorSelector customSelector) { return new ReflectionActivator(