I'm trying to write a function which will received a HTTP POST request, read some data, and write that data to a ServiceBus queue. Here's the code I have:
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.Azure.Functions.Worker;
namespace foo
{
public static class foo
{
[FunctionName(nameof(bar))]
[ServiceBusOutput("myBus", Connection = "ServiceBusConnection")]
public static async Task<IActionResult> bar(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req,
ILogger log)
{
log.LogInformation("processed a request.");
string tld;
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
Models.foo data = JsonConvert.DeserializeObject<Models.foo>(requestBody);
theThing = data.Name ?? "";
if (string.IsNullOrEmpty(theThing))
{
log.LogError("No data passed to function. Aborting");
throw new Exception("a message");
}
return new OkObjectResult(theThing);
}
}
}
My local.settings.json contains the following line:
"ServiceBusConnection__fullyQualifiedNamespace": "myfunctionnamespace.servicebus.windows.net",
I also have this value configured in the Function App application settings and have granted the function data reader and sender privileges via IAM.
I run this in debug from Visual Studio, which gives me a local URL to hit. I can post to this from PostMan, see data getting extracted and the function returns without error. I can also see requests going to the queue, but no messages are written.
I've tried various code changes from different SO posts, none of which have made any difference.
I have the following packages from NuGet installed:
My function.json file looks like this, which I think is wrong?
{
"generatedBy": "Microsoft.NET.Sdk.Functions.Generator-4.2.0",
"configurationSource": "attributes",
"bindings": [
{
"type": "httpTrigger",
"methods": [
"post"
],
"authLevel": "function",
"name": "req"
}
],
"disabled": false,
"scriptFile": "../bin/foo.dll",
"entryPoint": "foo.foo.bar"
}
What am I doing wrong?
The returned value is the HTTP response object. It shouldn't be used to return the message. The message should be enqueued using an output binding on IAsyncCollector
. Here's how it would look like.
[FunctionName(nameof(bar))]
public static async Task<IActionResult> bar(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequest req,
[ServiceBus("%OutputQueue%")] IAsyncCollector<ServiceBusMessage> output,
ILogger log)
{
log.LogInformation("processed a request.");
string tld;
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
Models.foo data = JsonConvert.DeserializeObject<Models.foo>(requestBody);
theThing = data.Name ?? "";
if (string.IsNullOrEmpty(theThing))
{
log.LogError("No data passed to function. Aborting");
throw new Exception("a message");
}
// Enqueue the message
await output.AddAsync(new ServiceBusMessage(theThing);
// Return HTTP response, not the message
return new OkResult();
}