[MVC 3] Images – Downloading Images


UPDATE: I have now combined all my MVC Image Handling  blog posts into a Open Source Project. Feel free to check this out once you have read the post.

http://mvcimage.codeplex.com/

Original Blog Post:

The previous posts i have shown you how to upload images, and use JQuery to preview the image. We have also used Entity Framework 4.0 and SQL to save a image as a varbinary data type.

Now I’m going to show you how to download the image, and display it on your view, using a HTML Helper.

Before we start lets think about what we need:

  • HTML Helper Extension to help display the image
  • Controller classes to grab the image
  • Object validation methods

Lets start with the code for the HTML Helper Extension. You should be familiar with how these work now. Again, mine is to accept a model using Lambda expressions:

public static MvcHtmlString DisplayImageFor<TModel, TProperty>    (this HtmlHelper<TModel> helper,
    Expression<Func<TModel, TProperty>> expression, string alt = null,     string action = null string controller= null, string actionParameterName = null,string height = null, string width = null)
{

    if (String.IsNullOrEmpty(alt)){
        string _name = ExpressionHelper.GetExpressionText(expression);
        alt = helper.ViewContext.ViewData.TemplateInfo.        GetFullHtmlFieldName(_name);
    }

    if (String.IsNullOrEmpty(height)){
        height = "126px";
    }

    if (String.IsNullOrEmpty(width)){
        width = "126px";
    }

    if(String.IsNullOrEmpty(actionParameterName)){
        actionParameterName = "id";
    }

    ///---Set the default src settings if null 
 ///--- src element is made up of action, controller and acionParameterName 
 if (String.IsNullOrEmpty(action)){
        action = "GetImage";

    }

    if (String.IsNullOrEmpty(controller)){
        controller = "ImagePreview";
    }

    ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression,     helper.ViewData);
    Object value = metadata.Model;
    Type valueType = metadata.Model.GetType();
string src = null;

    if(ObjectValidation.IsStringType(valueType))
    {
        src = String.Format(CultureInfo.InvariantCulture,
        "/{0}/{1}/{2}",controller,action,value);
    }

    var imgBuilder = new TagBuilder("img");

    imgBuilder.MergeAttribute("alt", alt);
    imgBuilder.MergeAttribute("src", src);
    imgBuilder.MergeAttribute("height", height);
    imgBuilder.MergeAttribute("width", width);

    return MvcHtmlString.Create(imgBuilder.ToString(TagRenderMode.SelfClosing));

}

So in a nutshell:

  1. If the parameters are null we set up the default values for the HTML Elements.
  2. build the metadata from the ViewData dictionary. We can then load the metadata.Model data to an Object, i.e. the value of the model.
  3. We build the src element to include the link of the controller we will build later to get the image.
  4. We use again to build the HTML Elements.
  5. The alt element will end up being the models name if there isn’t a parameter passed, for e.g.
     1: <img width="126" height="126" alt="property.UniqueKey" src="/ImagePreview/GetImage/b8b03b6d-e30c-46d6-9cba-002f3a4699ee"/>

     

You will notice we have used a static method, ObjectValidation.IsStringType. This has been built to allow me to query the object type. I need this so i can make sure the parameter I’m passing to the controller is a String. Here is how i have implemented this:

public static bool IsStringType(Type type)
{
    if (type == null)
    {
        return false;
    }

    switch (Type.GetTypeCode(type))
    {
        case TypeCode.String:
            return true;

        case TypeCode.Object:
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                return IsStringType(Nullable.GetUnderlyingType(type));
            }

            return false;

    }

    return false;
}

Quite  a simple class, which passes the type of the object (Previously we used .GetType() to achieve this), then we test to see if the equals String. If it does, we return true.

The other check is if the object is generic and Nullable, we pass the underlying type back through to the IsStringType method.

We have now built our HTML Helper and our Object Validation method, now onto our GetImage action method we set in the src element.

        #region GetImage
        public ActionResult GetImage(Guid id)
        {
            //Guid ID = new Guid(id); Medium profileimage = new Medium();

            try {
                int count = db.Media.Count(c => c.Unique_Key == id);

                if(count > 0)
                {
                    profileimage =  db.Media.SingleOrDefault(i => i.Unique_Key == id);
                    //--Convert the Image data into Memory. 
 byte[] imagedata = profileimage.Source;
                    return File(imagedata, profileimage.Content_Type, profileimage.File_Name);

                }

                count = 0;
                count = db.Media.Count(c => c.Table_Link == id);

                if (count > 0)
                {
                    profileimage = db.Media.SingleOrDefault(i => i.Table_Link == id);
                    //--Convert the Image data into Memory. 
 byte[] imagedata = profileimage.Source;
                    return File(imagedata, profileimage.Content_Type, profileimage.File_Name);
                }

                return File(new byte[0], null);
            }
            finally {
                if (db != null)
                    db.Dispose();

            }

        }

        #endregion 

This controller method contains alot of my own bespoke business logic in obtaining the image. Which is why i do 2 checks.

Enhanced by Zemanta

2 thoughts on “[MVC 3] Images – Downloading Images

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s