【问题标题】:MVC: How to make multiple requests share a List of ImagesMVC:如何让多个请求共享一个图像列表
【发布时间】:2015-12-29 23:44:44
【问题描述】:

我创建了一个控制器来从我的数据库中检索图像,并成功地检索到了图像:

public class ImageController : Controller
{
    [Route("user/{userId:int}/profile", Name = "GetUserProfileImage")]
    public ActionResult UserProfileImage(int userId)
    {
        using (var imgRepo = new ImageRepository())
        {
            UserProfileImage img = imgRepo.GetUserImage(userId);
            return File(img.Image, "image/jpg");
        }
    }
}

ImageRepository 在创建 DBContext 时对其进行实例化,并在释放 DBContext 时将其释放。

因此,我有一个显示用户列表的视图,并且对于每个用户,我都会像这样显示他们的图片:

@model IEnumerable<UserRankingViewModel>
<table class="table">
    <tr>
        <th>
            #
        </th>
        <th>
            @Html.DisplayNameFor(modelItem => modelItem.First().Name)
        </th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.RankingPosition)
            </td>
            <td>
                    <img src="@item.ImageUrl" class="img-circle img-nav">
                    @Html.DisplayFor(modelItem => item.Name)
            </td>
        </tr>
    }

</table>

其中@item.ImageUrl 是指向GetUserProfileImage 路由的Url。如果我要列出 50 个用户,那么将向该路由发出 50 个请求,我猜 DBContext 将被查询 50 次以获取用户图像。

对于这种特殊情况,是否可以在内存中存储 UserProfileImage 列表以避免每次都查询数据库?这是一个不好的做法吗?如果是,为什么?

在我的情况下,除此之外没有其他应用程序/网络服务可以更改数据库数据,因此如果用户更新他们的图片,我可以检查其中是否有任何内存中图片列出并更新它,除了更新数据库。

【问题讨论】:

  • 您可以使用 System.Web.Caching 命名空间缓存图像列表。
  • 您可以加载所有图像并使用Base64 格式将它们传递给查看。您还可以在文件系统中缓存图像并使用文件系统返回文件结果。
  • 不要混淆客户端缓存(由浏览器处理)和服务器缓存(由服务器处理)。我说的是服务器缓存。您可以让控制器首先检查缓存中是否存在图像列表,如果不存在,则调用图像存储库以检索列表并将其添加到缓存中。任何后续请求都将从缓存中检索图像列表,而不是命中数据库。您可以让缓存在设定的时间间隔后过期,或者只使用滑动过期并在每次更新/删除/添加图像时自己显式地使缓存无效。
  • 我认为您的 IEnumerable 模型的最佳实践是将图像加载到此模型中以在唯一查询中显示
  • 如果你把关注点分开,那么它就不会混淆。例如,如果您使用文件系统,那么您的操作的工作是首先检查文件系统上是否存在该项目,然后返回它,否则首先简单地从数据库中获取数据,然后将其放入文件系统并返回它。您还可以在需要时使整个缓存或缓存项无效。例如,您可以创建一个操作来重新创建文件系统,并在需要时从您的站点控制面板调用它。或者您可以在用户图像更改时使用户图像无效。或者您可以制定一个使文件系统失效的计划。

标签: c# asp.net-mvc entity-framework


【解决方案1】:

尝试将所有图像以 byte64 格式加载到模型中,并直接显示在视图中。 在您的代码中,什么是 UserProfileImage? UserProfileImage.Image 是什么王者?

你可以试试;

class UserRankingViewModel
{
    ... ...
    public string ImageBase64 {get;set;}
}

class yourController: Controller
{
    public IActionResult YourMethodForLoadUserRunk()
    {
        .... ....
        //here you can load image from dbcontext (memorystream for ex)
        //and convert to array
        var user = new UserRankingViewModel();
        var string64 = Convert.ToBase64String(yourimage.ToArray());
        user.ImageBase64 = String.Format("data:image/gif;base64,{0}", string64);
        ....
        ....
    }
}

所以在你看来:

@foreach (var item in Model)
{
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.RankingPosition)
        </td>
        <td>
                <img src="@item.ImageBase64" class="img-circle img-nav">
                @Html.DisplayFor(modelItem => item.Name)
        </td>
    </tr>
}

【讨论】:

  • 您可以使用服务器缓存(例如 System.Runtime.Caching.MemoryCache)改进我的解决方案并为您的排名视图保存用户数据
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-19
  • 1970-01-01
相关资源
最近更新 更多