使用ImageResizer的Azure C#WebJob未正确设置内容类型

问题描述:

我正在使用Azure WebJob来调整新上载的图像的大小。调整大小的作品,但新创建的图像没有在Blob存储中正确设置其内容类型。相反,它们被列为application/octet-stream。这里处理调整大小的代码:使用ImageResizer的Azure C#WebJob未正确设置内容类型

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

我的问题是在哪里以及如何设置内容类型?这是我必须手动执行的操作,还是在我如何使用库时出现错误,以防止它分配与原始内容类型相同的内容类型(库说它应该显示的行为)?

谢谢!

最后更新

感谢托马斯,他在最后的解决方案帮助来到这里啊!

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; } 
} 
+0

我已经编辑我的职务 – Thomas

你不能从你的实现设定的内容类型:

您需要访问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文档:How to use Azure blob storage with the WebJobs SDK

的WebJobs SDK扫描日志文件来监视新的或改变的斑点。这个过程不是实时的;一个函数可能不会触发,直到blob创建后几分钟或更长时间。另外,还有storage logs are created on a "best efforts"的基础;不保证所有事件都将被捕获。在某些情况下,日志可能会丢失。如果blob触发器的速度和可靠性限制不适用于您的应用程序,则建议的方法是在创建blob时创建队列消息,并在处理blob的函数上使用QueueTrigger属性而不是BlobTrigger属性。

因此,可以更好地触发从队列中的消息,只是发送的文件名,你可以输入斑点自动绑定到消息队列:

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

谢谢托马斯,能够弄清楚如何使用自定义对象通配符来表示队列消息所需的信息来完成,我会用代码更新我的答案。 –