Azure C# WebJob使用ImageResizer时未正确设置Content-Type

3

我正在开发一个Azure WebJob用于调整新上传的图像大小。调整大小是成功的,但是在Blob存储中,新创建的图像没有正确设置其内容类型。相反,它们被列为application/octet-stream。这里是处理调整大小的代码:

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

我的问题是在哪里以及如何设置内容类型?这是我需要手动完成的操作还是我使用的库中存在错误,导致其不能分配与原始内容相同的内容类型(库所说应该表现出的行为)?
谢谢!
最终更新
感谢Thomas的帮助,我们找到了最终的解决方案,下面是它!
public class Functions
{
    // output blolb sizes
    private static readonly int[] Sizes = { 800, 500, 250 };

    public static void ResizeImagesTask(
        [QueueTrigger("assetimage")] AssetImage asset,
        string container,
        string name,
        string ext,
        [Blob("{container}/{name}_master.{ext}", FileAccess.Read)] Stream blobStream,
        [Blob("{container}")] CloudBlobContainer cloudContainer)
    {

        // Get the mime type to set the content type
        var mimeType = MimeMapping.GetMimeMapping($"{name}_master.{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 = cloudContainer.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();
    }

    public static void PoisonErrorHandler([QueueTrigger("webjobs-blogtrigger-poison")] BlobTriggerPosionMessage message, TextWriter log)
    {
        log.Write("This blob couldn't be processed by the original function: " + message.BlobName);
    }
}

public class AssetImage
{
    public string Container { get; set; }

    public string Name { get; set; }

    public string Ext { get; set; }
}

public class BlobTriggerPosionMessage
{
    public string FunctionId { get; set; }
    public string BlobType { get; set; }
    public string ContainerName { get; set; }
    public string BlobName { get; set; }
    public string ETag { get; set; }
}
1个回答

4

您无法从实现中设置内容类型:

您需要访问CloudBlockBlob.Properties.ContentType属性:

CloudBlockBlob blob = new CloudBlockBlob(...);
blob.Properties.ContentType = "image/...";
blob.SetProperties();

Azure Webjob SDK支持Blob绑定,因此您可以直接将其绑定到Blob。在您的情况下,您希望绑定到一个输入Blob并创建多个输出Blob。使用BlobTriggerAttribute来作为输入。使用BlobTriggerAttribute来绑定到您的输出Blob。因为您想创建多个输出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();
    }
}

请注意在ImageJob对象上使用DisposeSourceObject,以便我们可以多次读取Blob流。
此外,您应该查看有关BlobTrigger的Webjob文档:如何使用WebJobs SDK与Azure Blob存储 WebJobs SDK扫描日志文件以监视新创建或更改的Blob。这个过程不是实时的;一个函数可能要几分钟甚至更长时间才能被触发。此外,存储日志是基于“尽力而为”的原则创建的;不能保证捕获所有事件。在某些情况下,可能会错过日志。如果Blob触发器的速度和可靠性限制对您的应用程序不可接受,则推荐的方法是在创建Blob时创建队列消息,并在处理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();
    }
}

谢谢Thomas,我已经能够通过使用自定义对象来通配符匹配队列消息中所需的信息,以便完成操作。我会更新我的答案并附上代码。 - Brian Bolli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接