Before going into details, have you considered using the Generic Host with the corresponding NServiceBus package instead of using the EndpointWithExternallyManagedServiceProvider API directly? The Generic Host integration is typically much easier to use and in this case, also handles the logging integration with the logger configured on the host. See NServiceBus.Extensions.Hosting • Particular Docs for more details. I’d definitely recommend to use the generic host integration instead of EndpointWithExternallyManagedServiceProvider in almost all cases.
Is there a way, to run the configuration (UseNServiceBus) and let NSB scan for handlers, but not start the actual endpoint? It is in our test suite, where I do not have RabbitMQ, but still want to get a MessageHandler from the IOC container.
We are using AspNetCore WebApplicationFactory for testing
Plain simple, we do a lot of accept test and is testing with the database. So often I like to get a service (read MessageHandler) from the IOC container and process a message into (with a TestableMessageSession). I assert what happens to the database.
Before when using EndpointWithExternallyManagedServiceProvider the NSB configuration (and MessageHandler scanning) was separated from the actually endpoint start up, hence the IOC container was populated with the MessageHandlers. The test suite was configured not to start the endpoint.
Now with UseNServiceBus the startup is not handled in my code, so the test suite with fail with missing RabbitMQ server.
Is there a way, to run the configuration (UseNServiceBus) and let NSB scan for handlers, but not start the actual endpoint?
Yes, you can build the generic host without starting it and it will provide you a IServiceProvider that can resolve message handlers without the endpoint being started:
Is your primary need for this the ability to scan the message handler and be able to resolve them from the DI container or are there other functionalities that your test relies on? It might be easier to handle the scanning and handler registration separately if that’s all you need.
Also, since you mentioned acceptance tests, have you considered running your endpoint with the learning transport instead and fully starting it, so that you get more actual behavior of the endpoint (like executing the full message handling pipeline)?
learning transport, might be handy later, but actually the handlers are very primitive and does not send messages. Also tests are run in parallel, could be fixed with different learning transport configurations.
.Start() does a lot important stuff like running EF migrations and start HTTP endpoints, so this is nice to execute from test suite, and WebApplicationFactory ( Microsoft.AspNetCore.Mvc.Testing ) does it implicit.
Actually I would also like the production start up to not fail if RabbitMQ is down. As it is now (again with UseNServiceBus) my Windows Service will fail on start up if RMQ is down. Before with EndpointWithExternallyManagedServiceProvider my service started gracefully and retries (Polly) would eventually connect
As I wrote Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory will always start your builder (since it runs your Program.cs).
So actually it is not possible to not start NSB when using UseNServiceBus. Only alternative is to check environment (e.g. Development) and add learning tranpost instead, right? I don’t put test code in my production code, so what to do then?
So actually it is not possible to not start NSB when using UseNServiceBus. Only alternative is to check environment (e.g. Development) and add learning tranpost instead, right? I don’t put test code in my production code, so what to do then?
My comment regarding just using Build was based on your described need to only resolve handlers from the DI container to invoke them manually, which would be possible with that. If you want to start the endpoint normally, then the generic host needs to be started, yes.
I think it might be easiest to just “copy” the endpoint configuration (or extract it into a shared class/method) and then overwrite the transport settings with the learning transport in the acceptance test-specific UseNserviceBus configuration.
The host is really just a host and not an existential part of your application logic, so it should be ok to use a different host for your testing needs.
learning transport, might be handy later, but actually the handlers are very primitive and does not send messages. Also tests are run in parallel, could be fixed with different learning transport configurations.
If you just want to test your fairly simple handlers, I think it would be a lot easier to just go with “unit tests” (the name might be misleading). Creating the instances, managing the dependencies etc. for testing purpose will be more straight forward (see Testing NServiceBus • Testing • Particular Docs). If your goal is to run with acceptance or integration tests, the NServiceBus endpoint should be fully started and handlers should be invoked by sending the message via the transport.
We currently don’t have an out-of-the-box solution for this when using the WebApplicationFactory as NServiceBus can’t be configured directly via IConfiguration APIs yet. So you’d have to support switching transports in your actually application via config or compilation flags and then use the WebApplicationFactory configuration options to switch the configuration.