In this post, let's look at how we can use multiple output bindings with
HTTP-triggered Azure Functions running on the isolated worker model.
When working with HTTP-triggered functions, you often need to return an HTTP
response to the caller while also sending data to other services like Azure
Service Bus, Azure Queue Storage, etc. This is where multiple output bindings
come in handy.
HttpRequestData vs HttpRequest
With Azure Functions isolated worker model, by default we have HttpRequestData and HttpResponseData types from the Microsoft.Azure.Functions.Worker.Extensions.Http package.
However, we can also use ASP.NET Core integration via the Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore NuGet package. This enables using standard ASP.NET Core types
including HttpRequest, HttpResponse, and IActionResult in HTTP Triggers.
Let's see how multiple output bindings work with both approaches.
To have multiple outputs, we need to create a class that contains our output
binding properties.
Using HttpRequestData
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using System.Net;
namespace FunctionApp1;
public class HttpStartWithHttpRequestData
{
[Function(nameof(HttpStartWithHttpRequestData))]
public async Task<HttpStartOutputWithHttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
{
HttpResponseData response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteStringAsync("Message Sent");
return new HttpStartOutputWithHttpResponseData()
{
ServiceBusMessageContent = "Some Content",
HttpResponse = response
};
}
}
public class HttpStartOutputWithHttpResponseData
{
[ServiceBusOutput("sbt-test-topic", ServiceBusEntityType.Topic, Connection = "ServiceBusConnection")]
public string? ServiceBusMessageContent { get; set; }
public HttpResponseData HttpResponse { get; set; }
}
With HttpRequestData, the HttpResponseData property doesn't require any special attribute. The function runtime
automatically recognizes it as the HTTP response.
Note: The ServiceBusMessageContent property is nullable. If the value isn't set (i.e., it's null), no
message will be sent to the Service Bus. This allows you to conditionally send
messages based on your business logic.
Using HttpRequest (ASP.NET Core Integration)
When using HttpRequest from the ASP.NET Core integration, things are slightly different. We
need to use the [HttpResult] attribute to indicate which property is the HTTP response.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using System.Net;
namespace FunctionApp1;
public class HttpStartWithHttpRequest
{
[Function(nameof(HttpStartWithHttpRequest))]
public HttpStartOutputWithHttpResponse Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req)
{
return new HttpStartOutputWithHttpResponse()
{
ServiceBusMessageContent = "Some Content",
HttpResponse = new ObjectResult("Message Sent")
{
StatusCode = (int)HttpStatusCode.OK
}
};
}
}
public class HttpStartOutputWithHttpResponse
{
[ServiceBusOutput("sbt-test-topic", ServiceBusEntityType.Topic, Connection = "ServiceBusConnection")]
public string? ServiceBusMessageContent { get; set; }
[HttpResult]
public IActionResult HttpResponse { get; set; }
}
The [HttpResult] attribute is required here because without it, the runtime won't know
which property represents the HTTP response.
Note: Similar to the previous example, the ServiceBusMessageContent property is nullable. If the value isn't set, no message will be sent
to the Service Bus.
Limitations
There's a significant limitation when it comes to Service Bus output bindings
in the isolated worker model. The content type has to be the message body
itself - it can be a simple type (like string) or a complex type (a POCO).
You cannot use ServiceBusMessage from the Azure.Messaging.ServiceBus SDK as the output type. If
you try to do so, the entire ServiceBusMessage object gets serialized as JSON, resulting in something like this:
{
"Body": "eyJDb250ZW50IjoiU29tZSBDb250ZW50In0=",
"MessageId": null,
"PartitionKey": null,
"SessionId": null,
"TimeToLive": "10675199.02:48:05.4775807",
"CorrelationId": null,
"Subject": null,
"ContentType": null,
"ApplicationProperties": {}
}
This means you cannot set message properties like CorrelationId, SessionId, Subject, or ApplicationProperties using output bindings in the isolated worker model. If you need to set
these properties, you'll have to use the ServiceBusClient directly.
This is a known limitation and has been discussed in several GitHub issues:
Hope this helps.
Happy Coding.
Regards,
Jaliya