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

Integrating Simple Injector with MassTransit #621

Open
skollm opened this Issue Oct 10, 2018 · 7 comments

Comments

3 participants
@skollm

skollm commented Oct 10, 2018

I am running into an error 'Unable to resolve service for type 'MassTransit.IBusControl' while attempting to activate 'PCNDmzWeb.Api.Services.MassTransitHostedService'.'"

I am using the boilerplate code for MVC Core with a few minor changes. In the Configure services method i have the following:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    _container.RegisterInstance<IBusControl>(
        Bus.Factory.CreateUsingRabbitMq(sbc =>
        {
            var host = sbc.Host("localhost", "dev", h =>
            {
                h.Username("guest");
                h.Password("guest");
            });
            sbc.ReceiveEndpoint(host, "job_results_queue", e =>
            {
                e.Consumer<StoreJobResultsConsumer>();
            });
        }));
  
    services.AddScoped<IHostedService, MassTransitHostedService>();

    IntegrateSimpleInjector(services);
}

It does not appear that the instance of the BusControl is getting created.
The message seems to indicate that the error is occurring in the Microsoft Extensions Dependency Injection. What am I doing wrong?

at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Type serviceType, Type implementationType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, ISet`1 callSiteChain)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType, ServiceProvider serviceProvider)
at System.Collections.Concurrent.ConcurrentDictionaryExtensions.GetOrAdd[TKey,TValue,TArg](ConcurrentDictionary`2 dictionary, TKey key, Func`3 valueFactory, TArg arg)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Hosting.Internal.WebHost.<StartAsync>d__26.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Hosting.WebHostExtensions.<RunAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Hosting.WebHostExtensions.<RunAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Hosting.WebHostExtensions.Run(IWebHost host)
at PCNDmzWeb.Api.Program.Main(String[] args) in C:\myapp\PCNDmzWeb.Api\Program.cs:line 17
@dotnetjunkie

This comment has been minimized.

Collaborator

dotnetjunkie commented Oct 11, 2018

You seem to have registered the IBusControl in Simple Injector, while the built-in configuration system seems to be resolving it. It's unclear to me what you are trying to achieve, but it seems you need to register IBusControl in the IServiceCollection.

Did you follow our integration guide?

@skollm

This comment has been minimized.

skollm commented Oct 11, 2018

I have followed the integration guide. I have cut and pasted the MVC Core example .
I am attempting to set up MassTransit. They don't show any examples for simple injector. Here is their autofac example below. Their example shows configure services returning a IServiceProvider versus the void in the boiler plate code.
after doing the verify in the configure method it appears this registration is available. However as you noted the Core DI code is doing the resolution not Simple injector.

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();
    // Add the service class so that the runtime can automatically handle the start and stop of our bus.
    services.AddScoped<IHostedService, MassTransitHostedService>();

    var builder = new ContainerBuilder(); 

    builder.Register(c =>
    {
        return Bus.Factory.CreateUsingRabbitMq(sbc => 
            sbc.Host("localhost","dev", h =>
            {
                h.Username("guest");
                h.Password("guest");
            })
        );
    })
    .As<IBusControl>()
    .As<IPublishEndpoint>()
    .SingleInstance();
    builder.Populate(services);
    container = builder.Build();

    // Create the IServiceProvider based on the container.
    return new AutofacServiceProvider(container);
}
@dotnetjunkie

This comment has been minimized.

Collaborator

dotnetjunkie commented Oct 11, 2018

Integration of Simple Injector with ASP.NET Core is very different from the guidance that the Autofac team gives, since the Autofac team embraced ASP.NET Core's Conforming Container, which is something Simple Injector can't possibly conform to, due to severe incompatibilities between the .NET Core DI Abstraction and Simple Injector.

So instead, as the integration guide states, you keep ASP.NET Core registrations separate from registration of your application components. So typically, since MassTransit is used by your application code, you would register its components in Simple Injector. The only point you seem to integrate is adding an IHostedService to allow the bus to be started and stopped. This means registering a MassTransitHostedService into the service collection, and because it depends on IBusControl, this need to be registered as well.

I would therefore suggest the following registration:

var bus = Bus.Factory.CreateUsingRabbitMq(sbc => 
    sbc.Host("localhost","dev", h =>
    {
        h.Username("guest");
        h.Password("guest");
    })
);

// Simple Injector registrations (if needed)
container.RegisterInstance<IBusControl>(bus);
container.RegisterInstance<IPublishEndpoint>(bus);

// Core registrations
services.AddSingleton<IBusControl>(bus);
services.AddScoped<IHostedService, MassTransitHostedService>();

Or optionally, the core registrations can be minimized to the following:

// Core registrations
services.AddScoped<IHostedService>(c => new MassTransitHostedService(bus));

@dotnetjunkie dotnetjunkie changed the title from Unable to resolve service for type. to Integrating Simple Injector with MassTransit Oct 11, 2018

@phatboyg

This comment has been minimized.

phatboyg commented Oct 11, 2018

A pull request to update the documentation here would be most excellent!

@dotnetjunkie

This comment has been minimized.

Collaborator

dotnetjunkie commented Oct 12, 2018

@phatboyg I would love to send you a PR that improves the MassTransit documentation. Can you guide me on what page to alter or add and where the documentation repository is located?

@skollm

This comment has been minimized.

skollm commented Oct 12, 2018

Both suggestions below yield the same result
services.AddSingleton(bus);
services.AddScoped<IHostedService, MassTransitHostedService>();

and

services.AddScoped(c=> new MassTransitHostedService(bus));

System.InvalidOperationException: 'Cannot consume scoped service 'Microsoft.Extensions.Hosting.IHostedService' from singleton 'Microsoft.AspNetCore.Hosting.Internal.HostedServiceExecutor'.'

getting rid of simpleinjector entirely and running .Net Core DI is working. Our standard here is to use simpleinjector and we have not ventured into .Net Core yet. Looks like I should stick with .Net Core .

@skollm skollm closed this Oct 12, 2018

@dotnetjunkie

This comment has been minimized.

Collaborator

dotnetjunkie commented Oct 12, 2018

This is your initial code sample that is biting you in the rear. Change your scoped registration to a singleton:

services.AddSingleton<IHostedService, MassTransitHostedService>();

Seems that hosted services can't be scoped. The MassTransitHostedService implementation seems to be stateless, so I assume it can safely be registered as singleton.

Where did you get that registration example from? If it is copied from the MassTransit docs, @pathboyg might need to update his docs. ASP.NET Core clearly explains that initial registration is wrong.

@skollm skollm reopened this Oct 13, 2018

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