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.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/src/Autofac/Core/Lifetime/MatchingScopeLifetimeResources.resx b/src/Autofac/Core/Lifetime/MatchingScopeLifetimeResources.resx index 31503a186..9a09571fa 100644 --- a/src/Autofac/Core/Lifetime/MatchingScopeLifetimeResources.resx +++ b/src/Autofac/Core/Lifetime/MatchingScopeLifetimeResources.resx @@ -1,17 +1,17 @@  - @@ -120,6 +120,8 @@ No scope with a tag matching '{0}' is visible from the scope in which the instance was requested. -If you see this during execution of a web application, it generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario). Under the web integration always request dependencies from the dependency resolver or the request lifetime scope, never from the container itself. +If you see this during execution of a web application, it generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario). Under the web integration always request dependencies from the dependency resolver or the request lifetime scope, never from the container itself. + +See https://autofac.rtfd.io/help/no-matching-scope for more info. - \ No newline at end of file + diff --git a/src/Autofac/Core/Registration/ComponentNotRegisteredExceptionResources.resx b/src/Autofac/Core/Registration/ComponentNotRegisteredExceptionResources.resx index 903522356..41cbf4ee7 100644 --- a/src/Autofac/Core/Registration/ComponentNotRegisteredExceptionResources.resx +++ b/src/Autofac/Core/Registration/ComponentNotRegisteredExceptionResources.resx @@ -1,17 +1,17 @@  - @@ -118,6 +118,8 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - The requested service '{0}' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency. + The requested service '{0}' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency. + +See https://autofac.rtfd.io/help/service-not-registered for more info. - \ No newline at end of file + 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(