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) :
Fig. 1.
Then we create a table for storing our images
(fig. 2):
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):
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.
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):
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):
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:
Good luck in programming !