首页 > 解决方案 > 为 asp.net mvc 应用程序处理 Stream 对象的问题?

问题描述

我有具有文件上传功能的 asp.net mvc 应用程序。在上传文件时,我在将上传的内容移动到数据库和文件系统位置之前对其进行了一些验证。

这是我的代码:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddImage([Bind(Include = "image,ImageName,ImageType,CountryId,Keyword,Source,Copyright,Description")] CreateImageViewModel model)
{
    if (!this.ModelState.IsValid)
    {
        return View("Images");
    }

    if (model != null && model.image.ContentType.Contains(Constants.Image) && !ValidateUploadedImageContent(model.image, model.image.FileName))
    {
        var dto = new ImageDTO();
        model.FilePath = model.image.FileName;
        dto.ImageFile = model.image;
        dto.Name = model.ImageName;
        dto.FilePath = model.image.FileName;
        dto.FileType = Path.GetExtension(model.FilePath);
        dto.ImageType = model.ImageType;
        dto.CountryId = model.CountryId;
        dto.Keyword = model.Keyword;
        dto.Source = model.Source;
        dto.Copyright = model.Copyright;
        dto.Description = model.Description;
        dto.CreatedBy = UserDto.emailId;
        try
        {
            _imageService.SaveImage(dto);
        }
        catch (Exception ex)
        {
            if (ex.Message.Equals(Constants.InvalidImageType))
                return GetSafeRedirect(Url.Action("AddImage", model) + "#onload-errors");
            throw ex;
        }

        return RedirectToAction(Constants.Actions.Images.ToString());
    }
    else
    {
        return GetSafeRedirect(Url.Action("AddImage", model) + "#onload-errors");
    }
}

private bool ValidateUploadedImageContent(HttpPostedFileBase uploadedFile, string imageFileName)
{
    if (Path.GetExtension(imageFileName).Equals(".svg", StringComparison.OrdinalIgnoreCase))
    {
        if (uploadedFile.ContentLength > 0)
        {
            byte[] data;
            //using (Stream inputStream = uploadedFile.InputStream)
            //{
            Stream inputStream = uploadedFile.InputStream;
            var memoryStream = inputStream as MemoryStream;
            if (memoryStream == null)
            {
                memoryStream = new MemoryStream();
                inputStream.CopyTo(memoryStream);
            }

            data = memoryStream.ToArray();
            //}
            var parsedData = Encoding.UTF8.GetString(data, 0, data.Length).TrimEnd('\0');
            var result = parsedData.ContainsAny(Constants.InsecureStrings, StringComparison.CurrentCultureIgnoreCase);
            return result;
        }
    }

    return false;
}

在上面的方法中:ValidateUploadedImageContent(),我尝试在 using 语句的帮助下处理流对象,但我发现如果我在方法中保留以下代码:ValidateUploadedImageContent(),那么在这种情况下,在验证过程之后,我在调试时发现 ContentLength 属性设置为 0 值,最后损坏的图像保存在文件系统位置。

更新 :

private bool ValidateUploadedImageContent(HttpPostedFileBase uploadedFile, string imageFileName)
{
    if (Path.GetExtension(imageFileName).Equals(".svg", StringComparison.OrdinalIgnoreCase))
    {
        if (uploadedFile.ContentLength > 0)
        {
            byte[] data;
            using (Stream inputStream = uploadedFile.InputStream)
            {
                Stream inputStream = uploadedFile.InputStream;
                var memoryStream = inputStream as MemoryStream;
                if (memoryStream == null)
                {
                    memoryStream = new MemoryStream();
                    inputStream.CopyTo(memoryStream);
                }

                data = memoryStream.ToArray();
            }

            var parsedData = Encoding.UTF8.GetString(data, 0, data.Length).TrimEnd('\0');
            var result = parsedData.ContainsAny(Constants.InsecureStrings, StringComparison.CurrentCultureIgnoreCase);
            return result;
        }
    }

    return false;
}

谁能帮我知道如何解决这个问题?

标签: c#asp.net-mvc-5

解决方案


首先解决你的问题,我现在明白的是,调用后ValidateUploadedImageContent的图像流是无效的。

这是因为从HttpPostedFileBase获得的流是“只读顺序(不可搜索)”,如本 SO answer中所述。这解释了为什么流的 ContentLength 为 0 - 流已被验证调用消耗。

如果您对 ImageDTO 类具有灵活性,那么修改验证方法以使其返回图像字节将是一种解决方法。

例如,

// on success, buffer contains the image data. Otherwise it is null.
private bool ValidateUploadedImageContent(
    out byte[] buffer,
    HttpPostedFileBase uploadedFile,
    string imageFileName)
{
    buffer = null;
    if (Path.GetExtension(imageFileName).Equals(".svg", StringComparison.OrdinalIgnoreCase))
    {
        if (uploadedFile.ContentLength > 0)
        {
            var reader = new BinaryReader(inputStream);
            buffer = reader.ReadBytes((int)uploadedFile.ContentLength);
            var parsedData = Encoding.UTF8.GetString(buffer, 0, buffer.Length).TrimEnd('\0');
            return parsedData.ContainsAny(Constants.InsecureStrings, StringComparison.CurrentCultureIgnoreCase);
        }
    }
    return false;
}

我使用 BinaryReader 来简化代码。

然后回到调用方法,

byte[] imageBuffer = null;

if (model != null && model.image.ContentType.Contains(Constants.Image) 
    && !ValidateUploadedImageContent(out imageBuffer, model.image, model.image.FileName)) {

    var dto = new ImageDTO();
    using(var imageStream = new MemoryStream(imageBuffer)) {
        // pass along imageStream to your ImageDTO and save.
    }        
}

同样,希望您对 ImageDTO 类有一些灵活性。


推荐阅读