1

Desired Scenario

From an Arduino:

  • take a photo and upload image as a blob in Azure storage container (works fine)
  • call a Web Function using HTTP with blob name and other info (works fine) From the Web function
  • read the HTTP request (works fine)
  • read the blob using the information from the HTTP request (does not work)
  • process the blob (not implemented yet)
  • respond result to Arduino

Problem

I can't figure out how to make the binding from the path to the HTTP parameters.

Web Function Config

{
  "bindings": [
    {
      "authLevel": "function",
      "name": "request",
      "type": "httpTrigger",
      "direction": "in",
      "methods": [
        "post"
      ]
    },
    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    }
  ],
  "disabled": false
}

Error:

Function ($HttpTriggerCSharp1) Error: Microsoft.Azure.WebJobs.Host: Error indexing method 'Functions.HttpTriggerCSharp1'. Microsoft.Azure.WebJobs.Host: No binding parameter exists for 'blobName'.

ORIGINAL, NON-WORKING code (working code below):

using System.Net;

public static async Task<HttpResponseMessage> Run(
    HttpRequestMessage request, 
    string blobName,           // DOES NOT WORK but my best guess so far
    string inputBlob, 
    TraceWriter log)
{

// parse query parameter   
string msgType = request.GetQueryNameValuePairs()
    .FirstOrDefault(q => string.Compare(q.Key, "msgType", true) == 0)
    .Value;

// Get request body
dynamic data = await request.Content.ReadAsAsync<object>();

// Set name to query string or body data  
msgType = msgType ?? data?.msgType;

string deviceId = data.deviceId;
string blobName = data.BlobName; // DOES NOT COMPILE

log.Info("blobName=" + blobName); // DOES NOT WORK
log.Info("msgType=" + msgType); 
log.Info("data=" + data); 

return msgType == null
    ? request.CreateResponse(HttpStatusCode.BadRequest, "HTTP parameter must contain msgType=<type> on the query string or in the request body")
    : request.CreateResponse(HttpStatusCode.OK, "Hello " + deviceId + " inputBlob:");// + inputBlob );

}

HTTP request looks like this:

  https://xxxxxxprocessimagea.azurewebsites.net/api/HttpTriggerCSharp1?code=CjsO/EzhtUBMgRosqxxxxxxxxxxxxxxxxxxxxxxx0tBBqaiXNewn5A==&msgType=New image
   "deviceId": "ArduinoD1_001",
   "msgType": "New image",
   "MessageId": "12345",
   "UTC": "2017-01-08T10:45:09",
   "FullBlobName": "/xxxxxxcontainer/ArduinoD1_001/test.jpg",
   "BlobName": "test.jpg",
   "BlobSize": 9567,
   "WiFiconnects": 1,
   "ESPmemory": 7824,
   "Counter": 1

(I know, msgType appears both in URL and in headers. I've tried different combinations - no effect).

If what I'm trying to do is impossible, alternative suggestions are also welcome. I just need a way through.

This code works thanks to Tom Sun's hint. The trick was to remove the binding to the storage blob in the JSON and instead just call the blob directly from the code.

    #r "Microsoft.WindowsAzure.Storage"
    using Microsoft.WindowsAzure.Storage; // Namespace for CloudStorageAccount
    using Microsoft.WindowsAzure.Storage.Blob; // Namespace for Blob storage types
    using Microsoft.WindowsAzure.Storage.Queue;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Host;
    using System.Net;
    using System.IO;

    public static async Task<HttpResponseMessage> Run(HttpRequestMessage request, string inputBlob, TraceWriter log)
    {
        string msgType = request.GetQueryNameValuePairs()
            .FirstOrDefault(q => string.Compare(q.Key, "msgType", true) == 0)
            .Value;

        dynamic data = await request.Content.ReadAsAsync<object>();
        msgType = msgType ?? data?.msgType;

        string deviceId = data.deviceId;
        string blobName = data.BlobName;

        string connectionString = AmbientConnectionStringProvider.Instance.GetConnectionString(ConnectionStringNames.Storage);
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference("nnriothubcontainer/" + deviceId);
        CloudBlockBlob blob = container.GetBlockBlobReference(blobName);

        MemoryStream imageData = new MemoryStream();
        await blob.DownloadToStreamAsync(imageData);

        return msgType == null
            ? request.CreateResponse(HttpStatusCode.BadRequest, "HTTP parameter must contain msgType=<type> on the query string or in the request body")
            : request.CreateResponse(HttpStatusCode.OK, "Hello " + deviceId + " inputBlob size:" + imageData.Length);// + inputBlob );
    }
  • are you sure you can have 2 input actions? – 4c74356b41 Jan 08 '17 at 20:46
  • How does your url looks like ? Where do you specify the blobname: header, querystring ? – Thomas Jan 09 '17 at 07:45
  • this post can give you some clues :http://stackoverflow.com/questions/36953126/azure-function-resize-image-stored-in-a-blob-container – Thomas Jan 09 '17 at 07:49
  • Hi Thomas, It's possible to read a blob "simultaneously" with during an http request. (with the HTTP call being the trigger). I can do that with a fixed blob name. It's also possible to make the blobname dynamic based on bindings in the JSON. There are examples of assigning the variable to "triggerqueues". I suspect the problem is that it's an HTTP-request. A post from early 2016 claimed that it was only possible to make a binding to the whole request entity. They also said they had a solution - without explaining what to do. It was a pretty hairy thread, though, so I had to skip it. – Ratnick66DK Jan 09 '17 at 13:17

1 Answers1

1

take a photo and upload image as a blob in Azure storage container (works fine)

call a Web Function using HTTP with blob name and other info (works fine) From the Web function read the HTTP request (works fine)

Base on my understanding, you can read the Http info including blob uri ,blob name, and try to operate the storage blob in the Azure Http Trigger Function. If it is that case, we could try to refer to "Microsoft.WindowsAzure.Storage" and import namespaces. Then we could operate Azure storage with Azure storeage SDK. More detail info about how to operate storage blob please refer to document.

#r "Microsoft.WindowsAzure.Storage"
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
Tom Sun - MSFT
  • 24,161
  • 3
  • 30
  • 47
  • 1
    THANKS! It took a while to get it working, but in fact, it was very simple. Working code inserted in original question. – Ratnick66DK Jan 11 '17 at 16:29