Saving and retrving image from mysql - c#

In C#, I am trying to save and load an image. I am saving it into a mysql database (type longblob) and trying to load it back into an picture box. The problem i keep getting is the error "Parameter is not valid", see code below
ConnectionClass Sqlconnection = new ConnectionClass();
Sqlconnection.ConnectionOpen();
OdbcCommand cmd = new OdbcCommand("Insert into pictest(pic) values('"+ Encoding.Unicode.GetBytes(richTextBox1.Rtf) + "')", Sqlconnection.connection);
int num = cmd.ExecuteNonQuery();
MessageBox.Show(num + " Rows inserted ");
Sqlconnection.ConnectionClose();
OdbcDataReader rd = null;
try
{
Sqlconnection.ConnectionOpen();
string query = "select * from pictest where id = 1";
cmd = new OdbcCommand(query, Sqlconnection.connection);
rd = cmd.ExecuteReader();
if (rd.Read())
{
byte[] bytes = (byte[])rd[1];
ImageConverter converter = new ImageConverter();
pictureBox1.Image = Image.FromStream(new MemoryStream(bytes)); <--Parameter is not valid
pictureBox1.Refresh();
pictureBox1.Image = Encoding.Unicode.GetString(bytes);
}
Sqlconnection.ConnectionClose();
rd.Close();
}
catch (Exception asd)
{
MessageBox.Show("Problem " + asd.Message);
Sqlconnection.ConnectionClose();
if (rd != null)
{
rd.Close();
}
}
what exact is the problem? Is the image not saving correctly? it should be as it is saving to a longblob. The record for the image says System.Byte[]

you should be able to inspect (via the debugger) the values inside OdbcDataReader before trying to cast the first field to byte[]. Take a look at what type is actually stored in the OdbcDataReader
Using SELECT * is problematic performance wise. It also leaves your rd[1] up for interpretation. If the order of columns ever changes, your code could break. Use rd["your_column_name"] to access the values. As of right now I can't tell if index 1 is correct due to the SELECT * and non-named indexing into the Items array.

First of all why you need to store image in MySql?
Why not in physical drive? If its not a crucial data go for saving it in physical drive.
However, here is code to retrieve:
public byte [] getImage(int imageNumber)
{
string strSql = "SELECT * FROM File";
DataSet ds = new DataSet("Image");
OdbcDataAdapter tempAP = new OdbcDataAdapter(strSql,this._objConn);
OdbcCommandBuilder objCommand = new OdbcCommandBuilder(tempAP);
tempAP.Fill(ds,"Table");
try
{
this._objConn.Open();
byte [] buffer = (byte [])ds.Tables["Table"].Rows[imageNumber]["Data"];
return buffer;
}
catch{this._objConn.Close();return null;}
finally{this._objConn.Close();}
}
Courtesy:
http://www.codeproject.com/Articles/6750/Storing-Images-in-MySQL-using-ASP-NET
For physical drive
http://www.codeproject.com/Articles/2113/C-Photo-Album-Viewer

Related

MySql.Data.MySqlClient.MySqlException: 'GetBytes can only be called on binary or guid columns'

I'm developing an app in C# with .NET and MySQL database. I need to be able to insert and retrieve images in and out of the database and I have a column named 'Image' of type LONGBLOB for that purpose. The insertion goes well but when I try to retrieve the blob the following error pops up:
GetBytes() can only be called on binary or GUID columns
I'm using the following code to select from the database:
con.Open();
string query = "select `Image`, `Name`, `Type`, `Price`, `Description` from `product`";
MySqlCommand cmd = new MySqlCommand(query, con);
MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
long len = reader.GetBytes(1,0,null,0,0);
byte[] array = new byte[len + 1];
reader.GetBytes(0, 0, null, 0, 0);
PictureBox pic = new PictureBox();
pic.Width = 100;
pic.Height = 100;
pic.BackgroundImageLayout = ImageLayout.Stretch;
flowLayoutPanel2.Controls.Add(pic);
}
reader.Close();
con.Close();
Despite changing the column type into binary and varbinary, I still got the same error.
Does anyone know what I'm doing wrong here?

Updating database Image just stores 0x

I have a table that stores information of users, which is filled by loading a XML file.
In that table, I have an Image type column that is for all users set as "null" in the XML file.
The problem comes when I try to update that column and set an image, it just stores "0x".
This is the table:
create table User(
ID INTEGER PRIMARY KEY,
name VARCHAR(50),
foto IMAGE,
email VARCHAR(100))
This is my update code:
protected void addFoto_Click(object sender, EventArgs e)
{
Byte[] imgByte = null;
if (file_upload.PostedFile != null)
{
HttpPostedFile File = file_upload.PostedFile;
File.InputStream.Position = 0;
imgByte = new Byte[File.ContentLength];
File.InputStream.Read(imgByte, 0, File.ContentLength);
}
string sql = "update User set foto = #foto where email= #email";
using(SqlCommand cmd = new SqlCommand(sql, con.getConexion()))
{
cmd.Parameters.AddWithValue("#email", Txtemail.Text.ToString());
cmd.Parameters.AddWithValue("#foto", imgByte);
con.open();
cmd.ExecuteNonQuery();
con.close();
}
}
I tried adding
File.InputStream.Position = 0;
as the answer in this post, but still didn't work.
Can't save byte[] array data to database in C#. It's saving 0x
I also tried with the column type VARBINARY(MAX) with this code:
string sql = "update User set foto = #foto where email= #email";
using (SqlCommand cmd = new SqlCommand(sql, con.getConexion()))
{
Stream fs = file_upload.PostedFile.InputStream;
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = br.ReadBytes((Int32)fs.Length);
cmd.Parameters.AddWithValue("#email", Txtemail.Text.ToString());
cmd.Parameters.Add("#foto", SqlDbType.Binary).Value = bytes;
con.open();
cmd.ExecuteNonQuery();
con.close();
}
Which just stored 0x000000... And finally, I also tried adding directly an image with:
System.Drawing.Image imag = System.Drawing.Image.FromStream(file_upload.PostedFile.InputStream);
cmd.Parameters.Add("foto", SqlDbType.Binary, 0).Value = ConvertImageToByteArray(imag, System.Drawing.Imaging.ImageFormat.Jpeg);
with no result.
Here are the values of the file_upload while debugging:
I find it odd that it has a posted file but no bytes...
If anyone can please tell me what I'm doing wrong I would be really grateful, and also excuse me if my English is not perfect.
The problem was that I was doing in the Page_Load a PostBack that refreshed the page in order to show the file's name, but at the same time it reset the PostedFile to nothing.
My solution was to make a global HttpPostedFile variable that stores the posted file in the PostBack for future usage.

Saving multiple Images at once to the database with a FileUpload Control

I am working on a company Blog site, and when a user is making a post, they can add an image from their computer to the post. I used a FileUpload control to do this, and it works great. However, I am trying to change the functionality to allow the user to select and upload multiple images in one post, and I am running into some issues. I have set the 'allow multiple' property to 'true', however once multiple images are selected into the control (Image URLs get separated by a comma) and the post button is clicked, only one of the images is inserted into the database, but it is inserted as many times as images there are, and only that one image is displayed on the blog post. So if I try to add three different images, it inserts three instances of the first image into the database. The code corresponding to the the FileUpload in my onClick function is below:
if (imageUpload.HasFile == true)
{
SqlCommand maxMessId = new SqlCommand("SELECT Max(MessageID) FROM BlogMessages", conn);
lastMessageID = Convert.ToInt32(maxMessId.ExecuteScalar());
foreach (var uploadedFile in imageUpload.PostedFiles)
{
SqlCommand cmdInsertImage = new SqlCommand("INSERT INTO BlogImages(Image, MessageID) VALUES (#Image, #MessageID)", conn);
cmdInsertImage.Parameters.AddWithValue("#Image", SqlDbType.Image).Value = imageUpload.FileBytes;
cmdInsertImage.Parameters.AddWithValue("#MessageID", lastMessageID);
cmdInsertImage.ExecuteNonQuery();
}
}
I am thinking the issue could be with:
cmdInsertImage.Parameters.AddWithValue("#Image", SqlDbType.Image).Value = imageUpload.FileBytes;
If that is getting the file bytes for only one image.. I am not sure how to get the filebytes for both files. The image column in my BlogImages table is of the type Image.
Any suggestions are much appreciated!
Are you sure that you're working on the right way ?????PostesFiles are the list of file and each one has it own properties you need to read from there.....nothing else
Here a simples examples
For Each xx In fp.PostedFiles
xx.InputStream
xx.ContentLength
xx.FileName
Next
Where those properties upon expose Inputstrem a stream of the image,ContenteLenght it lenght, Filename the filename of the images.So when you pass the imageupload.FileBytes is not the correct way to achive your goal.You have to read the stream and return a bytearray to save the data withing your sql server.Nothing else i hope it could help you to solve your issue.
UPDATE*
Assume that you're into the foreach loop for each single file you have to setup its own bytearray
MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();
then
change your insert statement like this
cmdInsertImage.Parameters.AddWithValue("#Image", SqlDbType.Image).Value = byts;
not tested but it should solve the issue.
UPDATE 2
if (test.HasFiles) {
StringBuilder sb = new StringBuilder();
foreach (void el_loopVariable in test.PostedFiles) {
el = el_loopVariable;
sb.AppendLine("FILENAME:<B>" + el.FileName.ToString + "</B><BR/>");
MemoryStream ms = new MemoryStream();
el.InputStream.CopyTo(ms);
byte[] byts = ms.ToArray;
ms.Dispose();
sb.AppendLine(string.Join(";", byts));
sb.AppendLine("<br/<br/>");
byts = null;
}
LitResponse.Text = sb.ToString;
}
I think the issue is that in your for each loop, you're stepping through the posted files, but you're still just using ImageUpload.FileBytes each time, which I expect would be returning the same thing each time.
I'm not super familiar with the file upload control, but maybe you can use the ContentLength property of your uploaded file object to index into the byte array returned by ImageUpload.FileBytes (assuming that array contains each of the multiple files).
protected void btnSubmit_Click(object sender, EventArgs e)
{
string strImageName = txtImage.Text.ToString(); //to store image into sql database.
if (FileUpload1.PostedFile != null &&
FileUpload1.PostedFile.FileName != "")
{
byte[] imageSize = new byte[FileUpload1.PostedFile.ContentLength];
HttpPostedFile uploadedImage = FileUpload1.PostedFile;
uploadedImage.InputStream.Read(imageSize, 0, (int)FileUpload1.PostedFile.ContentLength);
// Create SQL Command
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "INSERT INTO Pictures(ID,ImageName,Image)" +
" VALUES (#ID,#ImageName,#Image)";
cmd.CommandType = CommandType.Text;
cmd.Connection = conn;
//retrieve latest ID from tables which was stored in session.
int ID = Convert.ToInt32(System.Web.HttpContext.Current.Session["ID"].ToString());
SqlParameter ID = new SqlParameter
("#ID", SqlDbType.Int, 5);
ID.Value = (Int32)ID;
cmd.Parameters.Add(ID);
SqlParameter ImageName = new SqlParameter
("#ImageName", SqlDbType.VarChar, 50);
ImageName.Value = strImageName.ToString();
cmd.Parameters.Add(ImageName);
SqlParameter UploadedImage = new SqlParameter("#Image", SqlDbType.Image, imageSize.Length);
UploadedImage.Value = imageSize;
cmd.Parameters.Add(UploadedImage);
conn.Open();
int result = cmd.ExecuteNonQuery();
conn.Close();
if (result > 0)
lblMessage.Text = "File Uploaded";
lblSuccess.Text = "Successful !";
}}

How do I compare byte file if exist in database using query?

I want to check if file exist in database or not using asp.net. I searched about that but I didn't find comparing with byte file.
I used Visual Studio 2010, SQL Server 2008 and C# language .
So, I tried to write this code but display error:
Incorrect syntax near 'System.Byte[])'.
Also, is there anther solution about this problem ?
code
if (ext == ".doc" || ext == ".docx" || ext == ".pdf" || ext == ".txt")
{
Stream fs = FileUpload1.PostedFile.InputStream;
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = br.ReadBytes((Int32)fs.Length);
//insert the file into database
strQuery = "insert into [Text File](User_id, T_Title, T_Extension, T_Data, Course_code, Course_num, T_Description, T_Keyword,Date)" +
" values (#User_id, #T_Title, #T_Extension, #T_Data, #Course_code, #Course_num, #T_Description, #T_Keyword, #Date)";
SqlCommand cmd = new SqlCommand(strQuery);
cmd.Parameters.Add("#User_id", (string)Session["ID"]);
cmd.Parameters.Add("#T_Title", SqlDbType.VarChar).Value = filename;
cmd.Parameters.Add("#T_Extension", SqlDbType.VarChar).Value = ext;
cmd.Parameters.Add("#T_Data", SqlDbType.VarBinary).Value = bytes;
strQueryCount = "select count(*) from [Text File] where T_Data.SequenceEqual ('" + bytes + ")'";
cmd.Parameters.Add("#Date", SqlDbType.DateTime).Value = DateTime.Now;
cmd.Parameters.Add("#Course_code", Course_code.SelectedItem.Text);
cmd.Parameters.Add("#Course_num", Course_num.SelectedItem.Text);
cmd.Parameters.Add("#T_Description", Description.Text);
cmd.Parameters.Add("#T_Keyword", keywords.Text);
InsertUpdateData(cmd, bytes, strQueryCount);
}
private Boolean InsertUpdateData(SqlCommand cmd, Byte[] bytes, string strQueryCount)
{
String strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
SqlConnection con = new SqlConnection(strConnString);
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
try
{
con.Open();
command = new SqlCommand(strQueryCount, con);
int num = Convert.ToInt16(command.ExecuteScalar());
Label2.Text = num.ToString();
if (num == 0)
{
cmd.ExecuteNonQuery();
return true;
}
else
{
Label2.ForeColor = System.Drawing.Color.Red;
Label2.Text = "error ";
Description.Text = " ";
keywords.Text = " ";
Course_code.SelectedItem.Text = " ";
Course_num.SelectedItem.Text = " ";
return false;
}
}
catch (Exception ex)
{
Response.Write(ex.Message);
return false;
}
finally
{
con.Close();
con.Dispose();
}
}
Thanks..
You cannot compare files in byte stream as we do on other data types. You can generate some unique values for a file like hash or check-sum and store it along with byte stream in DB, which can be used to check for whether the file exists or not. Normally these mechanisms are not used for this. This only works if file contents are exactly the same. Even the slightest of variation will be failed to identify the match.
OR alternatively, you can decide to store some alternate information like we normally do. Like file name or user-based validations to check whether the file exists.
EDIT:
You can find hash like
string hash;
using(SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
{
hash = Convert.ToBase64String(sha1.ComputeHash(byteArray));
}
see it here
I agree, as suggested in above post, you can maintain hash to manage file comparing.
Since you asked how to compare using query, i am adding one more suggestion here.
Write a function in C# to get MD5 hash. Following is the code for function.
public static string GetMD5Hash(string input)
{
System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
bs = x.ComputeHash(bs);
System.Text.StringBuilder s = new System.Text.StringBuilder();
foreach (byte b in bs)
{
s.Append(b.ToString("x2").ToLower());
}
return s.ToString();
}
So get MD5 hash of file, and then using HASHBYTES('MD5', VarbinaryColumn)), you can compare values . This will work,because you will have MD5 hash generated C# and used HASHBYTES in SQL server to compare.
You can also do other type hashing like SHA1 in SQL server as well as C# side.
More on hashbytes - http://codepieces.tumblr.com/post/31006268297/sql-server-hashbytes-function-and-net-hashing-md5
Again, this has same limitation, slight change in content implies mismatch between posted file and stored file in SQL .

upload new file first check if this file exist already in database or not then if not exist save that in database

I'm trying to create sql database that contains
Image Id (int)
Imagename (varchar(50))
Image (image)
and in aspx write in upload button this code:
protected void btnUpload_Click(object sender, EventArgs e)
{
//Condition to check if the file uploaded or not
if (fileuploadImage.HasFile)
{
//getting length of uploaded file
int length = fileuploadImage.PostedFile.ContentLength;
//create a byte array to store the binary image data
byte[] imgbyte = new byte[length];
//store the currently selected file in memeory
HttpPostedFile img = fileuploadImage.PostedFile;
//set the binary data
img.InputStream.Read(imgbyte, 0, length);
string imagename = txtImageName.Text;
//use the web.config to store the connection string
SqlConnection connection = new SqlConnection(strcon);
connection.Open();
SqlCommand cmd = new SqlCommand("INSERT INTO Image (ImageName,Image) VALUES (#imagename,#imagedata)", connection);
cmd.Parameters.Add("#imagename", SqlDbType.VarChar, 50).Value = imagename;
cmd.Parameters.Add("#imagedata", SqlDbType.Image).Value = imgbyte;
int count = cmd.ExecuteNonQuery();
connection.Close();
if (count == 1)
{
BindGridData();
txtImageName.Text = string.Empty;
ScriptManager.RegisterStartupScript(this, this.GetType(), "alertmessage", "javascript:alert('" + imagename + " image inserted successfully')", true);
}
}
}
When I'm uploading a new image I need to first check if this image already exists in database and if it doesn't exist save that in database.
Please how I can do that?
Add a method that is responsible for checking if the filename already exists in the table.
private bool FileExists(string imageName)
{
using (SqlConnection conn = new SqlConnection()) // establish connection
{
using (SqlCommand cmd =
new SqlCommand("select 1 where exists(select Id from Image where ImageName = #)", conn))
{
cmd.Parameters.Add("#imagename", SqlDbType.VarChar, 50).Value = imageName;
return cmd.ExecuteNonQuery() > 0;
}
}
}
Then I would call this like so
if (fileuploadImage.HasFile && !FileExists(txtImageName.Text))
{
...
string cmd ="if not exists (select * from Image where ImageName= #imagename); ";
\\if you want to check image data
\\ (select * from Image where SUBSTRING(ImageName, 1, 8000)= SUBSTRING(#imagename, 1, 8000) );
string cmd += "INSERT INTO Image (ImageName,Image) VALUES (#imagename,#imagedata)";
SqlCommand cmd = new SqlCommand(cmd, connection);
If you want to verify imagedata, You can try to use DATALENGTH as first line of check for the two images.
If the DATALENGTH is different, then you suppose to have a "different" picture".
You can also use SUBSTRING(Image, 1, 8000) to check first 8000 bytes.
And also SUBSTRING(Image, DATALENGTH(Image) - 7999, 8000) to check last 8000 bytes.
One of the fastest ways is to do an UPDATE and then INSERT if update returns no updates.
string cmd = #"UPDATE Image SET Image = #imagedata WHERE ImageName = #ImageName
IF ##ROWCOUNT=0
INSERT INTO Image (ImageName,Image) VALUES (#imagename,#imagedata)";
Or if query on Image itself:
string cmd = #"UPDATE Image SET ImageName = #ImageName WHERE Image = #imagedata
IF ##ROWCOUNT=0
INSERT INTO Image (ImageName,Image) VALUES (#imagename,#imagedata)";

Categories

Resources