Read Image from SQL Server VarBinary(Max) - c#

I have a SQL Server Database. I have stored an image in there which is a varbinary(max). I inserted the image the following way :
string consString = ConfigurationManager.ConnectionStrings["connection"].ConnectionString;
SqlConnection con = new SqlConnection(consString);
con.Open();
String filePath = fuImage.PostedFile.FileName;
String naam = Path.GetFileName(filePath);
String extension = Path.GetExtension(naam);
Stream stream = fuImage.PostedFile.InputStream;
BinaryReader br = new BinaryReader(stream);
Byte[] imgByte = br.ReadBytes((Int32)stream.Length);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "spAddImage";
cmd.Parameters.AddWithValue("#FOTO", imgByte);
cmd.Parameters.AddWithValue("#ARTIEST", ddlArtiest.SelectedValue);
cmd.Connection = con;
cmd.ExecuteNonQuery();
con.Close();
The image now looks like this in the database :
It is stored as a varbinary.
http://puu.sh/ikF83/6a03b52520.png <--- database
Now I want to display my image on my asp.net page that I have inserted.
But I have no idea how I can achieve this.

You could use SqlDataReader to go over the results and get back what you need
var reader = cmd.ExecuteReader();
while (reader.Read())
{
byte[] myImage = (byte[])reader["MyImageColumn"];
}
This is from top of my head so make your adjustments as required. But it should give you the basic idea.
Furthermore, It's strongly recommended to use the using block as it ensures the object is disposed correctly.
So you could change your code to
using(var connection = new SqlConnection(connectionString))
{
//Your command
connection.Open();
//Datareader here
}//Object disposed here
Reference to SqlDataReader
Reference to using block

Extending the answer provided by Izzy, below is how we have implemented the same.
public HttpResponseMessage RenderImage(RenderRequest renderRequest, HttpRequestMessage request)
{
var httpResponse = new HttpResponseMessage();
try
{
var reader = cmd.ExecuteReader();
while (reader.Read())
{
byte[] imagebytes = (byte[])reader["MyImageColumn"];
}
return httpResponse = request.CreateResponse<byte[]>(HttpStatusCode.OK, imagebytes, new ImageMediaFormatter("image/png"));
}
catch ()
{
throw;
}
}

Related

How to return specific row from database that include image path

I write below code that correctly returns an image that its path stored in the database.
[HttpGet("{id}")]
public IActionResult RetrieveFile(int id)
{
string pathImage = "";
DataTable table = new DataTable();
string query = #"select image from mydb.courses where id=#id";
string sqlDataSource = _configuration.GetConnectionString("UsersAppCon");
MySqlDataReader myReader;
using (MySqlConnection mycon = new MySqlConnection(sqlDataSource))
{
mycon.Open();
using (MySqlCommand myCommand = new MySqlCommand(query, mycon))
{
myCommand.Parameters.AddWithValue("#id", id);
pathImage = (string)myCommand.ExecuteScalar();
mycon.Close();
}
}
var path = #$"{pathImage}";
var fs = new FileStream(path, FileMode.Open);
return File(fs, "image/jpeg");
}
Furthermore, I want to return the id, price, and name with the image from the database and send it to the client.
What changes should I make to the above code to send me What I want?
You cannot use ExecuteScalar, but you need to call ExecuteReader to get back an MySqlDataReader and then get the single inputs from the reader fields. and of course, you should change the query to get the required fields
string query = #"select id,price,name,image from mydb.courses where id=#id";
string sqlDataSource = _configuration.GetConnectionString("UsersAppCon");
using (MySqlConnection mycon = new MySqlConnection(sqlDataSource))
{
mycon.Open();
using (MySqlCommand myCommand = new MySqlCommand(query, mycon))
{
myCommand.Parameters.AddWithValue("#id", id);
// Then you use the reader to get the single field values
using(MySqlDataReader myReader = myCommand.ExecuteReader())
{
// Always check if the where clause produces records to read
if(myReader.Read())
{
// I have assumed the datatype for the fields. Change GetXXXX if different
pathImage = myReader.GetString("image");
id = myReader.GetInt32("id");
price = myReader.GetDecimal("price");
name = myReader.GetString("name");
}
}
}
}
Notice that you don't need to close the connection when it is declared inside a using statement. Also it is better to not use AddWithValue albeit in case of integers its problems are not relevant and MySql seems to be a bit more resilient than other db

How to execute another MySqlDataReader for each read ID?

I'm trying to get from my database some data, each of that data may have some attributes, so my logic was while i'm getting all data so while the MySqlDataReader is executed i was going to execute the query for each id of data i got to get it's attributes.
But i run in to error: 'There is already an open DataReader associated with this Connection' so my guess is that i can't run at the same time the MySqlDataReader so at this point, which would be the best approach to get attributes for each data?
Should i just cycle on each Plu element after i've added them to the list or is there a better solution?
Here is the function where i get the data (Plu object)
public IEnumerable<Plu> GetPlu(string piva, int menu)
{
string connectionString = $"CONSTR";
using var connection = new MySqlConnection(connectionString);
connection.Open();
var sql = #"QUERY";
using var cmd = new MySqlCommand(sql, connection);
cmd.Parameters.AddWithValue("#menu", menu);
cmd.Prepare();
using MySqlDataReader reader = cmd.ExecuteReader();
List<Plu> plu = new List<Plu>();
while (reader.Read())
{
plu.Add(new Plu(
(int)reader["ID_PLUREP"],
(string)reader["CODICE_PRP"],
(string)reader["ESTESA_DES"],
(string)reader["DESCR_DES"], (float)reader["PRE_PRP"],
reader.IsDBNull(reader.GetOrdinal("IMG_IMG")) ? null : (string)reader["IMG_IMG"],
Attributi(connection, (int)reader["ID_PLUREP"])
));
}
return plu;
}
And here is function Attributi which return the IEnumerable of attributes for each Plu
public IEnumerable<Plu.Attributi> Attributi(MySqlConnection connection, int idplu)
{
var sql = #"QUERY";
using var cmd = new MySqlCommand(sql, connection);
cmd.Parameters.AddWithValue("#idplu", idplu);
cmd.Prepare();
List<Plu.Attributi> attributi = new List<Plu.Attributi>();
using MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
attributi.Add(new Plu.Attributi(
reader.IsDBNull(reader.GetOrdinal("BCKCOL_ATT")) ? null : (string)reader["BCKCOL_ATT"],
reader.IsDBNull(reader.GetOrdinal("FORCOL_ATT")) ? null : (string)reader["FORCOL_ATT"],
reader.IsDBNull(reader.GetOrdinal("DESCR_ATT")) ? null : (string)reader["DESCR_ATT"]
));
}
return null;
}
You can't use an open connection with a reader already executing. Open a new connection in Attributi.
public IEnumerable<Plu.Attributi> Attributi(int idplu)
{
var sql = #"QUERY";
using var connection = new MySqlConnection(connectionString)
{
connection.Open();
using var cmd = new MySqlCommand(sql, connection)
{
cmd.Parameters.AddWithValue("#idplu", idplu);
cmd.Prepare();
List<Plu.Attributi> attributi = new List<Plu.Attributi>();
using MySqlDataReader reader = cmd.ExecuteReader()
{
while (reader.Read())
{
attributi.Add(new Plu.Attributi(
reader.IsDBNull(reader.GetOrdinal("BCKCOL_ATT")) ? null : (string)reader["BCKCOL_ATT"],
reader.IsDBNull(reader.GetOrdinal("FORCOL_ATT")) ? null : (string)reader["FORCOL_ATT"],
reader.IsDBNull(reader.GetOrdinal("DESCR_ATT")) ? null : (string)reader["DESCR_ATT"]
));
}
return null;
}
}
}
BTW, your usage of using is totally off. You need a block after the using statement where you deal with everything regarding the IDisposable object.
EDIT: Apparently that's a new .NET Core 3.1 feature.
For the more general case, my experience with MySQL has lead me to always "free" my reader with:
MySqlDataReader reader = cmd.ExecuteReader();
DataTable dataTable = new DataTable();
dataTable.Load(reader);
Then working from the DataTable rather than the MySqlDataReader, you can then reuse the connection as you prefer.

How to read VarBinary Data from the SqlServer ASP.Net

I have a binary data (Object of MyClass) in SqlServer field, But i am not able to retrieve the binary value and convert it into My Class Object.
I have used following code to write into the DB.
conn = getConnection();
MemoryStream memStream = new MemoryStream();
StreamWriter sw = new StreamWriter(memStream);
sw.Write(sql);
SqlCommand sqlCmd = new SqlCommand(#"INSERT INTO PExercise(P_Enroll_No,P_Exercises,P_Date) VALUES (#VarEnroll,#VarBinary,#Date)", conn);
sqlCmd.Parameters.Add("#VarEnroll",System.Data.SqlDbType.NVarChar,Int32.MaxValue);
sqlCmd.Parameters["#VarEnroll"].Value = sql.getEnrollNo();
sqlCmd.Parameters.Add("#VarBinary", System.Data.SqlDbType.VarBinary, Int32.MaxValue);
sqlCmd.Parameters["#VarBinary"].Value = memStream.GetBuffer();
sqlCmd.Parameters.Add("#Date",System.Data.SqlDbType.NVarChar,Int32.MaxValue);
sqlCmd.Parameters["#Date"].Value = date;
int success = sqlCmd.ExecuteNonQuery();
closeConnection();
This code successfully writes my data into the table. I have used following code to read it from database.
please help me with the code.
conn = getConnection();
SqlCommand sqlCmd = new SqlCommand(#"Select P_Exercises from PExercise where P_Enroll_No='" + enrollNo + "' AND P_Date='"+date+"'", conn);
SqlDataReader dr = sqlCmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess);
byte[] bytes = new byte[1024];
long i = dr.GetBytes(0,0,bytes,0,1024*1024*8);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
MemoryStream ms = new MemoryStream(bytes);
ms.Position = 0;
mc = (List<ExerciseDetails>)bf.Deserialize(ms);
I have searched a lot but still have no luck.
Above code is giving me Exception "Invalid Read, No Data is Present".
I have also tried QueryManager to run the sql query. and its working fine there.
You could do something like the following where you do an ExecuteScaler as safe cast it as a byte array. By the way, make sure you wrap objects that implement IDisposable with using statements so they are closed and disposed properly.
using (var cn = _db.CreateConnection())
using (var cm = cn.CreateTextCommand(sql))
{
cm.AddInParam("name", DbType.String, name);
cn.Open();
var data = cm.ExecuteScalar() as byte[];
return data;
}

populate list with images from database

I want to retrieve the images from SQL table and save it in the list and show it in my listview. But I don't know how to do this. I need your help.
I am using SQL Server 2008, Visual Studio 2008, C# Window Application.
Here is my code:
cmd = new SqlCommand("Select ScanImage from ScanDocuments", con);
dr = cmd.ExecuteReader();
List<ImageList> lstitem = new List<ImageList>();
while (dr.Read())
{
ImageList _image = new ImageList();
byte[] data = (byte[])dr["ScanImage"];
MemoryStream ms = new MemoryStream(data);
Image bmp = new Bitmap(ms);
lstitem.Add(bmp);
}
Your code has several flaws - you need to use something like this instead:
// define connection string and select statement
// I used AdventureWorks 2012 database - change to match *YOUR* environment
string connectionString = "server=.;database=AdventureWorks2012;integrated security=SSPI;";
string query = "SELECT ThumbNailPhoto FROM Production.ProductPhoto";
// define a list of "Image" objects
List<Image> listOfImages = new List<Image>();
// using the SqlConnection and SqlCommand ....
using(SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand selectCmd = new SqlCommand(query, conn))
{
// open connection
conn.Open();
// execute SqlCommand to return a SqlDataReader
using (SqlDataReader rdr = selectCmd.ExecuteReader())
{
// iterate over the reader
while (rdr.Read())
{
// load the bytes from the database that represent your image
var imageBytes = (byte[]) rdr[0];
// put those bytes into a memory stream and "rewind" the memory stream
MemoryStream memStm = new MemoryStream(imageBytes);
memStm.Seek(0, SeekOrigin.Begin);
// create an "Image" from that memory stream
Image image = Image.FromStream(memStm);
// add image to list
listOfImages.Add(image);
}
}
conn.Close();
}
This works just fine for me - it loads the 101 ThumbNailPhoto from the AdventureWorks2012 database

How do I store a image BLOB in an access database after getting the name from openfiledialog?

I am developing a C# application that has an Access database. What I want to do is allow a user to select an image through an "openfiledialog." I then want to store the image in one of the table of the access database in a BLOB field. I have searched over the internet, but found nothing helpful. I hope you can help me.
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
// textBox1.Show(openFileDialog1.FileName.ToString());
// MessageBox.Show(openFileDialog1.FileName.ToString());
textBox1.Text = openFileDialog1.FileName.ToString();
String filename = openFileDialog1.FileName.ToString();
byte[] buffer = File.ReadAllBytes(filename);
using (var conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Policias.accdb"))
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "INSERT INTO DetallesMunicipio(imagen) VALUES (#imagen)";
cmd.Parameters.AddWithValue("#imagen", buffer);
conn.Open();
cmd.ExecuteNonQuery();
}
}
else
{
MessageBox.Show("Porfavor selecciona una imagen");
}
}
but now how can I be sure that is stored in the access database?
Example:
string filename = "foo.txt"; // TODO: fetch from file dialog
byte[] buffer = File.ReadAllBytes(filename);
using (var conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=foo.mdb"))
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "INSERT INTO MyTable VALUES (#Name, #Data)";
cmd.Parameters.AddWithValue("#Name", filename);
cmd.Parameters.AddWithValue("#Data", buffer);
cmd.ExecuteNonQuery();
}
What you will want to do is something similar to the following.
using (OpenFileDialog fileDialog = new OpenFileDialog){
if(fileDialog.ShowDialog == DialogResult.OK){
using (System.IO.FileInfo fileToSave = new System.IO.FileInfo(fileDialog.FilePath)){
MemoryStream ms = System.IO.FileStream(fileToSave.FullNae, IO.FileMode.Open);
//Here you can copy the ms over to a byte array to save into your blob in your database.
}
}
}
I would use File.ReeadAllBytes(file) and save the byte[] there in the DB.

Categories