Using LINQ, when working with images in Web Application


In our ASP.NET applications we often need to create some pages to upload, edit, delete and of course just to see images (this is: pulling these images out of our database) etc. To do all these operations with help of LINQ and ObjectDataSourse is simple enough. In this article I will explain how you can use LINQ, when working with images in Web Application. For best understanding we will work with the small project, named Image_WA. Ok, let's start.

First of all we create ASP.Net Web Application project and add to it SQL Server Database (fig. 1) :

Image_f1.JPG

Fig. 1.

Then we create a table for storing our images (fig. 2):

Image_f2.JPG

Fig. 2.

As you can see, the table has seven columns (of corresponding Data Type), that allow to store all information about our images. The column ForeingNum we use as "connection" with another table (this is just foreign key for some table. Let's assume, you store images of some rock groups; in this case all images of Deep Purple have to have, for example, ForeingNum = 11; Pink Floyd, for example, - 12 and so on. Of course, you have to have some table RockGroups with the PrimaryKey 11, 12 etc.).

Now, we add to our project dbml file (LINQ to SQL Class), named ImageDal. It will be our data access layer (Dal). All our business logic we put into ImageBL class. Of course, we can create special BL and Dal project, but our project is small enough, and there is no need to create special projects. With the drag/drop operation we create Data Class Image (fig. 3):

Image_f3.JPG

Fig. 3.

To retrieve and then display our image dynamically we can use just aspx file or the Handler class (ashx file). As usually, for binary file (this is: our images) it's recommended to use the Handler class, but we will give example for both: aspx and ashx files (by the way, about the Handler you can read: "What is an ASHX file Handler or web handler" by Purushottam Rathore). With this purpose we add to our project WebFormHandlerImage.aspx and ImageHandler.ashx (again, in fact we have to use only one of them). Now our project looks so (fig. 4) and we are ready to add code to the pages and classes.

Image_f4.JPG

Fig. 4.

OK! Our ImageHandler has ProcessRequest method. We change two lines of the code (which this method has by default) to the following:

public void ProcessRequest(HttpContext context)
{
    ////context.Response.ContentType = "text/plain";
    ////context.Response.Write("Hello World");
    ImageDalDataContext dc = new ImageDalDataContext();
    int imageNum = int.Parse(context.Request.Params["biNum"].ToString());
    var bdi = from bi in dc.Images
              where bi.ImageNum.Equals(imageNum)
              select bi;
    context.Response.ContentType = bdi.First().ImageType.ToString();
    context.Response.BinaryWrite((byte[])(bdi.First().Img.ToArray()));
}


If you use, for some reasons, WebFormHandlerImage.aspx, then add the following lines of code:


protected void Page_Load(object sender, EventArgs e)

{

    ProcessImages();

}


private void ProcessImages()

{

    ImageDalDataContext dc = new ImageDalDataContext();

    int imageNum = int.Parse(Request.Params["biNum"].ToString());

    var bdi = (from i in dc.Images

               where i.ImageNum.Equals(imageNum)

               select i).First();

    Response.Clear();

    Response.ContentType = bdi.ImageType.ToString();

    Response.BinaryWrite((byte[])(bdi.Img.ToArray()));

    ////--------or lamda-----

    //ImageDalDataContext dc = new ImageDalDataContext();

    //int imageNum = int.Parse(Request.Params["biNum"].ToString());

    //var bdi = dc.Images.Where(i => i.ImageNum.Equals(imageNum)).First();

    //Response.Clear();

    //Response.ContentType = bdi.ImageType.ToString();

    //Response.BinaryWrite((byte[])(bdi.Img).ToArray());

    ////------------------

}


To our ImageBL class we have to add at least methods to update data of some image, insert some new data or delete, if necessary, already available data. We have to have some method to get images with the same ForeignNum (see fig. 2). All our adding will look so:


[DataObject]

public static class ImageBL

{

    [DataObjectMethod(DataObjectMethodType.Select, true)]

    public static DataTable GetImages(int foreignNum)

    {

        ImageDalDataContext dc = new ImageDalDataContext();

        var bi = from b in dc.Images

                 where b.ForeignNum.Equals(foreignNum)

                 select b;

        return ListToTable<Image>(bi.ToList());

    } 


    [DataObjectMethod(DataObjectMethodType.Update, false)]

    public static string UpdateImage(Image original_obj, Image obj)

    {

        string result = string.Empty;

        try

        {

            ImageDalDataContext dc = new ImageDalDataContext();

            obj.LastUpdate = DateTime.Now;

            Image bi = dc.Images.Single(p => p.ImageNum.Equals(obj.ImageNum));

            bi.ImageName = obj.ImageName;

            dc.SubmitChanges();

        }

        catch (ChangeConflictException e)

        {

            result = e.Message;

        }

        return result;

    }


    [DataObjectMethod(DataObjectMethodType.Delete, false)]

    public static string DeleteImage(Image obj)

    {

        string result = string.Empty;

        try

        {

            ImageDalDataContext dc = new ImageDalDataContext();

            Image bi = dc.Images.Single(p => p.ImageNum.Equals(obj.ImageNum));

            dc.Images.DeleteOnSubmit(bi);

            dc.SubmitChanges();

        }

        catch (ChangeConflictException e)

        {

            result = e.Message;

        }

        return result;

    }


    [DataObjectMethod(DataObjectMethodType.Insert, false)]

    public static string InsertImage(Image obj)

    {

        string result = string.Empty;

        try

        {

            ImageDalDataContext dc = new ImageDalDataContext();

            dc.Images.InsertOnSubmit(obj);

            dc.SubmitChanges();

        }

        catch (ChangeConflictException e)

        {

            result = e.Message;

        }

        return result;

    }

    private static DataTable ListToTable<T>(List<T> list)

    {

        DataTable dt = new DataTable();

        if (list.Count > 0)

        {

            PropertyInfo[] propInfo = list[0].GetType().GetProperties();

            List<string> columns = new List<string>();

            foreach (PropertyInfo propertyInfo in propInfo)

            {

                dt.Columns.Add(propertyInfo.Name);

                columns.Add(propertyInfo.Name);

            }

            foreach (T item in list)

            {

                object[] row = getRow(columns, item);

                dt.Rows.Add(row);

            }

        }

        return dt;

    }

    private static object[] getRow(List<string> columns, object propertyValue)

    {

        object[] row = new object[columns.Count];

        int i = 0;

        for (i = 0; i < row.Length; i++)

        {

            PropertyInfo pi = propertyValue.GetType().GetProperty(columns[i]);

            object value = pi.GetValue(propertyValue, null);

            row[i] = value;

        }

        return row;

    }

}


As you can see our GetImages method returns DataTable type. To convert List to DataTable we use method ListToTable. Of course, you can write your own method or use, for example, article "Convert a LINQ Query Resultset to a DataTable" by Vimal Lakhera. The methods UpdateImage, InsertImage and DeleteImage return a message (as string) in the case of exception and you can use it as you want.


Well, now we add some controls to our Default.aspx page, such as: GridView, FileUpload, Label, ObjectDataSource etc. (see fig. 5):


Image_f5.JPG


Fig. 5.

Of course, the ObjectDataSourceDGVGeneral control is chosen as DataSource of our GridView control. We configure the DataSource so, that we get the parameter foreignNum with the help of the HiddenFielNum (you can choose your own way):

Image_f6.JPG


Fig. 6.

Now we write some code to upload image and get foreingnNum on Page_Load event:


public partial class _Default : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

        PageLoad();

    }

    private void PageLoad()

    {

        if (!IsPostBack)

        {

            HiddenFieldNum.Value = Request.Params["btNum"];

        }

    }

    protected void ButtonNewImage_Click(object sender, EventArgs e)

    {

        Image bi = GetImage();

        if (bi != null)

        {

            ImageBL.InsertImage(bi);

            GridViewGeneral.DataBind();

        }

    }

    private Image GetImage()

    {

        int fileLength = FileUploadImage.PostedFile.ContentLength;

        Image bi = new Image();

        if (FileUploadImage.HasFile && fileLength > 0)

        {

            byte[] fileLoad = FileUploadImage.FileBytes;

            ImageDalDataContext dc = new ImageDalDataContext();

            FileUploadImage.PostedFile.InputStream.Read(fileLoad, 0, fileLength);

            Binary imageLoad = new Binary(fileLoad);

            bi.ForeignNum = GetNum();

            bi.Img = imageLoad;

            bi.ImageName = TextBoxImageName.Text.Trim();

            bi.ImageSize = fileLength;

            bi.ImageType = FileUploadImage.PostedFile.ContentType;

            bi.LastUpdate = DateTime.Now;

            return bi;

        }

        else

        {

            return null;

        }

    }

    private int GetNum()

    {

        return int.Parse(HiddenFieldNum.Value.Trim());

    }

}


One more step. We have to change at least one column of our GridView to TemplateField type in order to get our image for this column (here our HandlerImageHandler/ WebFormHandlerImage come):


<asp:TemplateField HeaderText="Photos">

    <ItemTemplate>

        <asp:Image ID="Image1" runat="server"

            ImageUrl='<%# "ImageHandler.ashx?biNum=" + Eval("ImageNum")%>' />

    </ItemTemplate>

</asp:TemplateField>


As for me, I have also changed column of the image's description (Name) in order to have MultiLinetextMode of the textBox :


<asp:TemplateField HeaderText="Name" SortExpression="ImageName">

    <ItemTemplate>

        <asp:Label ID="Label1" runat="server" Text='<%# Bind("ImageName") %>'

            Width="120px"></asp:Label>

    </ItemTemplate>

    <EditItemTemplate>

        <asp:TextBox ID="TextBox1" runat="server" Rows="5"

Text='<%# Bind("ImageName") %>' TextMode="MultiLine" Width="120px"></asp:TextBox>
    </EditItemTemplate>
</asp:TemplateField>


OK! Our project is ready to run. We can create our photo's collection and edit it. And our first photo will be, of course, logo of the site:


Image_f7.JPG



Good luck in programming !


Similar Articles