Search code examples
azure-functionsazure-servicebus-queues

Write message to service bus from HTTP triggered function


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:

  • Microsoft.Azure.Functions.Worker.Extensions.ServiceBus (5.14.1)
  • Microsoft.Azure.WebJobs.Extensions.ServiceBus (5.13.4)
  • Microsoft.NET.Sdk.Functions (4.2.0)

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?


Solution

  • 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();
    }