0

在我的 ASP.NET Core 3.1 Web 应用程序中,我允许用户上传存储在应用程序本身的本地目录中的图像。虽然,使用 Azure 上的 blob 存储可以更好地实现这一点,但这个特定项目要求将它们存储在本地,所以我必须使用它:

wwwroot/images/products/whatever_id/whatever_name.jpg

wwwroot/images/companies/whatever_id/whatever_name.jpg

当用户上传图像时,图像的处理由 SixLabors 的 ImageSharp 处理,其中图像被调整几次以供跨平台使用,并保存到由 Id 分隔的相对目录中。

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;

问题

我面临的问题是,虽然当我在本地测试我的应用程序时这个过程有效,但当我将我的应用程序部署到 Azure 并且没有报告任何类型的错误时它不起作用。当我试图弄清楚发生了什么时,这让我感到兴奋和干燥。

假设

由于这个问题的性质和这些图像的位置,我只能假设它是天蓝色的,出于安全原因防止覆盖目录中的图像,或者它可能是 ImageSharp 库本身。

重要的是要注意,当目录不存在时,实际创建产品和添加图像,因此,一个新产品可以完美地工作。只有当你试图覆盖它不起作用的图像时。

这是我的代码,我删除了所有非必要元素,留下了图像处理特定的代码。

编辑视图)

@model Products
<form asp-action="Edit" asp-controller="Products" method="POST" enctype="multipart/form-data">
    <div class="card m-4">
        <div class="card-header">
            <h3 class="card-title">Add Product</h3>
        </div>
        <div class="card-body">
            <div class="container-fluid">
                <div class="row">
                    <div class="col-md-4">
                        <div class="form-group">
                            <label>Product Images</label>                         
                            <kendo-upload name="ProductImages" multiple="true" show-file-list="true">
                            </kendo-upload>
                        </div>
                    </div>                        
                </div>              
                <div class="row">
                    <div class="col">
                        <button type="submit" class="btn btn-purple">Submit</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</form>

编辑(控制器)

[HttpPost]
public IActionResult Edit(Products product)
{
    if (ModelState.IsValid && product != null)
    {
        try
        {
            //Process the Images
            if (product.ProductImages != null)
            {
                ProcessImages(product, product.Id);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        return RedirectToAction("Index");
    }
    return View();
}

处理图像(流)

private readonly int[] sizeArray = new int[] { 700, 350, 150 };

public Stream ProcessImages(Products model, int? id)
{
    try
    {
        //Get the images and define the directory structure
        var images = model.ProductImages;
        var root = _env.WebRootPath;
        var folderName = Path.Combine(root, "images", "products", id.ToString());

        //If the ID Directory doesn't exist, create it first.
        if (!Directory.Exists(folderName))
        {
            Directory.CreateDirectory(folderName);
        }
        //Interate over the images and process them
        foreach (var item in images)
        {
            foreach (var imageSize in sizeArray)
            {
                string imageSizeName = "image" + imageSize + ".jpg";
                string fullPath = Path.Combine(folderName, imageSizeName);
                //Create the stream and process the image
                using FileStream fileStream = new FileStream(fullPath, FileMode.Create);

                try
                {
                    Stream inStream = item.OpenReadStream();
                    using Image image = Image.Load(inStream);
                    int width = imageSize;
                    int height = 0;
                    var clone = image.Clone(i => i.Resize(width, height));
                    clone.SaveAsJpeg(fileStream);
                    inStream.Position = 0;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
    }
    catch (Exception ex)
    {
       Console.WriteLine(ex.Message);
    }
    return (null);
}

如您所见,有一个大小数组,其中定义了我们需要的大小,然后循环处理。我们创建文件名并保存为 jpg。高度设置为 0,以便在定义宽度然后重置流时自动设置它。

Products.cs(模型)

    public class Products : BaseEntity
    {        
        public string Title { get; set; }

        [NotMapped]
        public IFormFileCollection ProductImages { get; set; }

    }

所以,问题仍然存在,为什么我的应用程序在 Azure 中运行后不能覆盖我的图像?是 Azure 安全问题,还是 ImageSharp 库问题之类的简单问题,还是我的应用程序没有正确执行此操作?

4

1 回答 1

1

该代码看起来不正确。在ProcessImages

  • 您正在加载图像,然后为每种尺寸克隆它(在循环外加载)
  • 将克隆保存到流后,您不会对其进行处理。
  • 你总是回来null

不过,关于缓存,@LazZiya 在这里是正确的。由于您再次重复使用相同的名称,浏览器将只请求相同的缓存图像。如果您在 eg 中添加任何查询字符串参数,您v=[PRODUCTRECORD_LASTWRITETIME]将获得新图像。

为简单起见,我建议您只需上传源图像并使用ImageSharp.Web中间件来提供调整大小的图像。

这将自动处理源图像更改并减少存储开销。您可以将源图像托管在服务器上,并将缓存结果托管在 Blob 存储中。

请求变得如此简单

https://PATH_TO_IMAGE?with=[NUMBER]

于 2021-02-26T13:48:13.730 回答