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

Autofac.Core.Registration.ComponentNotRegisteredException for a registered component #22

Closed
kahaeia1 opened this issue Feb 3, 2019 · 8 comments

Comments

@kahaeia1
Copy link

kahaeia1 commented Feb 3, 2019

I was using:
Autofac 4.8.1
Autofac.Extras.Moq 4.3.0

Autofac.Core.Registration.ComponentNotRegisteredException
HResult=0x80131500
Message=The requested service 'MyControlStandard.MyService.IMyManager' 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.
Source=Autofac
StackTrace:
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable1 parameters) at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable1 parameters)
at MyProject.Tests.MyProject.Engines.UnitTestServices.MockEngineDependencies(AutoMock autoMock) in D:\Code\products\MyProject\MyProject.Tests\MyProject\Engines\UnitTestServices.cs:line 22
at MyProject.Tests.MyProject.Engines.NameDemoEngineTests..ctor(BaseFixture baseFixture) in D:\Code\products\MyProject\MyProject.Tests\MyProject\Engines\NameDemoEngineTests.cs:line 39

I had fun trying to resolve the above-mentioned exception for a couple of hours. The main problem was that the class was actually registered in the DI container and other dependencies were resolved but one of the dependencies was throwing this exception. After searching the whole internet, I noticed this StackOverflow thread: https://stackoverflow.com/questions/46886274/error-when-create-instance-generic-type-with-automock

The problem mentioned in that thread is not exactly my problem. But when I tried downgrading Autofac.Extras.Moq to version 4.0.0 my problem was resolved.

This is the rough code:


public MyEngineTests(BaseFixture baseFixture)
        {
            // Arrange
            m_autoMock = AutoMock.GetLoose();
            m_baseFixture = baseFixture;
            m_autoMock.Mock<IFormattingLogger>().Setup(l => l.WithType(typeof(NameDemoEngine))).Returns(m_autoMock.Create<IFormattingLogger>());
            m_baseFixture.Tag = new TagData { EPC = "3615D09360159F9BB76EDED579D56C4DAB080000000000000000" };
             m_autoMock.Mock<IFormattingLogger>().Setup(m => m.WithType(It.IsAny<VilantBaseRfidEngine>()))
                .Returns(autoMock.Create<IFormattingLogger>());
            m_autoMock.Mock<IGpioService>().SetupGet(m => m.DefaultGpioDevice).Returns(new Mock<IGPIO>().Object);
            m_autoMock.Mock<ISettings>().Setup(m => m.GetSettingString(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns("");
            m_autoMock.Mock<IRFIDService>().SetupGet(m => m.DefaultRFIDManager).Returns(m_autoMock.Create<IRFIDManager>()); // ----> This is where the exception was thrown
            m_nameDemoEngine = m_autoMock.Create<NameDemoEngine>();
        }

And this was the interface:

 public interface IRFIDService
    {
        IRFIDManager DefaultRFIDManager { get; }
     }

And here is the registeration line in the DI container:

bld.RegisterType<RFIDManager>().As<IRFIDManager>();

Please fix this issue so that we can upgrade to the latest version of Autofac.Extras.Moq.

@kahaeia1 kahaeia1 changed the title Autofac.Core.Registration.ComponentNotRegisteredException for registered a component Autofac.Core.Registration.ComponentNotRegisteredException for a registered component Feb 4, 2019
@tillig
Copy link
Member

tillig commented Mar 25, 2019

Sorry for the delay in response here. Unfortunately, Autofac.Extras.Moq has relatively few users, all things considered, so isn't as high on the priority list for the project maintainers as bugs in core Autofac. Time is limited and we've been looking for help for a while with no takers.

If you need an immediate fix, your best answer will be to submit a PR with said fix. Otherwise, sorry, this may hang out here for a while.

One thing that may be helpful is to create a minimum reproduction. Looking at the "rough code" there are no interface definitions here, and I'm guessing that not all of that rough code is required to actually see the issue. The more time it takes us to create a repro, the less likely it'll be that attention goes to the issue. If there's already a repro in full with a unit test format such that we can grab the unit test and bring it in, that's a huge benefit.

@cmeyertons
Copy link

@tillig is there a mock library pairing with Autofac you would recommend that has more users than Autofac.Extras.Moq?

@tillig
Copy link
Member

tillig commented Sep 13, 2019

I have no recommendations. I personally avoid any sort of auto-mocking because it makes unit tests unclear (what's actually required?) and hides the fact that if a unit test actually has a really difficult setup with a lot of dependencies that it's a sign you should refactor (one of the big benefits of TDD).

@cmeyertons
Copy link

Yeah agree -- it's definitely nice when you're injecting a logger all over the place and don't really want to have to concern yourself w/ that in your unit tests.

on another note: was able to repro the issue in an xunit test in my fork -- it's pushed and available.

it seems to be a core issue w/ Autofac -- in the AnyConcreteTypeNotAlreadyRegisteredSource it requires all of the generic arguments to already be registered, which doesn't really make sense? this also limits the generic to reference types, which could be undesirable.

if (typeInfo.IsGenericType)
{
    foreach (var typeParameter in typeInfo.GenericTypeArguments)
    {
        // Issue #855: If the generic type argument doesn't match the filter don't look for a registration.
        if (_predicate(typeParameter) && !registrationAccessor(new TypedService(typeParameter)).Any())
        {
            return Enumerable.Empty<IComponentRegistration>();
        }
    }
}

the _predicate above is just => true so it's always going to look for a reg.

@tillig
Copy link
Member

tillig commented Sep 13, 2019

If you've found an issue in core Autofac, please file it there along with code to repro it. Thanks! https://github.com/autofac/Autofac/issues

@gnewtzie
Copy link

I was able to fix this for generics that have primitives as parameters by registering the types like this:
This was using Bogus but any way of generating a primitive would work.

        var mocker = AutoMock.GetLoose(t =>
        {
            t.Register(c =>
            {
                var f = new Faker("en").Random.Int();
                return f;
            });
            t.Register(c =>
            {
                var f = new Faker("en").Random.Long();
                return f;
            });
            t.Register(c =>
            {
                var f = new Faker("en").Random.Decimal();
                return f;
            });

            t.Register(c =>
            {
                var f = new Faker("en").Random.Double();
                return f;
            });
        });

@alistairjevans
Copy link
Member

This issue has been resolved in Autofac 5; the imminent release of the Moq integration will close this.

@alistairjevans
Copy link
Member

Closing as resolved in develop.

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

No branches or pull requests

5 participants