首页 > 解决方案 > 从以二进制形式存储的 Mssql 服务器数据库中检索图像

问题描述

我已经在 MSSql 数据库中以二进制格式存储了一个 jpeg 文件,现在我无法检索原始图像文件/jpeg 文件。有人可以帮我吗?我使用 ASP.net 核心 MVC 将数据存储在数据库中。

ASP.net Core 2.2
MSSQL 2008
Visual Studio 2019

     [HttpGet]
      public IActionResult Index1()
     {
        var ab = _context.Movie.Select(a => a.File).Single();

        return View(ab);
     }

    // POST: api/Uploads
    [HttpPost]
       public IActionResult Post(Movie entity, IFormFile File)
      {
          using (var stream = new MemoryStream())
         {
            File.CopyTo(stream);
            entity.File = stream.ToArray();

        }

        _context.Movie.Add(entity);
        _context.SaveChanges();

        return Ok();
    }

 @model IEnumerable<FileUploads.Models.Movie>

@{
    ViewBag.Title = "Index1";
  }

 <h1>Index1</h1>
  <table>

    <tr>

      @foreach (var item in Model)
       {

          <td>

            @{ 


                var base64 = Convert.ToBase64String(item.File);
                var imgsrc = string.Format("data:image/jpeg;base64,{0}",  base64);
            }

            <img src='@imgsrc' style="max-height:100px;max-width:100px"/>
            }


</td>

        }

    </tr>

</table>
_________

这就是我的 post 方法、get 方法和查看页面的外观。

请帮我。如何获取原始 JPEG 格式的图像?如果您也可以向我展示查看页面,那将会很有帮助。

标签: sql-serverasp.net-core-mvc

解决方案


目前尚不清楚实际问题是什么。您拥有的代码应该可以工作。

但是,无论如何,这不是正确的方法,因此与其浪费时间尝试调试它,不如简单地做对。

使用数据 URI 的问题有两个:

  1. 您基本上是在 HTML 响应中嵌入图像,这意味着它将非常大并且可能需要很长时间才能下载。Web 浏览器在收到完整的 HTML 文档之前无法开始呈现页面,因此文档越大,第一次有意义的绘制之前的时间就越长(即您将盯着一个空白屏幕)。一张图片可能还不错,但是以这种方式添加的越多,问题就会成倍地恶化。您的 HTML 文档最终可能会达到兆字节大小,尤其是对于移动数据而言,这是一个不好的溢价。

  2. Base64 是一种低效的编码。顾名思义,每个字节由 64 个 ASCII 字符的组合表示。由于一个字节可以编码 256 个数字,因此最多需要 4 个字符(每个字符 1-2 个字节)来表示图像中的每个单独的字节。如果不清楚,这意味着您的图像大小将膨胀。正常运行 50-60KB JPEG 的成本可能高达 240KB Base64 编码,这只会激怒首先描述的页面大小问题。

总而言之,正确的方法是通过一个动作来服务图像。例如:

[HttpGet("movie-image/{movieId}")]
public async Task<IActionResult> MovieImage(int movieId)
{
    var movieImage = _context.Movie.Where(x => x.Id == movieId).Select(a => a.File).SingleOrDefault();
    if (movieImage == null)
        return NotFound();

    return File(movieImage, "image/jpeg");
}

那么,在你看来:

<img src="@Url.Action("MovieImage", new { movieId = item.Id })" />

您还可以考虑添加一些缓存标头,以便浏览器缓存图像,并从缓存中加载它,而不是在以后每次显示时都访问服务器:

Response.Headers.Add(HeaderNames.CacheControl, $"max-age={TimeSpan.FromDays(365).TotalSeconds}");
return File(movieImage, "image/jpeg");

最后,由于将被缓存的 URL 与电影 id 而不是物理图像相关联,因此您可以考虑使用 Etags,以防万一您需要更新图像。这有点高级,并不是绝对必要的。最坏的情况是,如果用户之前已经下载了旧图像,则可能会从缓存中加载旧图像。

无论如何,要生成 Etag,您需要生成图像字节的哈希:

string checksum;
using (var sha256 = SHA256.Create())
{
    checksum = Convert.ToBase64String(sha256.ComputeHash(movieImage));
}

if (Request.Headers.TryGetValue(HeaderNames.IfNoneMatch, out var etag && checksum == etag)
    return StatusCode((int)HttpStatusCode.NotModified);

Response.Headers.Add(HeaderNames.CacheControl, $"max-age={TimeSpan.FromDays(365).TotalSeconds}");
Response.Headers.Add(HeaderNames.Etag, checksum);
return File(movieImage, "image/jpeg");

推荐阅读