Background
I'm trying to set up a Web API 2 which needs to communicate to a NServicebus Endpoint.
I will need to implement IoC, which will be done using Autofac.
What I have
A controller defined like so:
[RoutePrefix("api")]
public class Controller : ApiController
{
private IEndpointInstance EndpointInstance { get; set; }
public public MyController(IEndpointInstance endpointInstance)
{
this.EndpointInstance = endpointInstance;
}
[HttpGet]
[Route("dostuff")]
public async Task DoStuff()
{
var command = new MyCommand
{
...
};
await this.EndpointInstance.SendLocal(command);
}
}
And in global.asax
Application_Start
protected async void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
await RegisterNServiceBusWithAutofac();
}
RegisterNServiceBusWithAutofac
private async Task RegisterNServiceBusWithAutofac()
{
var builder = new ContainerBuilder();
var endpointConfiguration = await GetEndpointConfiguration("My.Service");
var endpointInstance = await Endpoint.Start(endpointConfiguration);
builder.RegisterInstance(endpointInstance);
var container = builder.Build();
endpointConfiguration.UseContainer<AutofacBuilder>(c => c.ExistingLifetimeScope(container));
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
}
GetEndpointConfiguration
private static async Task<EndpointConfiguration> GetEndpointConfiguration(string name)
{
var endpointConfiguration = new EndpointConfiguration(name);
// Set transport.
var routing = endpointConfiguration.UseTransport<MsmqTransport>().Routing();
// Register publish to self
routing.RegisterPublisher(typeof(EventHasFinished), name);
endpointConfiguration.UseSerialization<JsonSerializer>();
endpointConfiguration.UsePersistence<InMemoryPersistence>();
endpointConfiguration.SendFailedMessagesTo("error");
endpointConfiguration.EnableInstallers();
return endpointConfiguration;
}
The result
I get the following error on the UseContainer
line:
Unable to set the value for key: NServiceBus.AutofacBuilder+LifetimeScopeHolder. The settings has been locked for modifications. Move any configuration code earlier in the configuration pipeline
What I think this means
I think I need to do all Autofac registrations for the NServicebus when creating the endpointConfiguration
. The above manipulates the builder instance after that.
But
I can't do the above, because I need to register the endpointinstance
to the IoC, because I need that in my controller to send messages. And that doesn't exist yet, because I need the endpointConfiguration
first, for that.
So I have a chicken and egg situation ...
Question
Do I understand the issue correctly and how can I solve it while making sure that IoC works correctly for the Controller?
I.e.: this.EndpointInstance
has been correctly instantiated through IoC.
Instead of registering the actual instance, you could register it with a lambda expression that is going to be executed the first time the container will be asked to resolve IEndpointInstance
.
builder
.Register(x =>
{
var endpointConfiguration = GetEndpointConfiguration("My.Service").GetAwaiter().GetResult();
var endpointInstance = Endpoint.Start(endpointConfiguration).GetAwaiter().GetResult();
return endpointInstance
})
.As<IEndpointInstance>()
.SingleInstance();