Uploading and Viewing Images With ASP.NET MVC and Mongo DB






4.73/5 (8 votes)
How to upload and view images with ASP.NET MVC and Mongo DB
The goal today is to create a small and quick ASP.NET MVC application that will allow us to upload and view images using MongoDB as the database. One of the methods for handling files with MongoDB is using Mongo’s GridFS specification. This method stores the file in chunks and stores those chunks in separate documents. The method we will use is more of a “classic” way to store images in databases. We will simply convert the bytes of the image to a string
and store it and do the reverse for viewing the image.
The Tools We’ll Need
- Visual Studio (I’m using VS 2013 express)
- The ASP.NET MVC framework (I’m using version 5)
- A MongoDB server instance (I’m running mine locally with the default settings)
- Already be little familiar with MVC and the mongoDB in general
Let’s Get Started
First, we’ll need to create a new web application proeject. Go to File on the menu and select “new project”.
On the next screen, select MVC with the default settings.
We now have a basic MVC web application template. Next, add a new controller by right-clicking the Controllers folder and selecting “add” and then “Controller”. Select empty MVC 5 controller. We should now have an empty gallery controller like so:
Get MongoDb Drivers From NuGet
To use the mongo database from this application, we will need to get the necessary drivers for C#. Open your Package Manager console and type the command:
Install-Package mongocsharpdriver
This will add the mongo c sharp drivers to your application from NuGet.
The Picture Model
Next, add a class to your models folder named MongoPictureModel.cs with the following:
using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MongoAndMVC.Models
{
public class MongoPictureModel
{
public ObjectId _id { get; set; }
public string FileName { get; set; }
public string PictureDataAsString { get; set; }
}
}
A couple of things to notice. We added a using
statement for the “MongoDB.Bson
” namespace
. We did this because we are using the type “ObjectId
” which is a type native to mongo. Now that we have our model, we can now edit our controller with the need functions.
GalleryController.cs
Update the gallery controller like so…
using MongoAndMVC.Models;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MongoAndMVCTutorial.Controllers
{
public class GalleryController : Controller
{
public ActionResult Index()
{
var theModel = GetThePictures();
return View(theModel);
}
public ActionResult AddPicture()
{
return View();
}
[HttpPost]
public ActionResult AddPicture(HttpPostedFileBase theFile)
{
if (theFile.ContentLength > 0)
{
//get the file's name
string theFileName = Path.GetFileName(theFile.FileName);
//get the bytes from the content stream of the file
byte[] thePictureAsBytes = new byte[theFile.ContentLength];
using (BinaryReader theReader = new BinaryReader(theFile.InputStream))
{
thePictureAsBytes = theReader.ReadBytes(theFile.ContentLength);
}
//convert the bytes of image data to a string using the Base64 encoding
string thePictureDataAsString = Convert.ToBase64String(thePictureAsBytes);
//create a new mongo picture model object to insert into the db
MongoPictureModel thePicture = new MongoPictureModel()
{
FileName = theFileName,
PictureDataAsString = thePictureDataAsString
};
//insert the picture object
bool didItInsert = InsertPictureIntoDatabase(thePicture);
if (didItInsert)
ViewBag.Message = "The image was updated successfully";
else
ViewBag.Message = "A database error has occurred";
}
else
ViewBag.Message = "You must upload an image";
return View();
}
/// <summary>
/// This method will insert the picture into the db
/// </summary>
/// <param name="thePicture"></param>
/// <returns></returns>
private bool InsertPictureIntoDatabase(MongoPictureModel thePicture)
{
var thePictureColleciton = GetPictureCollection();
var theResult = thePictureColleciton.Insert(thePicture);
return theResult.Ok;
}
/// <summary>
/// This method will return just the id's and filenames of the pictures
/// to use to retrieve the image from the db
/// </summary>
/// <returns></returns>
private List<MongoPictureModel> GetThePictures()
{
var thePictureColleciton = GetPictureCollection();
var thePictureCursor = thePictureColleciton.FindAll();
//use SetFields to just return the id and the name of the picture instead of the entire document
thePictureCursor.SetFields(Fields.Include("_id", "FileName"));
return thePictureCursor.ToList() ?? new List<MongoPictureModel>();
}
/// <summary>
/// This action will return an image result to render the data from the picture as a jpeg
/// </summary>
/// <param name="id">id of the picture as a string</param>
/// <returns></returns>
public FileContentResult ShowPicture(string id)
{
var thePictureColleciton = GetPictureCollection();
//get picture document from db
var thePicture = thePictureColleciton.FindOneById(new ObjectId(id));
//transform the picture's data from string to an array of bytes
var thePictureDataAsBytes = Convert.FromBase64String(thePicture.PictureDataAsString);
//return array of bytes as the image's data to action's response.
//We set the image's content mime type to image/jpeg
return new FileContentResult(thePictureDataAsBytes, "image/jpeg");
}
/// <summary>
/// This will return the mongoDB picture collection object to use dor data related actions
/// </summary>
/// <returns></returns>
private MongoCollection<MongoPictureModel> GetPictureCollection()
{
//set this to what ever your connection is or from config
var theConnectionString = "mongodb://localhost";
//get the mongo db client object
var theDBClient = new MongoClient(theConnectionString);
//get reference to db server
var theServer = theDBClient.GetServer();
//gets the database , if it doesn't exist it will create a new one
string databaseName = "PictureApplication";//replace with whatever name you choose
var thePictureDB = theServer.GetDatabase(databaseName);
//finally attempts to get a collection, if not there it will make a new one
string theCollectionName = "pictures";
var thePictureColleciton = thePictureDB.GetCollection<MongoPictureModel>(theCollectionName);
return thePictureColleciton;
}
}
}
Let’s look at what we did here. The first thing that we did was add some new namespace
s from the Mongo driver library to help us access the mongo DB and give us access to some very useful classes for manipulating the mongo data.
MongoAndMVC.Models;
MongoDB.Bson;
MongoDB.Driver;
MongoDB.Driver.Builders;
We also added the System.IO namespace
for some of the byte manipulation that we’ll be doing.
GetPictureCollection Function
This function goes through the process of giving us a MongoCollection<T>
object that we can use for inserting and retrieving data. If the database or collection does not exist, the mongo database will create it on the fly.
ShowPicture Action
This action retrieves the picture data using the id passed in the URL. It will then take the data retrieved that was stored in string
format and convert back to an array of bytes. Since we are returning a FileContentResult
, this action will take the bytes and return them in the response in the designated “image/jpeg” mime type.
GetThePictures Function
This function returns a list of the MongoPictureModel
objects retrieved from the database. The thing we did different here is use the SetFields
function to reduce the fields we bring back. For the gallery page, we will only need the filename and ids of the pictures and not the data. We will get the image data from the individual calls to the ShowPicture
action. For the Gallery view, we only need to render the filename and id (which we use to make the URL for image tag’s src
attribute).
AddPicture Post Action
This action is the meat of what we are doing, but is very simple. First, we use the HttpPostedFileBase
object that is passed in from the file type input control in the view. We check to make sure that we have a file there, then we get the file’s name. We will use this for the FileName
property of the MongoPictureModel
object we will create. Next, we get the content stream of the file passed in and convert it to an array of bytes. We then convert that array of bytes into a base64
encoded string
. We use this data for the PictureDataAsString
property of our MongoPictureModel
. We then take our newly created model and pass it to our “InsertPictureIntoDatabase
” function.
Make your way back to the index view for the gallery controller and edit it to match this…
@model List<MongoAndMVC.Models.MongoPictureModel>
@{
ViewBag.Title = "Gallery";
}
<h2>Gallery</h2>
@Html.ActionLink("Add a new Picture", "AddPicture")
@foreach (var pictue in Model)
{
<div>
@pictue.FileName<br />
<img src="@string.Format("/Gallery/ShowPicture/{0}",pictue._id.ToString())" alt="@pictue.FileName" />
</div>
}
In the same directory, create a view named AddPicture.cshtml for the AddPicture
actions with this…
@{
ViewBag.Title = "Upload an image";
}
<h2>Upload a new image</h2>
@Html.ActionLink("View Gallery", "Index")
<div>
@if (ViewBag.Message != null && ViewBag.Message != "")
{
@ViewBag.Message
}
</div>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" id="theFile" name="theFile" />
<br />
<button type="submit">Upload Image</button>
</form>
Also edit the layout.cshtml file in the shared folder under views and add a link to the index action of the gallery controller in the app’s navigation.
Let’s Test It Out
Alright, fire up your web app and traverse to the gallery controller by going to “localhost/Gallery”. You should get something like this:
As you can see, we do not have any images yet, but we will soon rectify that. Click the “Add a new Picture” link and it should take you to the “Add a New Picture” page.
Simply click the input control and select a jpeg image to upload. If everything goes good, you should get the “The image was updated successfully
” message from the AddPicture
’s http post action.
Click “View Gallery” and go back to the gallery page. You should see your newly uploaded image loaded straight from a mongo database.
Nice!
Additional Notes
- You should carefully review the MongoDB documentation to come up with a file storage mechanism that’s more suited to your needs. The
GridFS
specification has its advantages (like no 16MB size limit) as well as some disadvantages vs storing files directly in the document vs just storing them on the file system. - This is just a tutorial, but if you are going to use some kind of method of image retrieval and display similar to this, you will be wise to come up with strategies to help alleviate the load on the DB such as paging and server side caching.