public async static Task Run(
            [QueueTrigger("receiptitems", Connection = "AzureWebJobsStorage")] ReceiptQueueMessage receiptQueueItem,
            [Table("receiptsTable", Connection = "AzureWebJobsStorage")] CloudTable receiptsTable,
            [Queue("ocrqueue", Connection = "SmartServicesStorage")] ICollector <string> receiptOCRQueue,
            [Blob("incontainer/receipts", System.IO.FileAccess.Read, Connection = "AzureWebJobsStorage")] string receiptBlob,
            TraceWriter log)
        {
            log.Info($"Step is: {receiptQueueItem.ProcessingStep}");

            switch (receiptQueueItem.ProcessingStep)
            {
            case 0:     // processing
                log.Info($"Step 0 for item: {receiptQueueItem}");
                await CreateTableEntry(receiptQueueItem, receiptsTable);

                StartOCR(receiptQueueItem, receiptOCRQueue);
                break;

            case 1:     // complete
                log.Info($"Processing Complete for item: {receiptQueueItem}");
                UpdateTableStatus(receiptsTable, receiptQueueItem.Status, receiptQueueItem.ExpenseId);
                break;

            case 99:     // retrying
                log.Info($"Retrying Processing for item: {receiptQueueItem}");
                UpdateTableStatus(receiptsTable, "Retrying", receiptQueueItem.ExpenseId);
                StartOCR(receiptQueueItem, receiptOCRQueue);
                break;

            default:
                break;
            }
        }
        private static async Task CreateTableEntry(ReceiptQueueMessage receiptQueueItem, CloudTable receiptsTable)
        {
            // create table entry
            var item = new ReceiptTableItem()
            {
                PartitionKey = "key",
                RowKey       = receiptQueueItem.ExpenseId,
                ExpenseId    = receiptQueueItem.ExpenseId,
                UserId       = receiptQueueItem.UserId,
                Status       = "Processing"
            };

            var operation = TableOperation.Insert(item);
            await receiptsTable.ExecuteAsync(operation);
        }
        private static void StartOCR(ReceiptQueueMessage receiptQueueItem, ICollector <string> receiptOCRQueue)
        {
            // add message to OCR queue
            var    OCRCallbackKey      = ConfigurationManager.AppSettings["OCRCallbackKey"];
            var    baseCallbackAddress = ConfigurationManager.AppSettings["BaseCallbackAddress"];
            string imageUrl            = string.Empty;

            if (TryGetBlobLink(receiptQueueItem, out imageUrl))
            {
                var message = new OCRQueueMessage()
                {
                    ItemId   = receiptQueueItem.ExpenseId,
                    ItemType = "receipt",
                    ImageUrl = imageUrl,
                    Callback = $"{baseCallbackAddress}/ocrCallback?code={OCRCallbackKey}"
                };

                receiptOCRQueue.Add(JsonConvert.SerializeObject(message));
            }
        }
        private static bool TryGetBlobLink(ReceiptQueueMessage receiptQueueItem, out string imageUrl)
        {
            var storageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["AzureWebJobsStorage"]);
            var blobClient     = storageAccount.CreateCloudBlobClient();
            var blobContainer  = blobClient.GetContainerReference("receipts");

            imageUrl = string.Empty;

            if (blobContainer.Exists())
            {
                var blob = blobContainer.GetBlockBlobReference(receiptQueueItem.ExpenseId);

                SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
                sasConstraints.SharedAccessStartTime  = DateTime.UtcNow.AddMinutes(-5);
                sasConstraints.SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24);
                sasConstraints.Permissions            = SharedAccessBlobPermissions.Read;

                string sasBlobToken = blob.GetSharedAccessSignature(sasConstraints);

                imageUrl = blob.Uri + sasBlobToken;
            }

            return(!string.IsNullOrEmpty(imageUrl));
        }