Триггер BLOB-объектов Azure WebJobs - изменение размера нескольких объектов

Я пытаюсь создать C # Azure WebJob, которое запускается при создании нового BLOB-объекта, чтобы изменить размер загруженного изображения до трех разных размеров. Я нашел и следил за этим замечательным учебник.

Есть два раздела, первая часть «работает», но входит в цикл рекурсии, поскольку создание трех новых размеров запускает скрипт, который создает еще три экземпляра для каждого из трех новых изображений и т. Д., И т. Д. Это было сделано намеренно, чтобы подчеркнуть необходимость окончательной реализации.

Вот исходный код цикла рекурсии, который "работает" в файле Functions.cs:

public static void ResizeImagesW800([BlobTrigger("input/{name}.{ext}")] Stream input,
    [Blob("output/{name}-w800.{ext}", FileAccess.Write)] Stream output)
{
    ResizeImage(input, output, 800);
}

public static void ResizeImagesW500([BlobTrigger("input/{name}.{ext}")] Stream input,
    [Blob("output/{name}-w500.{ext}", FileAccess.Write)] Stream output)
{
    ResizeImage(input, output, 500);
}

private static void ResizeImage(Stream input, Stream output, int width)
{
    var instructions = new Instructions
    {
        Width = width,
        Mode = FitMode.Carve,
        Scale = ScaleMode.Both
    };
    ImageBuilder.Current.Build(new ImageJob(input, output, instructions));
}

Вот код, в котором Visual Studio 2015 выдает ошибку:

public static void ResizeImagesTask(
    [BlobTrigger("input/{name}.{ext}")] Stream inputBlob,
    string name,
    string ext,
    IBinder binder)
{
    int[] sizes = { 800, 500, 250 };
    var inputBytes = inputBlob.CopyToBytes();
    foreach (var width in sizes)
    {
        var input = new MemoryStream(inputBytes);
        var output = binder.Bind<Stream>(new BlobAttribute($"output/{name}-w{width}.{ext}", FileAccess.Write));

        ResizeImage(input, output, width);
    }
}

private static void ResizeImage(Stream input, Stream output, int width)
{
    var instructions = new Instructions
    {
        Width = width,
        Mode = FitMode.Carve,
        Scale = ScaleMode.Both
    };
    ImageBuilder.Current.Build(new ImageJob(input, output, instructions));
}

Ошибка возникает в этой строке:

 var inputBytes = inputBlob.CopyToBytes();

Ошибка:

CS1061: 'Stream' does not contain a definition for 'CopyToBytes' and no extension method 'CopyToBytes' accepting a first argument of type 'Stream' could be found (are you missing a using directive or an assembly reference?)

Я пробовал использовать .NET 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1 в качестве целевых фреймворков, но все они выдают одну и ту же ошибку.

Кроме того, вот операторы using для файла Functions.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.WindowsAzure.Storage;
using ImageResizer;

Что я здесь делаю не так? Спасибо!

ОБНОВЛЕНИЕ 1

using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.WindowsAzure.Storage;
using ImageResizer;
using ImageResizer.ExtensionMethods;
using Microsoft.WindowsAzure.Storage.Blob;

namespace HilcoIndustrialAssetApiWebJob
{
    public class Functions
    {
        // output blolb sizes
        private static readonly int[] Sizes = { 800, 500, 250 };

        public static void ResizeImagesTask(
        [QueueTrigger("newfileuploaded")] string filename,
        [Blob("input/{queueTrigger}", FileAccess.Read)] Stream blobStream,
        [Blob("output")] CloudBlobContainer container)
        {
            // Extract the filename  and the file extension
            var name = Path.GetFileNameWithoutExtension(filename);
            var ext = Path.GetExtension(filename);

            Console.WriteLine("New Blob name -> " + name);

            // Get the mime type to set the content type
            var mimeType = MimeMapping.GetMimeMapping(filename);

            foreach (var width in Sizes)
            {
                // Set the position of the input stream to the beginning.
                blobStream.Seek(0, SeekOrigin.Begin);

                // Get the output stream
                var outputStream = new MemoryStream();
                ResizeImage(blobStream, outputStream, width);

                // Get the blob reference
                var blob = container.GetBlockBlobReference($"{name}_{width}.{ext}");

                // Set the position of the output stream to the beginning.
                outputStream.Seek(0, SeekOrigin.Begin);
                blob.UploadFromStream(outputStream);

                // Update the content type =>  don't know if required
                blob.Properties.ContentType = mimeType;
                blob.SetProperties();
            }
        }

        private static void ResizeImage(Stream input, Stream output, int width)
        {
            var instructions = new Instructions
            {
                Width = width,
                Mode = FitMode.Carve,
                Scale = ScaleMode.Both
            };
            var imageJob = new ImageJob(input, output, instructions);

            // Do not dispose the source object
            imageJob.DisposeSourceObject = false;
            imageJob.Build();
        }
    }
}

person Brian Bolli    schedule 26.04.2016    source источник
comment
Вы видели этот пост stackoverflow.com/questions/7238018/?   -  person Thomas    schedule 26.04.2016
comment
Брайан, я отредактировал ваш вопрос, чтобы добавить тег в хранилище Azure blob.   -  person Thomas    schedule 27.04.2016
comment
Брайан, не хотите ли вы переименовать заголовок своего сообщения на что-то вроде этого: Azure WebJobs Blob Trigger - несколько изменений размера?   -  person Thomas    schedule 27.04.2016
comment
@Thomas, я написал еще один вопрос специально для этого, но изменил заголовок как предполагалось   -  person Brian Bolli    schedule 27.04.2016


Ответы (3)


Я предполагаю, что в образце используется пакет ImageResizer NuGet. Вы можете установить его из VS2015 с помощью команды Install-Package ImageResizer. Затем, если вы добавите using ImageResizer.ExtensionMethods; в вашем коде вы получите метод CopyToBytes, расширяющий объект Stream. Надеюсь, это поможет С уважением, Стефан

person stephgou    schedule 26.04.2016
comment
спасибо, что действительно избавились от ошибки. Хотя код теперь компилируется и может быть опубликован в Azure, при срабатывании триггера возникает ошибка. Обновил мой вопрос с файлом журнала, есть предложения? Еще раз спасибо за быстрое решение! - person Brian Bolli; 26.04.2016

Пакет SDK для веб-задания Azure поддерживает привязку больших двоичных объектов, поэтому вы можете выполнять привязку напрямую к большому двоичному объекту.

В вашем контексте вы хотите выполнить привязку к входному BLOB-объекту и создать несколько выходных BLOB-объектов.

  • Используйте BlobTriggerAttribute для ввода.
  • Используйте BlobTriggerAttribute для привязки к выходным BLOB-объектам. Поскольку вы хотите создать несколько больших двоичных объектов вывода, вы можете выполнить привязку непосредственно к контейнеру вывода.

Код вашей запущенной функции может выглядеть так:

using System.IO;
using System.Web;
using ImageResizer;
using Microsoft.Azure.WebJobs;
using Microsoft.WindowsAzure.Storage.Blob;

public class Functions
{
    // output blolb sizes
    private static readonly int[] Sizes = {800, 500, 250};

    public static void ResizeImage(
        [BlobTrigger("input/{name}.{ext}")] Stream blobStream, string name, string ext
        , [Blob("output")] CloudBlobContainer container)
    {
        // Get the mime type to set the content type
        var mimeType = MimeMapping.GetMimeMapping($"{name}.{ext}");
        foreach (var width in Sizes)
        {
            // Set the position of the input stream to the beginning.
            blobStream.Seek(0, SeekOrigin.Begin);

            // Get the output stream
            var outputStream = new MemoryStream();
            ResizeImage(blobStream, outputStream, width);

            // Get the blob reference
            var blob = container.GetBlockBlobReference($"{name}-w{width}.{ext}");

            // Set the position of the output stream to the beginning.
            outputStream.Seek(0, SeekOrigin.Begin);
            blob.UploadFromStream(outputStream);

            // Update the content type
            blob.Properties.ContentType = mimeType;
            blob.SetProperties();
        }
    }

    private static void ResizeImage(Stream input, Stream output, int width)
    {
        var instructions = new Instructions
        {
            Width = width,
            Mode = FitMode.Carve,
            Scale = ScaleMode.Both
        };
        var imageJob = new ImageJob(input, output, instructions);

        // Do not dispose the source object
        imageJob.DisposeSourceObject = false;
        imageJob.Build();
    }
}

Обратите внимание на использование DisposeSourceObject в объекте ImageJob, чтобы мы могли многократно читать поток больших двоичных объектов.

Кроме того, вам следует ознакомиться с документацией Webjob о BlobTrigger: Как использовать хранилище BLOB-объектов Azure с SDK WebJobs

Пакет SDK для веб-заданий сканирует файлы журналов на наличие новых или измененных BLOB-объектов. Этот процесс не происходит в реальном времени; функция может сработать только через несколько минут или дольше после создания большого двоичного объекта. Кроме того, журналы хранилища создаются на основе «максимальных усилий»; нет гарантии, что все события будут записаны. В некоторых случаях журналы могут отсутствовать. Если ограничения скорости и надежности триггеров больших двоичных объектов неприемлемы для вашего приложения, рекомендуется создать сообщение очереди при создании большого двоичного объекта и использовать атрибут QueueTrigger вместо атрибута BlobTrigger в функции, обрабатывающей большой двоичный объект. .

Таким образом, было бы лучше запускать сообщение из очереди, которая просто отправляет имя файла, вы можете автоматически привязать входной BLOB-объект к очереди сообщений:

using System.IO;
using System.Web;
using ImageResizer;
using Microsoft.Azure.WebJobs;
using Microsoft.WindowsAzure.Storage.Blob;

public class Functions
{
    // output blolb sizes
    private static readonly int[] Sizes = { 800, 500, 250 };

    public static void ResizeImagesTask1(
        [QueueTrigger("newfileuploaded")] string filename,
        [Blob("input/{queueTrigger}", FileAccess.Read)] Stream blobStream,
        [Blob("output")] CloudBlobContainer container)
    {
        // Extract the filename  and the file extension
        var name = Path.GetFileNameWithoutExtension(filename);
        var ext = Path.GetExtension(filename);

        // Get the mime type to set the content type
        var mimeType = MimeMapping.GetMimeMapping(filename);

        foreach (var width in Sizes)
        {
            // Set the position of the input stream to the beginning.
            blobStream.Seek(0, SeekOrigin.Begin);

            // Get the output stream
            var outputStream = new MemoryStream();
            ResizeImage(blobStream, outputStream, width);

            // Get the blob reference
            var blob = container.GetBlockBlobReference($"{name}-w{width}.{ext}");

            // Set the position of the output stream to the beginning.
            outputStream.Seek(0, SeekOrigin.Begin);
            blob.UploadFromStream(outputStream);

            // Update the content type =>  don't know if required
            blob.Properties.ContentType = mimeType;
            blob.SetProperties();
        }
    }

    private static void ResizeImage(Stream input, Stream output, int width)
    {
        var instructions = new Instructions
        {
            Width = width,
            Mode = FitMode.Carve,
            Scale = ScaleMode.Both
        };
        var imageJob = new ImageJob(input, output, instructions);

        // Do not dispose the source object
        imageJob.DisposeSourceObject = false;
        imageJob.Build();
    }
}
person Thomas    schedule 26.04.2016
comment
Ух ты, Томас, спасибо за очевидно хорошо продуманный и осознанный ответ. Я просматриваю сейчас и скоро вернусь! - person Brian Bolli; 27.04.2016
comment
Поскольку вы предложили лол. Я предполагаю, что вы использовали пакет NuGet или .NET для класса MimeMapping, или я делаю что-то еще не так, чтобы получить ошибку ole «не существует в этом контексте»? - person Brian Bolli; 27.04.2016
comment
Вам необходимо добавить ссылку на библиотеку system.web - person Thomas; 27.04.2016
comment
хммм, я добавил using System.Web в начало, но все еще получаю ошибку. Однако C # не самый сильный для меня язык, так что это может быть что-то базовое. Я вставил код функционального класса, который у меня есть, в редактирование на случай, если что-то еще мне не хватает. - person Brian Bolli; 27.04.2016
comment
см. эту статью, чтобы добавить ссылку msdn.microsoft.com/en-us/library /wkze6zky.aspx. Даже если пространство имен system.web известно, вам все равно нужна ссылка на библиотеку system.web, потому что она содержит больше классов. - person Thomas; 27.04.2016
comment
Хорошо, вот и все. Я опубликовал и протестировал, но похоже, что триггер не сработал, что вполне ожидаемо, учитывая, что я не добавил ничего для создания сообщения очереди при загрузке нового Blob. Уже 8 часов вечера в США, так что звоню сегодня вечером и заберу снова завтра утром. Еще раз спасибо за вашу помощь! - person Brian Bolli; 27.04.2016
comment
Меня смущает соглашение об именах, используемое с QueueTrigger, newfileuploaded. Я предполагаю, что это был произвольный выбор, но как мне тогда создать сообщение очереди при новой загрузке большого двоичного объекта? Я не могу использовать blobTrigger для создания сообщения очереди, потому что это вновь вводит исходную проблему отложенных и ненадежных триггеров больших двоичных объектов ... или я что-то упустил? - person Brian Bolli; 27.04.2016
comment
Я считаю, что разобрался с проблемой QueueTrigger, теперь у меня новая проблема. Собираюсь создать еще один вопрос для этого, однако оригинал был изменен. Кроме того, не могли бы вы опубликовать свой ответ на вопрос, который я разместил специально для изменения размера? Я хочу отдать вам должное, но этот вопрос изначально был для чего-то еще, на что другой пользователь ответил. Было бы несправедливо получить его награду :), спасибо! - person Brian Bolli; 27.04.2016
comment
а вот ссылка - ›stackoverflow.com/questions/36874081/ - person Brian Bolli; 27.04.2016

Я создал проект Webjob с VS2015 (все еще в update1), я использую Azure 2.8 SDK (скоро обновлю его до 2.9).

Я вырезал и вставил образец кода из вашей исходной ссылки. Я добавил две строки подключения конфигурации приложения (и обновил соответствующие строки подключения веб-приложения в параметрах приложения). Я только что добавил упомянутый пакет самородков и недостающее слово using. Работает нормально.

Я опубликовал образец кода на GitHub на случай, если вы захотите его попробовать.

https://github.com/stephgou/ImageResizer.git

Вам просто нужно обновить конфигурацию приложения и строки подключения вашего веб-приложения.

Надеюсь это поможет

С уважением, Стефан

person stephgou    schedule 27.04.2016