【问题标题】:Different ways to display images in ASP.NET MVC and when to use which approach在 ASP.NET MVC 中显示图像的不同方式以及何时使用哪种方式
【发布时间】:2013-05-31 10:49:41
【问题描述】:

我正在构建一个使用 ASP.NET MVC4 来上传/显示图像的网站,并找到了几种显示图像的方法,主要是以下 -

1) 将图片作为文件本地存储在服务器上,并使用相对路径在页面上显示。

 //ImageFile is a property which holds a path to the image in the model
 <img src="@item.ImageFile" />

 When the page is rendered, this becomes a path like - <img src="/Content/Images/Jellyfish.jpg" />      

2) 将图像存储为字节数组并使用控制器操作检索它 -

//Use a controller action (GetImg) to get the URL of the image
<img src="@Url.Action("GetImg", "ViewPhotos", new { id = item.ID })" alt="Image" />  

When the page is rendered, this becomes a path like - <img src="/ViewPhotos/GetImg/4" alt="Image" />    

3) 将图像存储为字节数组并直接在视图中检索 -

//Directly re-construct the image in the view from the byte array (Image property of the model)
<img src="@String.Format("data:image/jpg;base64,{0}", Convert.ToBase64String(item.Image))" />  

When the page is rendered, this becomes a path like - <img src="data:image/jpg;base64,/9j/4AAQSkZJRgABAgEA....<long string> .../>

我的问题是 -

1) 1 和 2 有什么区别?

1 直接提供文件的路径,2 提供文件的 URL。它们在后台是相同的还是一种方法比另一种更好?

我检查了here,它说 - Url.Action 将构造动作的路径,返回一个 url,而不是执行动作的结果。那么什么时候检索结果呢?

2) 对 1 或 2 使用 3 是否会对性能产生影响?

3) 当图像尺寸较小(小于 1MB)或较大时,应该使用哪种方法?

如果你能指出任何可以帮助的链接,我很高兴。 谢谢。

代码 -

//型号

public class Photo
{
  public int ID { get; set; }
  public string ImageFile { get; set; }
  public byte[] Image { get; set; }
  public string Caption { get; set; }
}

//控制器

public FileContentResult GetImg(int id)
{
    byte[] byteArray = db.Photos.Find(id).Image;
    if (byteArray != null)
    {
        return new FileContentResult(byteArray, "image/jpeg");
    }
    else
    {
         return null;
    }
}

//查看(方法二)

@model IEnumerable<MyPhotoLibrary.Models.Photo>
@foreach (var item in Model) {
<tr>
  <td>
    <img src="@Url.Action("GetImg", "ViewPhotos", new { id = item.ID })" alt="Image" />
  </td>
</tr>
}

//查看(这是方法3)

@model IEnumerable<MyPhotoLibrary.Models.Photo>
@foreach (var item in Model) {
<tr>
  <td>
    <img src="@String.Format("data:image/jpg;base64,{0}", Convert.ToBase64String(item.Image))" />
  </td>
</tr>
}

【问题讨论】:

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


    【解决方案1】:

    我最近自己查了一下,发现了 Microsoft 研究论文 To BLOB Or Not To BLOB,其中比较了将文件(例如图像)作为二进制数据存储在数据库中的性能与传统文件系统的性能。

    调查结果,大致总结:

    • 小文件(大小 > 256KB)最好以字节数组的形式存储在数据库中(您的第二个和第三个选项),可以从中快速检索它们并提供给用户。
    • 大文件(大小 > 1MB 左右)最好存储在文件系统中(您的首选),因为大文件的吞吐量和碎片会随着文件的增大而急剧下降
    • 介于 256KB 和 1MB 之间(大致;范围很模糊,取决于您的确切设置)性能取决于文件可能被编辑或覆盖的次数;一般来说,数据库在处理静态文件时表现更好,而文件系统在保持高吞吐量和低碎片率方面要好得多。

    选项之间的其他区别:

    选项 1 要求您的应用程序对图像所在的任何文件夹都具有读取权限,如果图像是由用户上传或编辑的,那么应用程序将需要对该文件夹的写入权限,因为好吧。如果您使用共享主机(尤其是廉价或免费主机计划)或者您的系统管理员特别偏执,这可能会很棘手。

    选项 2 需要从客户端多次调用服务器来获取所有数据;这可能看起来像一件坏事,但它确实将页面加载分解成可能实际上有帮助的块 - 页面(没有图像)将在第一次调用时加载,然后将单独请求图像,如果其中一个需要一段时间,或者有某种错误,那么页面的其余部分应该不受影响,这很好。与 cmets 中的 jgauffin pointed out 一样,此选项允许您为图像设置缓存,因此浏览器可以通过仅在图像发生更改时重新下载它们来节省带宽。

    选项 3 要求客户端一次性加载全部内容,这可能需要一段时间。它还将字节数组的处理转移到客户端,这可能是智能手机或低端上网本等低功耗客户端的问题。如果您的图像很大,最好使用服务器的 CPU 能力来实际处理从字节数组到图像文件的转换。正如 cmets 中的 jgauffin notes 一样,这也不能很好地与缓存一起使用 - 如果视图的 HTML 的任何部分发生更改,浏览器将不得不再次下载图像

    此外,这可能与您的具体情况无关,但通过单独调用加载图像可以让您在这些操作中执行其他操作,例如写入调试日志或在后台执行其他一些内务处理。

    【讨论】:

    • +1 选项 2 优于选项 3,因为后者的图像缓存很难,因为每次更改视图(或图像本身)时缓存都会失效。 Base64 还需要一些额外的处理
    • 是的,缓存也值得一提。在选项 2 中,浏览器将识别出它们正在生成 GET 并获取图像,它们可以缓存并在多个页面中重复使用;在选项 3 中,他们只看到必须处理的大量 base64 字符串。
    • 关于将图像存储在文件或数据库中,您可以看到sqlskills.com/blogs/paul/sql-server-2008-filestream-performance,正如您所说的research.microsoft.com/apps/pubs/?id=64525,以及关于从视图中调用哪种类型的图像,我同意方法2,因为它的缓存和加载成块。但我不知道当它没有缓存时,点击服务器的超计数如何影响性能。你能绝对建议吗?
    【解决方案2】:

    1) 在服务器端的处理会更少,因为函数调用会更少。如果你想渲染动作的输出 - 你需要在differences here

    上调用 HTML 帮助器方法 Html.RenderAction 或 Html.Action 更多

    2) 2 和 3 之间的区别在于,当您直接输入字节数组时,您到服务器的往返次数更少(DNS 查找等),但在单个请求中下载的数据更多。某些浏览器可能会并行下载内容(每个域 5-8 次并行下载),因此如果您使用 3 个,则会在页面加载速度方面松动。更多关于并行下载herehere

    这导致我们 3)如果你有小图像,3 是要走的路,因为客户端会请求更少的资源,页面加载速度会更快,但是如果你有大图像,你应该使用 1。

    【讨论】:

    • 谢谢伊加里奥什卡。现在已经很清楚了。所以对于小图像我可以使用 3,对于大图像我可以使用 1。但是我什么时候应该更喜欢 2 而不是 1?
    • @siddharth 好吧,如果您有一组图像并且想要全局自定义它们的呈现方式或应用自定义逻辑(某种角色验证),则使用 2。 2 基本上是一个附加功能,因为您可以通过调用操作来实现 1 和 3
    【解决方案3】:

    我没有时间测试性能,但我会告诉你几点。

    在方法 1 中,您确实仅依靠 HDD 存储和性能来保存文件以及您的 Web 服务器提供静态文件的能力。

    在方法 2 中,每次有请求时都会生成字节流...存储和检索是 DB 驱动的(当然是 HDD 起作用),如果不添加,就无法利用 Web 服务器的本机缓存功能一些相关代码(可能只是属性OutputCache,但它可能更复杂)。

    在方法 3 中,客户端只是渲染,而您正在将图像与网页一起发送。这里的性能确实取决于浏览器,但请记住,如果图像很大,接收整个页面需要一些时间。

    所以我通常更喜欢方法 1,我只需在 db 中存储一个图像路径,然后我可以从磁盘获取图像并让 IIS 进行缓存、交付、优化等。

    选择方法 2 有很多正当理由,这主要是如果您有一个分布式 Web 服务器架构,其中方法 1 意味着每个服务器必须在 HDD 上保存图像的副本,同时拥有一切在数据库中的一个地方意味着您可以随时检索 iamges...也许实施一些缓存以避免在每个请求中访问数据库。

    方法 3 仅适用于一次性使用的小图像。我说一次性使用是因为您不想将它用于周围使用的图标和图像,它们应该保持静态,以便客户端可以缓存它们。

    希望这有助于做出更好的决定。

    在类似于 2 的场景中,具有多个 Web 服务器架构,在过去的工作中,我们采用了混合解决方案:图像位于数据库中,但每个 Web 服务器在第一次请求时遇到 404图像,将从数据库下载图像并指示客户端重试(在某种程度上,这是一种非常原始的缓存实现)。

    【讨论】:

      猜你喜欢
      • 2021-06-19
      • 2021-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-04
      • 2014-10-12
      相关资源
      最近更新 更多