Hi, I’m trying to use an instance of a function endpoint in 2 different classes, however within the scope of one azure function - it seems it’s not possible. I’m getting The transport is already started
exception.
Here’s the code. The ProductFunction
class contains Run
method (azure function) that sends a command. This works. If I add another dependency IContextPublisher
using IFunctionEndpoint
and call Publish
method on it that publishes an event, the event is sent but then the Send
method in the Run
method fails with The transport is already started
exception.
public class ProductFunction
{
private readonly IFunctionEndpoint functionEndpoint;
private readonly IContextPublisher contextPublisher;
public OnboardUserFunction(
IFunctionEndpoint functionEndpoint,
IContextPublisher contextPublisher)
{
this.functionEndpoint = functionEndpoint;
this.contextPublisher = contextPublisher;
}
[FunctionName("AddProduct")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequest request,
ExecutionContext executionContext,
ILogger logger)
{
this.contextPublisher.Publish(); // works (it uses the first IFunctionEndpoint instance)
await this.functionEndpoint.Send(commandMessage, executionContext, logger); // throws the exception (it uses the second IFunctionEndpoint instance)
}
}
public class ContextPublisher : IContextPublisher
{
private readonly IFunctionEndpoint functionEndpoint;
public ContextPublisher(IFunctionEndpoint functionEndpoint)
{
this.functionEndpoint = functionEndpoint;
}
public async Task Publish() {
await this.functionEndpoint.Publish(eventMessage, null); // executionContext is null, but it doesn't work with the valid context either - is it required?
}
}
I found out that it’s because UseNServiceBus
method registers IFunctionEndpoint
as factory method:
// for backward compatibility
functionsHostBuilder.Services.AddSingleton(endpointFactory);
functionsHostBuilder.Services.AddSingleton<IFunctionEndpoint>(sp => sp.GetRequiredService<FunctionEndpoint>());
That means every class that depends on IFunctionEndpoint
gets a new instance of the function endpoint. The problem is that only the first instance works.
It creates the pipeline if the pipeline is null. In my case 2 function endpoints instances are created. Both have null
pipeline at the beginning. When the first endpoint publishes the event, the pipeline is created and the event sent. When the second endpoint sends the command, the pipeline is also created but perhaps it shares the transport receiver with the first one and so it fails with The transport is already started
. The TransportReceiver
:
public Task Start()
{
if (isStarted)
{
throw new InvalidOperationException("The transport is already started");
}
...
Why the factory is used for the function endpoints and there isn’t only one registered? I would expect one per azure function (registered as scope). Now it behaves as a transient dependency.
If the IFunctionEndpoint
instances are different, why it then shares the transport receiver?
How I can inject the same instance of IFunctionEndpoint to classes so I can use more classes sending/publishing messages within a scope of one Azure Function?