The goal is to use a database to store images and use MVC to call those images, using custom routes.
The premises are,
- The URL must be something like this: “imagebank/sample-file” or “imagebank/32403404303“.
- The MVC Controller/Action will get the image by an ID “sample-file” or “32403404303” and find out on some cache and/or database to display the image. If it exists in cache, get from cache if not get from database. So in HTML, we can call the image like this.
- <img src="~/imagebank/sample-file" />
- If you want to use another URL, for instance “foo/sample-file”, you can change the image bank route name in web.config.
- If you do not want to display the image and just download the file, use - “imagebank/sample-file/download“.
So, let's get started!
The image bank route configuration
App_Start\RouteConfig.cs
- public class RouteConfig
- {
- public static void RegisterRoutes(RouteCollection routes)
- {
- routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
-
- routes.MapRoute(
- name: "ImageBank",
- url: GetImageBankRoute() + "/{fileId}/{action}",
- defaults: new { controller = "ImageBank", action = "Index" }
- );
-
- routes.MapRoute(
- name: "Default",
- url: "{controller}/{action}/{id}",
- defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
- );
- }
-
- private static string GetImageBankRoute()
- {
- var key = "imagebank:routeName";
- var config = ConfigurationManager.AppSettings.AllKeys.Contains(key) ? ConfigurationManager.AppSettings.Get(key) : "";
-
- return config ?? "imagebank";
- }
- }
The Image Bank Controller
Controllers\ImageBankController.cs
- public class ImageBankController : Controller
- {
- public ImageBankController()
- {
- Cache = new Cache();
- Repository = new Repository();
- }
-
- public ActionResult Index(string fileId, bool download = false)
- {
- var defaultImageNotFound = "pixel.gif";
- var defaultImageNotFoundPath = $"~/content/img/{defaultImageNotFound}";
- var defaultImageContentType = "image/gif";
-
- var cacheKey = string.Format("imagebankfile_{0}", fileId);
- Models.ImageFile model = null;
-
- if (Cache.NotExists(cacheKey))
- {
- model = Repository.GetFile(fileId);
-
- if (model == null)
- {
- if (download)
- {
- return File(Server.MapPath(defaultImageNotFoundPath), defaultImageContentType, defaultImageNotFound);
- }
-
- return File(Server.MapPath(defaultImageNotFoundPath), defaultImageContentType);
- }
-
- Cache.Insert(cacheKey, "Default", model);
- }
- else
- {
- model = Cache.Get(cacheKey) as Models.ImageFile;
- }
-
- if (download)
- {
- return File(model.Body, model.ContentType, string.Concat(fileId, model.Extension));
- }
-
- return File(model.Body, model.ContentType);
- }
-
- public ActionResult Download(string fileId)
- {
- return Index(fileId, true);
- }
-
- private Repository Repository { get; set; }
-
- private Cache Cache { get; set; }
- }
The above code has two actions - one for displaying the image and the other for downloading it.
The database repository
Repository.cs
- public class Repository
- {
- public static Models.ImageFile GetFile(string fileId)
- {
-
- SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["ImageBankDatabase"].ConnectionString);
-
- try
- {
- connection.Open();
- var sql = @"SELECT *
- FROM dbo.ImageBankFile
- WHERE FileId = @fileId
- OR ISNULL(AliasId, FileId) = @fileId";
-
- var command = new SqlCommand(sql, connection);
- command.Parameters.Add("@fileId", SqlDbType.VarChar).Value = fileId;
- command.CommandType = CommandType.Text;
- var ada = new SqlDataAdapter(command);
- var dts = new DataSet();
- ada.Fill(dts);
-
- var model = new Models.ImageFile();
- model.Extension = dts.Tables[0].Rows[0]["Extension"] as string;
- model.ContentType = dts.Tables[0].Rows[0]["ContentType"] as string;
- model.Body = dts.Tables[0].Rows[0]["FileBody"] as byte[];
-
- return model;
- }
- catch
- {
-
- }
- finally
- {
- if (connection != null)
- {
- connection.Close();
- connection.Dispose();
- connection = null;
- }
- }
-
- return null;
- }
- }
The repository is very simple. This code is just for demonstration. You can implement your own code.
The image bank model class
Models\ImageFile.cs
- public class ImageFile
- {
- public byte[] Body { get; set; }
-
- public string ContentType { get; set; }
-
- public string Extension { get; set; }
- }
Create table script
- USE [ImageBankDatabase]
- GO
-
- /****** Object: Table [dbo].[ImageBankFile] Script Date: 11/16/2016 12:36:56 ******/
- SET ANSI_NULLS ON
- GO
-
- SET QUOTED_IDENTIFIER ON
- GO
-
- SET ANSI_PADDING ON
- GO
-
- CREATE TABLE [dbo].[ImageBankFile](
- [FileId] [nvarchar](50) NOT NULL,
- [AliasId] [nvarchar](100) NULL,
- [FileBody] [varbinary](max) NULL,
- [Extension] [nvarchar](5) NULL,
- [ContentType] [nvarchar](50) NULL,
- CONSTRAINT [PK_ImageBankFile] PRIMARY KEY CLUSTERED
- (
- [FileId] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
-
- GO
-
- SET ANSI_PADDING OFF
- GO
The Cache provider class
Cache.cs
- public class Cache
- {
- public Cache()
- {
- _config = ConfigurationManager.GetSection("system.web/caching/outputCacheSettings") as OutputCacheSettingsSection;
- }
-
- private OutputCacheSettingsSection _config;
-
- private OutputCacheProfile GetProfile(string profile)
- {
- return !string.IsNullOrEmpty(profile) ? _config.OutputCacheProfiles[profile] : new OutputCacheProfile("default");
- }
-
- private object GetFromCache(string id)
- {
- if (string.IsNullOrEmpty(id)) throw new NullReferenceException("id is null");
- if (System.Web.HttpRuntime.Cache != null)
- {
- lock (this)
- {
- return System.Web.HttpRuntime.Cache[id];
- }
- }
-
- return null;
- }
-
- public Cache Insert(string id, string profile, object obj)
- {
- if (System.Web.HttpRuntime.Cache != null)
- {
- if (string.IsNullOrEmpty(id))
- {
- throw new ArgumentNullException("id", "id is null");
- }
-
- if (string.IsNullOrEmpty(profile))
- {
- throw new ArgumentNullException("profile", string.Format("profile is null for id {0}", id));
- }
-
- var objProfile = GetProfile(profile);
- if (objProfile == null)
- {
- throw new NullReferenceException(string.Format("profile is null for id {0} and profile {1}", id, profile));
- }
-
- lock (this)
- {
- System.Web.HttpRuntime.Cache.Insert(id, obj, null, DateTime.Now.AddSeconds(objProfile.Duration), TimeSpan.Zero);
- }
- }
-
- return this;
- }
-
- public bool NotExists(string id)
- {
- return GetFromCache(id) == null;
- }
-
- public Cache Remove(string id)
- {
- if (System.Web.HttpRuntime.Cache != null)
- {
- lock (this)
- {
- System.Web.HttpRuntime.Cache.Remove(id);
- }
- }
-
- return this;
- }
-
- public object Get(string id)
- {
- return GetFromCache(id);
- }
- }
So that's it! I hope you enjoyed! Download full source code from
here.