MVC - 如何从主页面上的文件夹中放置随机图像

时间:2021-11-16 00:32:19

I have an MVC app and I want on the top of the master page to have a series of random images from the folder.

我有一个MVC应用程序,我想在母版页的顶部从文件夹中获得一系列随机图像。

To do this I have to write code but not where to write the code?? It has to be done in one place.

要做到这一点,我必须编写代码,但不是在哪里编写代码?它必须在一个地方完成。

I will probably just set the images at the beginning of the session so they are cached by the browser and improve performance of the site.

我可能只是在会话开始时设置图像,以便浏览器缓存它们并提高网站的性能。

Malcolm

4 个解决方案

#1


Caching is Key

缓存是关键

As the others have said, you've got to use caching since you are performing repetitive disk I/O on data that doesn't change often.

正如其他人所说,你必须使用缓存,因为你在不经常更改的数据上执行重复的磁盘I / O.

My example creates and caches a List<T> of the image file paths you will need for each subsequent request. System.Web.Caching is perfect for this because you can create a CacheDependency object directly on your image directory -- if a file gets changed or added, your cache is automatically invalidated. It is then recreated the next time it is requested.

我的示例创建并缓存了每个后续请求所需的映像文件路径的List 。 System.Web.Caching非常适用于此,因为您可以直接在映像目录上创建CacheDependency对象 - 如果文件被更改或添加,您的缓存将自动失效。然后在下次请求时重新创建它。

Avoiding Duplicates with the HashSet<T>

使用HashSet避免重复

I bet you don't want two of the same pictures ever showing up in your header!

我打赌你不希望你头上出现两张相同的照片!

Randomizing using Random.Next does not exclude previously generated duplicates. I used a HashSet<T> as a poor man's unique randomizer since the HashSet<T> will only allow you to add unique values.

使用Random.Next进行随机化不会排除先前生成的重复项。我使用HashSet 作为穷人的独特随机函数,因为HashSet 只允许您添加唯一值。

The Model

This operation should be part of your model in MVC. You change it to go along with your other data fetching classes as you see fit.

此操作应该是MVC中模型的一部分。您可以根据需要将其更改为与其他数据提取类一起使用。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Caching;

public class RandomImage
{
    public static string[] GetImages(string folder, int count)
    {
        HttpContext context = HttpContext.Current;
        string virtualFolderPath = string.Format("/content/{0}/", folder);
        string absoluteFolderPath = context.Server.MapPath(virtualFolderPath);

        Cache cache = context.Cache;
        var images = cache[folder + "_images"] as List<string>;

        // cache string array if it does not exist
        if (images == null)
        {
            var di = new DirectoryInfo(absoluteFolderPath);
            images = (from fi in di.GetFiles()
                            where fi.Extension.ToLower() == ".jpg" || fi.Extension.ToLower() == ".gif"
                            select string.Format("{0}{1}", virtualFolderPath, fi.Name))
                            .ToList();


            // create cach dependency on image randomFolderName
            cache.Insert(folder + "_images", images, new CacheDependency(absoluteFolderPath));
        }

        Random random = new Random();
        var imageSet = new HashSet<string>();
        if (count > images.Count())
        {
            throw new ArgumentOutOfRangeException("count");
        }

        while (imageSet.Count() < count)
        {
            //using an hashset will ensure a random set with unique values.
            imageSet.Add(images[random.Next(count)]);
        }

        return imageSet.ToArray();
    }
}

The Controller

Access the method in your controller something like....

访问控制器中的方法,如....

string[] images = Models.RandomImage.GetImages("myPictures", 4);

#2


Write a helper function that would get a random filename from an array of filenames which is generated at application startup.

编写一个辅助函数,它将从应用程序启动时生成的文件名数组中获取随机文件名。

#3


Well, to get the images:

好吧,要获得图像:

string[] get_images(string folder) {
     string[] files = Directory.GetFiles(folder, "*.jpg"/* or whatever */);
     List<string> rand = new List<string>();
     Random r = new Random();
     for ( int i = 0; i < numImages; i++ ) {
         rand.Add(Path.GetFileName(files[r.Next(files.Length-1)]));
     }
     return rand.ToArray();
}

And then in the master page:

然后在母版页中:

<% PrintImages(); %>

Where PrintImages() is:

PrintImages()的位置是:

string[] img = get_images(Server.MapPath("~/Content/RandomImages"));
foreach (string i in img) { Response.Write("<img src=\"/Content/RandomImages/"+i+"\" />"); }

That is a rough solution, and caching would be good - that would really thrash a disk.

这是一个粗略的解决方案,缓存会很好 - 这会真正破坏磁盘。

#4


I'd want to make sure that simply reading the directory each time and generating the file names is a real bottleneck before I'd do anything more complicated. It's certainly less efficient, but the code is arguably simpler. If it isn't a bottleneck, then the controller action responsible for rendering the view is the right place for the code. Note that you'll need to turn of output caching for the action (if it isn't already) if you want the image to change each time.

我想确保在我做任何更复杂的事情之前,每次只读取目录并生成文件名是一个真正的瓶颈。它的效率当然不高,但代码可以说更简单。如果它不是瓶颈,则负责呈现视图的控制器操作是代码的正确位置。请注意,如果您希望每次更改图像,则需要为操作(如果尚未执行)转换输出缓存。

If it turns out that reading the file names and constructing the links really is a bottleneck -- it may take much less time than reading the actual file -- AND the files in the directory can change while the application is running, then constructing a collection of them and storing them in the session on login is a reasonable way to handle it. The caveat is that if the application is also responsible for uploading the images (so that it knows when they change), you might be able to load them at application start and keep them in a global instance which is updated by the application as images are uploaded (or removed).

如果事实证明读取文件名和构建链接确实是一个瓶颈 - 它可能比读取实际文件花费的时间少得多 - 并且目录中的文件可以在应用程序运行时更改,然后构建集合他们在登录时将它们存储在会话中是一种合理的方法来处理它。需要注意的是,如果应用程序还负责上传图像(以便它知道何时更改),您可以在应用程序启动时加载它们并将它们保存在由应用程序更新的全局实例中,因为图像是上传(或删除)。

Once you have your collection of images (by reading each time, from the session, or a global instance), use a random number generator to pick the image that you want to display or a set that you want to rotate through using something like the jQuery Cycle plugin, pass it (them) to the view and have it render the image tags.

获得图像集后(通过每次,从会话或全局实例读取),使用随机数生成器选择要显示的图像或要使用类似于jQuery Cycle插件,将它(它们)传递给视图并让它渲染图像标签。

#1


Caching is Key

缓存是关键

As the others have said, you've got to use caching since you are performing repetitive disk I/O on data that doesn't change often.

正如其他人所说,你必须使用缓存,因为你在不经常更改的数据上执行重复的磁盘I / O.

My example creates and caches a List<T> of the image file paths you will need for each subsequent request. System.Web.Caching is perfect for this because you can create a CacheDependency object directly on your image directory -- if a file gets changed or added, your cache is automatically invalidated. It is then recreated the next time it is requested.

我的示例创建并缓存了每个后续请求所需的映像文件路径的List 。 System.Web.Caching非常适用于此,因为您可以直接在映像目录上创建CacheDependency对象 - 如果文件被更改或添加,您的缓存将自动失效。然后在下次请求时重新创建它。

Avoiding Duplicates with the HashSet<T>

使用HashSet避免重复

I bet you don't want two of the same pictures ever showing up in your header!

我打赌你不希望你头上出现两张相同的照片!

Randomizing using Random.Next does not exclude previously generated duplicates. I used a HashSet<T> as a poor man's unique randomizer since the HashSet<T> will only allow you to add unique values.

使用Random.Next进行随机化不会排除先前生成的重复项。我使用HashSet 作为穷人的独特随机函数,因为HashSet 只允许您添加唯一值。

The Model

This operation should be part of your model in MVC. You change it to go along with your other data fetching classes as you see fit.

此操作应该是MVC中模型的一部分。您可以根据需要将其更改为与其他数据提取类一起使用。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Caching;

public class RandomImage
{
    public static string[] GetImages(string folder, int count)
    {
        HttpContext context = HttpContext.Current;
        string virtualFolderPath = string.Format("/content/{0}/", folder);
        string absoluteFolderPath = context.Server.MapPath(virtualFolderPath);

        Cache cache = context.Cache;
        var images = cache[folder + "_images"] as List<string>;

        // cache string array if it does not exist
        if (images == null)
        {
            var di = new DirectoryInfo(absoluteFolderPath);
            images = (from fi in di.GetFiles()
                            where fi.Extension.ToLower() == ".jpg" || fi.Extension.ToLower() == ".gif"
                            select string.Format("{0}{1}", virtualFolderPath, fi.Name))
                            .ToList();


            // create cach dependency on image randomFolderName
            cache.Insert(folder + "_images", images, new CacheDependency(absoluteFolderPath));
        }

        Random random = new Random();
        var imageSet = new HashSet<string>();
        if (count > images.Count())
        {
            throw new ArgumentOutOfRangeException("count");
        }

        while (imageSet.Count() < count)
        {
            //using an hashset will ensure a random set with unique values.
            imageSet.Add(images[random.Next(count)]);
        }

        return imageSet.ToArray();
    }
}

The Controller

Access the method in your controller something like....

访问控制器中的方法,如....

string[] images = Models.RandomImage.GetImages("myPictures", 4);

#2


Write a helper function that would get a random filename from an array of filenames which is generated at application startup.

编写一个辅助函数,它将从应用程序启动时生成的文件名数组中获取随机文件名。

#3


Well, to get the images:

好吧,要获得图像:

string[] get_images(string folder) {
     string[] files = Directory.GetFiles(folder, "*.jpg"/* or whatever */);
     List<string> rand = new List<string>();
     Random r = new Random();
     for ( int i = 0; i < numImages; i++ ) {
         rand.Add(Path.GetFileName(files[r.Next(files.Length-1)]));
     }
     return rand.ToArray();
}

And then in the master page:

然后在母版页中:

<% PrintImages(); %>

Where PrintImages() is:

PrintImages()的位置是:

string[] img = get_images(Server.MapPath("~/Content/RandomImages"));
foreach (string i in img) { Response.Write("<img src=\"/Content/RandomImages/"+i+"\" />"); }

That is a rough solution, and caching would be good - that would really thrash a disk.

这是一个粗略的解决方案,缓存会很好 - 这会真正破坏磁盘。

#4


I'd want to make sure that simply reading the directory each time and generating the file names is a real bottleneck before I'd do anything more complicated. It's certainly less efficient, but the code is arguably simpler. If it isn't a bottleneck, then the controller action responsible for rendering the view is the right place for the code. Note that you'll need to turn of output caching for the action (if it isn't already) if you want the image to change each time.

我想确保在我做任何更复杂的事情之前,每次只读取目录并生成文件名是一个真正的瓶颈。它的效率当然不高,但代码可以说更简单。如果它不是瓶颈,则负责呈现视图的控制器操作是代码的正确位置。请注意,如果您希望每次更改图像,则需要为操作(如果尚未执行)转换输出缓存。

If it turns out that reading the file names and constructing the links really is a bottleneck -- it may take much less time than reading the actual file -- AND the files in the directory can change while the application is running, then constructing a collection of them and storing them in the session on login is a reasonable way to handle it. The caveat is that if the application is also responsible for uploading the images (so that it knows when they change), you might be able to load them at application start and keep them in a global instance which is updated by the application as images are uploaded (or removed).

如果事实证明读取文件名和构建链接确实是一个瓶颈 - 它可能比读取实际文件花费的时间少得多 - 并且目录中的文件可以在应用程序运行时更改,然后构建集合他们在登录时将它们存储在会话中是一种合理的方法来处理它。需要注意的是,如果应用程序还负责上传图像(以便它知道何时更改),您可以在应用程序启动时加载它们并将它们保存在由应用程序更新的全局实例中,因为图像是上传(或删除)。

Once you have your collection of images (by reading each time, from the session, or a global instance), use a random number generator to pick the image that you want to display or a set that you want to rotate through using something like the jQuery Cycle plugin, pass it (them) to the view and have it render the image tags.

获得图像集后(通过每次,从会话或全局实例读取),使用随机数生成器选择要显示的图像或要使用类似于jQuery Cycle插件,将它(它们)传递给视图并让它渲染图像标签。