Save image file content to Database with resizing (EF 4.1, SQLServer 2008 R2, MVC4)

File uploading is a very common task in nowadays specially with web applications. Normally what we do is we save the uploading files in the server-side. Recently, I have developed a software component which can be used to save images directly to a database table field(even with re-sizing if needed). For this module, I have used Entity Framework, Sql Server 2008 R2 and MVC4. How it has been achieved is described below.

Table – Content

table

Content table contains two fields FileName, FileContent and FIleType, which are nvarchar(64), varbinary(MAX) and nvarchar(64) respectively. The file contain was stored in FileContent field.

Entity Class – Content

public class Content : EntityBase
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Uid { get; set; }

    [StringLength(64)]
    [Display(Name = "File Name")]
    [Required]
    public string FileName { get; set; }

    [Required]
    public byte[] FileContent { get; set; }

    [StringLength(64)]
    [Display(Name = "File Type")]
    [Required]
    public string FileType { get; set; }

}

Entity Map – ContentMap

public class ContentMap : EntityTypeConfiguration<Entity.FileContent.Content>
{
    public ContentMap()
    {
        ToTable("Content");
        HasKey(t => t.Uid);
    }
}

Helper Class – ImageHelper 

I have implemented ToByteArray method as an extension method for HttpPostedFileBase. As this described if the image dimension is not meet your desired height or width it will be re-sized and stored.
public static class ImageHelper
{
    /// <summary>
    /// Checking whether the image needs to be resized
    /// </summary>
    /// <param name="uploadImage"></param>
    /// <param name="height"></param>
    /// <param name="width"></param>
    /// <returns>true or false depending on the size</returns>
    private static bool IsResizeNeeded(Image uploadImage, int height, int width)
    {
        var originalWidth = uploadImage.Width;
        var originalHeight = uploadImage.Height;
        return (originalHeight != height) || (originalWidth != width);
    }

    /// <summary>
    /// Resize the image depending on the size given
    /// </summary>
    /// <param name="uploadImage"></param>
    /// <param name="height"></param>
    /// <param name="width"></param>
    /// <returns></returns>
    private static Image ResizeBySize(Image uploadImage, int height, int width)
    {
        var originalWidth = uploadImage.Width;
        var originalHeight = uploadImage.Height;

        var modifiedHeight = height;
        var modifiedWidth = width;

        var bitmap = new Bitmap(modifiedWidth, modifiedHeight,
                                 PixelFormat.Format32bppPArgb);
        bitmap.SetResolution(uploadImage.HorizontalResolution, uploadImage.VerticalResolution);

        var graphics = Graphics.FromImage(bitmap);
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

        graphics.DrawImage(uploadImage,
                          new Rectangle(0, 0, modifiedWidth, modifiedHeight),
                          new Rectangle(0, 0, originalWidth, originalHeight),
                          GraphicsUnit.Pixel);

        graphics.Dispose();

        return bitmap;
    }

    /// <summary>
    /// Since we need the ImageFormat inorder to convert Image -> MemoryStream
    /// </summary>
    /// <param name="imageType"></param>
    /// <returns>ImageFormat according to the image type(Ex: jpg, jpeg etc.)</returns>
    private static ImageFormat GetImageFormat(string imageType)
    {
        ImageFormat imageFormat;
        switch (imageType)
        {
            case "image/jpg":
                imageFormat = ImageFormat.Jpeg;
                break;
            case "image/jpeg":
                imageFormat = ImageFormat.Jpeg;
                break;
            case "image/pjpeg":
                imageFormat = ImageFormat.Jpeg;
                break;
            case "image/gif":
                imageFormat = ImageFormat.Gif;
                break;
            case "image/png":
                imageFormat = ImageFormat.Png;
                break;
            case "image/x-png":
                imageFormat = ImageFormat.Png;
                break;
            default:
                throw new Exception("Unsupported image type !");
        }

        return imageFormat;
    }

    /// <summary>
    /// Convert files to byte array(Special function added for images which needs to be resized)
    /// </summary>
    /// <param name="fileUpLoad"></param>
    /// <returns>byte array of the image file</returns>
    public static byte[] ToByteArray(this HttpPostedFileBase fileUpLoad)
    {
        byte[] byteArray;

        if (IsImage(fileUpLoad))
        {
            //getting the height and width of the image to be uploaded
            var theHeight = Int32.Parse(WebConfigurationManager.AppSettings["UploadImageHeight"]);
            var theWidth = Int32.Parse(WebConfigurationManager.AppSettings["UploadImageWidth"]);

            //converting to a bitmap
            var uploadImage = new Bitmap(fileUpLoad.InputStream);

            //checking whether resize is needed
            if (IsResizeNeeded(uploadImage, theHeight, theWidth))
            {
                //resizing the image
                var resizedImage = ResizeBySize(uploadImage, theHeight, theWidth);
                //getting the image format(not the type)
                var resizedImageFormat = GetImageFormat(fileUpLoad.ContentType);

                using (resizedImage)
                {
                    using (var memoryStream = new MemoryStream())
                    {
                        //loading it to the memory stream
                        if (resizedImageFormat != null)
                        {
                            resizedImage.Save(memoryStream, resizedImageFormat);
                        }
                        memoryStream.Position = 0;
                        byteArray = memoryStream.ToArray();
                    }
                }
            }
            else
            {
                byteArray = ByteArrayConvertion(fileUpLoad);
            }
        }
        // for non-image files
        else
        {
            byteArray = ByteArrayConvertion(fileUpLoad);
        }

        return byteArray;
    }

    /// <summary>
    /// Default byte array creation
    /// </summary>
    /// <param name="fileUpload"></param>
    /// <returns>byte array</returns>
    private static byte[] ByteArrayConvertion(HttpPostedFileBase fileUpload)
    {
        byte[] byteArray;

        using (fileUpload.InputStream)
        {
            using (var memoryStream = new MemoryStream())
            {
                fileUpload.InputStream.CopyTo(memoryStream);
                byteArray = memoryStream.ToArray();
            }
        }
        return byteArray;
    }

    /// <summary>
    /// Checking the file is an image....
    /// </summary>
    /// <param name="fileUpload"></param>
    /// <returns>True if the file is an image</returns>
    /// http://yassershaikh.com/how-to-check-if-an-uploaded-file-is-an-image-or-not-in-asp-net-mvc-3/
    private static bool IsImage(HttpPostedFileBase fileUpload)
    {
        if (fileUpload.ContentType.Contains("image"))
        {
            return true;
        }

        var formats = new string[] { ".jpg", ".png", ".gif", ".jpeg" }; // add more if u like...

        // linq from Henrik Stenbæk
        return formats.Any(item => fileUpload.FileName.EndsWith(item, StringComparison.OrdinalIgnoreCase));
    }
}
Note: If you are hoping to store non-image files in DB, still it can be accomplished using ToByteArray extension method.
View
@using (Html.BeginForm("Upload", "ContentFile", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <input type="file" name="FileUpload" />
    <input type="submit" name="Submit" id="Submit" value="Upload" />
}
Controller – ContentFileController
I have used the extension method ToByteArray with the width and height parameters which obtained by web.config.
[HttpPost]
public ActionResult Upload(FileUploadModel fileUploadModel)
{
    HttpPostedFileBase file = Request.Files[0];

    if (file != null && file.ContentLength > 0)
    {
        //creating the content entity using repository
        Content fileUpload = _fileContentRepository.Create();
        fileUpload.FileName = Path.GetFileName(file.FileName);

        var extension = Path.GetExtension(file.FileName);
        if (extension != null)
            fileUpload.FileType = extension.TrimStart('.');

        //getting the height and width of the image to be uploaded
        var theHeight = Int32.Parse(WebConfigurationManager.AppSettings["UploadImageHeight"]);
        var theWidth = Int32.Parse(WebConfigurationManager.AppSettings["UploadImageWidth"]);

        fileUpload.FileContent = file.ToByteArray(theHeight, theWidth);

        _fileContentRepository.SaveOrUpdate(fileUpload);
        _unitOfWork.Commit();

    }

    var uploadedFiles = _fileContentRepository.GetAll();
    ViewData["UploadedFiles"] = uploadedFiles;

    return View(fileUploadModel);
}
View – Uploaded Files
@using DinotaMSM.Entity.FileContent
@using MvcContrib.UI.Grid
@using TekMVC.Models
@model FileUploadModel
@{
    ViewBag.Title = "Upload";
}

<div>
    @if (Model != null)
    {
        Html.Grid((IEnumerable<Content>) ViewData["UploadedFiles"])
            .Columns(column =>
                         {
                             column.For(c => @Html.ActionLink(c.Uid.ToString(), "GetFile", new {uid = c.Uid})).Named("ID");
                             column.For(c => c.FileName);
                             column.For(c => "<img src=" + string.Format("data:image/{0};base64,{1}", c.FileType, Convert.ToBase64String(c.FileContent)) + ">").Encode(false);
                         }).Render();
    }
</div>
Output
output

Accessing WCF Service via Android (WCF, EF 4.1, SQLServer 2008 R2, Android, Gson)

Recent past as an R&D Project I was working on a prototype basis Shopping cart application (assuming that the end-users are always in a connected environment-WiFi/3G) which has no local database so that it had to interact with WCF Service for data-manipulation.

WCF Service, data handling section was developed using Entity Framework(Code First approach). There were several modules like Item, Category, Order etc. Among those I picked Item module for further explanation.

Entity Class – Item

public class Item
{
	public string Id { get; set; }

	public string Name { get; set; }

	public string Url { get; set; }

	public int InStock { get; set; }

	public decimal Price { get; set; }
}

Entity Map – ItemMap

public class ItemMap : EntityTypeConfiguration<Item>
{
	public ItemMap()
	{
		ToTable("tbl_Item");
		HasKey(item => item.Id);
	}
}

Repository – ItemRepo

public class ItemRepo
{
    protected IDbSet<Item> ItemSet;
    protected DataContext Context;

    public ItemRepo(DataContext dataContext)
    {
        Context = dataContext;
        ItemSet = dataContext.Set<Item>();
    }

    public List<Item> GetItems(string from, string to)
    {
        IEnumerable<Item> items = (from a in ItemSet
                                   select a).OrderBy(a => a.Id).Skip(Convert.ToInt32(from)).Take(Convert.ToInt32(to));

        return items.ToList();
    }
}

WCF Service Method

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class Html5Service
{
    [OperationContract]
    [WebGet(ResponseFormat = WebMessageFormat.Json)]
    public List<Item> GetItems(string From, string To)
    {
        var itemRepo = new ItemRepo(new DataContext());
        return itemRepo.GetItems(Convert.ToInt32(From), Convert.ToInt32(To));
    }
}

Client(Android) side implementation was as follows.

You have to access the WCF Service with a similar function like below. I have used a third party library called gson-1.7.1(not the latest one), which can be downloaded from the below link.
download google-gson

Item-Mapping [since my mapping properties had the same name with compared to the json result item list, i have not used the SerializedName annotation]

Class – Item

public class Item{

	private String Id;
	private String Name;
	private String Url;
	private int InStock;
	private Double Price;

	public String getId() {
		return Id;
	}
	public void setId(String id) {
		Id = url;
	}

	public String getName() {
		return Name;
	}
	public void setName(String name) {
		Name = name;
	}

	public String getUrl() {
		return Url;
	}
	public void setUrl(String url) {
		Url = url;
	}

	public int getInStock() {
		return InStock;
	}
	public void setInStock(int inStock) {
		InStock = inStock;
	}

	public Double getPrice() {
		return Price;
	}
	public void setPrice(Double price) {
		Price = price;
	}
}

WCF Service call

public List<Item> getItems(String from, String to) {

	List<Item> items = null;
	Gson gson = new Gson();

	try {

		String urlWithParam = String.format("http://app.dinotait.com/Items/HTML5Service.svc/GetItems?From=%s&To=%s",from, to);

		HttpGet request = new HttpGet(urlWithParam);

		request.setHeader("Accept", "application/json");
		request.setHeader("Content-type", "application/json");

		DefaultHttpClient httpClient = new DefaultHttpClient();
		HttpResponse response = httpClient.execute(request);

		HttpEntity responseEntity = response.getEntity();

		// Read response data into buffer
		char[] buffer = new char[(int) responseEntity.getContentLength()];
		InputStream stream = responseEntity.getContent();
		InputStreamReader reader = new InputStreamReader(stream);
		reader.read(buffer);
		stream.close();

		Type type = new TypeToken<List<Item>>(){}.getType();
		items = gson.fromJson(new String(buffer), type);

	} catch (Exception e) {
		e.printStackTrace();
	}

	return items;
}

Remember that you have to execute this function within an AsyncTask or similar approach since this is a network operation.