OutOfMemoryException was unhandled Image.FromFile() in C# - c#

i got out of memory exception upon loading image from file.. i retrieve the file from database and the output file image can be viewed..
String temp = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/img.jpg";
using (FileStream fs = new FileStream(temp, FileMode.Create))
{
fs.Write(StudentImage(id), 0, StudentImage(id).Length);
fParent.picAvatar.BackgroundImage = Image.FromFile(temp);
//fParent.picAvatar.Image = Image.FromFile(temp2);
}
private byte[] StudentImage(String _id)
{
try
{
String sqlCmd = String.Format("SELECT studpic FROM dbo.studentpic WHERE idnum = '{0}'", _id);
using (SqlConnection con = new SqlConnection(gVar._conString))
{
con.Open();
SqlCommand cmd = new SqlCommand(sqlCmd, con);
using (SqlDataReader r = cmd.ExecuteReader())
{
r.Read();
byte[] imgData = (byte[])r["studpic"];
return imgData;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}
did i miss any object that needs to close?

You tend to get an OutOfMemory exception when an image cannot be read for a number of reasons.
In your case the issue is that you have not closed your file! Also, you are calling the database twice.
I suggest the following code:
File.WriteAll(temp, StudentImage(id));
fParent.picAvatar.Image = Image.FromFile(temp);

Related

Invalid length for a Base-64 char array or string in web method asp.net

I am converting image from string by FromBase64String in asp.net C#, but at that time it showing title error in web method.
Here is my code,
[WebMethod]
public static List<CustomerMortgageModel> GetProductList()
{
string constr = ConfigurationManager.ConnectionStrings["connection"].ConnectionString;
List<CustomerMortgageModel> customers = new List<CustomerMortgageModel>();
Service service = new Service();
using (SqlConnection con = new SqlConnection(constr))
{
string qrySelProductDetail = "select * from tbl_MortageDetail " + System.Environment.NewLine;
using (SqlCommand cmd = new SqlCommand(qrySelProductDetail, con))
{
con.Open();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
while (sdr.Read())
{
byte[] bytes = Convert.FromBase64String(sdr["DesignImage"].ToString());
System.Drawing.Image image;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = System.Drawing.Image.FromStream(ms);
}
customers.Add(new CustomerMortgageModel
{
DesignImage = image.ToString()
});
}
}
con.Close();
}
}
return customers;
}
The error coming from this line
byte[] bytes = Convert.FromBase64String(sdr["DesignImage"].ToString());
use
var base64Img = (string)sdr["DesignImage"];
if (string.IsNullOrEmpty(base64Img))
{
throw new ArgumentException("'DesignImage' is null or empty");
}
byte[] bytes = Convert.FromBase64String(base64Img);
so you'll be sure of the column's type and that the string isn't empty, if you still get an error at 'Convert.FromBase64String' it's impossible to find the problem without having a sample of the invalid base64 content (but paste it here only if it doesn't contain private data)

MySQL Reader in C# - "There is already an open Data Reader associated with this connection which must be closed first."

I have a problem with my MySQL Reader - I am running the reader in a loop, checking if a configured entry exists in my database. After the reader is applied, the reader is getting closed and set to null again.
Anyhow, I always get this error message when I am running the "CheckExistEntry" - function in my code.
"07.04.2021 14:28:05 ERROR: There is already an open Data Reader associated with this connection which must be closed first."
The error does not occur in the following situations:
If I set a breakpoint at the relevant position in the code, the error does not occur.
If I set a sleep for 1000 MS before the reader is executed, the error does not occur.
Is it possible that C# is running loops via multithreading without me knowing it?
Here's the code:
public bool CheckExistEntry(string iColumnName)
{
MySqlDataReader reader = null;
string query2 = "SHOW COLUMNS FROM defectdetection.defects_main";
MySqlCommand cmd = new MySqlCommand(query2, MySqlConn);
try
{
// SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA =[Database Name] AND TABLE_NAME =[Table Name];#
// write_Log()
write_Log(log_directory, log_file, "BEFORE ExecuteReader");
//COMMENT FOR STACKOVERFLOW: cmd.ExecuteReader() triggers the Error.
reader = cmd.ExecuteReader();
write_Log(log_directory, log_file, "AFTER ExecuteReader");
//now, communication with MySQL is finished. ..
List<string> ColumnNames = new List<string>();
while (reader.Read())
{
ColumnNames.Add((string)reader[0]);
}
if (ColumnNames.Contains(iColumnName))
{
reader.Close();
reader.Dispose();
reader = null;
return true;
}
else
{
reader.Close();
reader.Dispose();
reader = null;
return false;
}
}
catch (Exception ex)
{
if (reader != null)
{
reader.Close();
reader.Dispose();
reader = null;
}
exception = new ArgumentException(ex.Message);
MessageBox.Show(ex.Message);
//TODO handle exception
write_Log(log_directory, log_file,"ERROR: There is already an open Data Reader associated with this connection which must be closed first.");
progressBarForm.Invoke(new updatebar(progressBarForm.Close));
return false;
}
}
i tried it with a triple-using statement now (using MySqlConnection, using MySqlCommand, using MySqlDatareader). But it still does not work, i get another error now: "Connection must be valid and open."
using (MySqlConnection MySqlConnLocal = new MySqlConnection()) {
using (MySqlCommand cmd = new MySqlCommand(query2, MySqlConnLocal)) {
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
ColumnNames.Add((string)reader[0]);
}
}
if (ColumnNames.Contains(iColumnName))
{
return true;
}
else
{
return false;
}
}
}
FIXED IT NOW: This Code here was the solution:
//System.Threading.Thread.Sleep(1);
using (MySqlConnection MySqlConnLocal = new MySqlConnection(ConnString))
{
MySqlConnLocal.Open();
using (MySqlCommand cmd2 = new MySqlCommand(query2, MySqlConnLocal))
{
reader = cmd2.ExecuteReader();
while (reader.Read())
{
ColumnNames.Add((string)reader[0]);
}
}
}
You haven't dispose of "cmd". Try the following:
...
public bool CheckExistEntry(string iColumnName)
{
string query2 = "SHOW COLUMNS FROM defectdetection.defects_main";
try
{
using (MySqlConnection mySqlConn = new MySqlConnection(ConnectionStr))
{
mySqlConn.Open();
using (MySqlCommand cmd = new MySqlCommand(query2, mySqlConn))
{
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
if ((string)reader[0] == iColumnName)
{
return true;
}
}
}
}
}
}
catch (Exception ex)
{
var exception = new ArgumentException(ex.Message);
MessageBox.Show(ex.Message);
//TODO handle exception
write_Log(log_directory, log_file, "ERROR: There is already an open Data Reader associated with this connection which must be closed first.");
//ToDo: add any additional desired code
}
return false;
}

sqlfilestream - getting blob data from SQL Server and saving the file locally to disk

I have the following scenario:
I have successfully saved my files(various extensions) into my sql server db using FILESTREAM. These can be anything from an image, to a word doc, pdf etc.
now i want to retreive them and save them as a file to my local directory.
here is what i have so far
My function calling SQL and getting the the filestream information i want
public static void SelectFile(string sourceId)
{
string serverPath;
string filename;
byte[] serverTxn;
using (TransactionScope ts = new TransactionScope())
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["DBConn"].ToString()))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("OPS.LoadFileBlobFromSQL", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#AttachmentId", SqlDbType.VarChar).Value = sourceId;
using (SqlDataReader rdr = cmd.ExecuteReader())
{
rdr.Read();
filename = rdr.GetSqlString(0).Value;
serverPath = rdr.GetSqlString(1).Value;
serverTxn = rdr.GetSqlBinary(2).Value;
rdr.Close();
}
}
StreamObjectFromFilestream(serverPath, serverTxn, filename);
}
ts.Complete();
}
}
private static void StreamObjectFromFilestream(string serverPath, byte[] serverTxn, string filename)
{
SqlFileStream sfs = new SqlFileStream(serverPath, serverTxn, FileAccess.Read);
byte[] buffer = new byte[sfs.Length];
sfs.Read(buffer, 0, buffer.Length);
System.IO.File.WriteAllBytes(#"c:\test\hello.pdf", buffer);
sfs.Close();
}
I am getting serverpath, filename and serverTxn .. but when i go into my StreamObjectFromFilestream function the buffer is empty.. i know i am missing something simple here ... just dont know what.
Any pointers in the right direction would be appreciated.
Thanks,
Corey
You can skip using the SqlFilestream inside StreamObjectFromFilestram, your serverTxn is already a byte array that the Method WriteAllBytes is needing.

Writing multiple queries to single csv

I need to write multiple queries to a single CSV file. For example I will generate a report with an Employee Schedule then below that in the same CSV I want to see the employee personal information such as salary, office location, etc. I can return both queries from a single stored procedure thinking it would write one followed by the next, but apparently that's incorrect as only the first result is returned.
My SQL Query is like the following:
SELECT EmployeeSchedule.TaskTime, Employees.EmployeeName, EmployeeSchedule.M, EmployeeSchedule.Tu, EmployeeSchedule.W,
EmployeeSchedule.Th, EmployeeSchedule.F, EmployeeSchedule.Sa, EmployeeSchedule.Su
FROM EmployeeSchedule
INNER JOIN Employees on EmployeeSchedule.EmployeeID = Employees.EmployeeID
WHERE (
EmployeeSchedule.EmployeeID = #EmployeeID AND
EmployeeSchedule.TaskTime >= #ShiftStart AND
EmployeeSchedule.TaskTime <= #ShiftEnd AND
(
(EmployeeSchedule.M=1) AND (EmployeeSchedule.M = #M) OR
(EmployeeSchedule.Tu=1) AND (EmployeeSchedule.Tu = #Tu) OR
(EmployeeSchedule.W=1) AND (EmployeeSchedule.W = #W) OR
(EmployeeSchedule.Th=1) AND (EmployeeSchedule.Th = #Th) OR
(EmployeeSchedule.F=1) AND (EmployeeSchedule.F = #F) OR
(EmployeeSchedule.Sa=1) AND (EmployeeSchedule.Sa = #Sa) OR
(EmployeeSchedule.Su=1) AND (EmployeeSchedule.Su = #Su)
)
)
ORDER BY EmployeeName, TaskTime
SELECT Employees.EmployeeName, Salary, City, AdditionalDetails
FROM EmployeeDetails
INNER JOIN Employees on EmployeeDetails.EmployeeID = Employees.EmployeeID
WHERE Employees.EmployeeID=#EmployeeID
My relevant portion of code is as follows:
public void GenerateEmployeeLog()
{
string employee = Convert.ToString(EmployeesDropDown.SelectedItem.Text);
string sqlConn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection sqlConnection1 = new SqlConnection(sqlConn))
{
try
{
sqlConnection1.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = ("usp_" + proc);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = sqlConnection1;
cmd.Parameters.AddWithValue("EmployeeID", Convert.ToString(EmployeeDropDown.SelectedItem.Value));
cmd.Parameters.AddWithValue("ShiftStart", StartTextBox.Text);
cmd.Parameters.AddWithValue("ShiftEnd", EndTextBox.Text);
cmd.Parameters.AddWithValue("M", MCheckBox.Checked);
cmd.Parameters.AddWithValue("Tu", TuCheckBox.Checked);
cmd.Parameters.AddWithValue("W", WCheckBox.Checked);
cmd.Parameters.AddWithValue("Th", ThCheckBox.Checked);
cmd.Parameters.AddWithValue("F", FCheckBox.Checked);
cmd.Parameters.AddWithValue("Sa", SaCheckBox.Checked);
cmd.Parameters.AddWithValue("Su", SuCheckBox.Checked);
using (SqlDataReader reader = cmd.ExecuteReader())
{
try
{
using (DataTable dt = new DataTable())
{
dt.Load(reader);
using (StreamWriter writer = new StreamWriter(Response.OutputStream))
{
DataConvert.ToCSV(dt, writer, false);
Response.AddHeader("content-disposition", #"attachment;filename=""" + "EmployeeLog - " + employee + #".csv""");
Response.Charset = "";
Response.ContentType = "application/text";
Response.End();
}
}
}
catch (Exception)
{
throw;
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
sqlConnection1.Close();
sqlConnection1.Dispose();
}
}
}
Any suggestions on how to accomplish what I'm looking for is greatly appreciated.
SOLUTION:
I ended up splitting out the two queries into different stored procedures and made the final modifications to my code, based on suggestions from the accepted answer below.
public void GenerateEmployeeLog()
{
string employee = Convert.ToString(EmployeesDropDown.SelectedItem.Text);
string sqlConn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection sqlConnection1 = new SqlConnection(sqlConn))
{
try
{
sqlConnection1.Open();
using (SqlCommand cmd1 = new SqlCommand())
{
cmd1.CommandText = ("usp_" + proc + "_EmployeeDetails");
cmd1.CommandType = CommandType.StoredProcedure;
cmd1.Connection = sqlConnection1;
cmd1.Parameters.AddWithValue("EmployeeID", Convert.ToString(AffiliatesDropDown.SelectedItem.Value));
using (SqlDataReader reader = cmd1.ExecuteReader())
{
try
{
using (dt1 = new DataTable())
{
dt1.Load(reader);
}
}
catch (Exception)
{
throw;
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
using (SqlCommand cmd2 = new SqlCommand())
{
cmd2.CommandText = ("usp_" + proc);
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.Connection = sqlConnection1;
cmd2.Parameters.AddWithValue("EmployeeID", Convert.ToString(EmployeeDropDown.SelectedItem.Value));
cmd2.Parameters.AddWithValue("ShiftStart", StartTextBox.Text);
cmd2.Parameters.AddWithValue("ShiftEnd", EndTextBox.Text);
cmd2.Parameters.AddWithValue("M", MCheckBox.Checked);
cmd2.Parameters.AddWithValue("Tu", TuCheckBox.Checked);
cmd2.Parameters.AddWithValue("W", WCheckBox.Checked);
cmd2.Parameters.AddWithValue("Th", ThCheckBox.Checked);
cmd2.Parameters.AddWithValue("F", FCheckBox.Checked);
cmd2.Parameters.AddWithValue("Sa", SaCheckBox.Checked);
cmd2.Parameters.AddWithValue("Su", SuCheckBox.Checked);
using (SqlDataReader reader = cmd2.ExecuteReader())
{
try
{
using (DataTable dt2 = new DataTable())
{
dt2.Load(reader);
using (StreamWriter writer = new StreamWriter(Response.OutputStream))
{
DataConvert.ToCSV(dt2, writer, false);
writer.WriteLine();
DataConvert.ToCSV(dt1, writer, false);
Response.AddHeader("content-disposition", #"attachment;filename=""" + "EmployeeLog - " + employee + #".csv""");
Response.Charset = "";
Response.ContentType = "application/text";
Response.End();
}
}
}
catch (Exception)
{
throw;
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
sqlConnection1.Close();
sqlConnection1.Dispose();
}
}
}
I like Mike U's 2nd approach very much, but if you absolutely must have one csv file output, its not pretty, but could you not do something like this?:
using (SqlDataReader reader = cmd.ExecuteReader()){
using (SqlDataReader reader1 = cmd1.ExecuteReader()){
using (DataTable dt = new DataTable()){
using (DataTable dt1 = new DataTable()){
dt.Load(reader);
dt1.Load(reader1);
using (StreamWriter writer = new StreamWriter(Response.OutputStream)){
DataConvert.ToCSV(dt, writer, false);
DataConvert.ToCSV(dt1, writer, false);
...
}}}}}
Judging by the Response stuff, you're doing this on a web page. The problem you're going to run into is that you can only return a single response for a single request. Since you're just sending the DataConvert.ToCSV() output as a response stream, that would mean a different stream for each of the files.
If you're not going to actually display these in HTML, then you'll need to create a ZIP file to store the two different files.
Examples for creating a multi-file ZIP file can be found here: https://msdn.microsoft.com/en-us/library/system.io.compression.zipfile(v=vs.110).aspx
EDIT: A second option would be to emit javascript into the Page_Load event which would call an HTTPHandler which actually runs the two separate queries. This would popup two additional tabs, each with one of the CSV files. You would have to move all this code into a custom HTTPHandler, where the querystring string parameter "t" could determine which of the two queries was run.
protected void btn_OnClick(object sender, EventArgs e)
{
string sysPgLoad = "Sys.Application.add_load(function () {{ {0}; }});";
this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), "employeeLog", string.Format(sysPgLoad, "window.Open('exployeeCsv.axd?t=log')"));
this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), "employeeSal", string.Format(sysPgLoad, "window.Open('exployeeCsv.axd?t=sal')"));
}

Retrieve image from SQL Server using ASP.NET web service

I have a SQL Server (2008 R2) with an Image table, the table has a column with type image. I insert my Image into this column using
Stream fs = FileUpload1.PostedFile.InputStream;
BinaryReader br = new BinaryReader(fs);
Byte[] bytes = br.ReadBytes((Int32)fs.Length);
//insert the file into database
string strQuery = "insert into pm005.images(imageName, type, alt, img)" + " values (#Name, #ContentType, #Alt, #Data)";
SqlCommand cmd = new SqlCommand(strQuery);
cmd.Parameters.Add("#Name", SqlDbType.VarChar).Value = filename;
cmd.Parameters.Add("#ContentType", SqlDbType.VarChar).Value = contenttype;
cmd.Parameters.Add("#Alt", SqlDbType.VarChar).Value = TextBox1.Text;
cmd.Parameters.Add("#Data", SqlDbType.Binary).Value = bytes;
InsertUpdateData(cmd);
lblMessage.ForeColor = System.Drawing.Color.Green;
lblMessage.Text = "File Uploaded Successfully";
private Boolean InsertUpdateData(SqlCommand cmd)
{
// Open a connection the the SQL Server
SqlConnection con = new SqlConnection();
con.ConnectionString = "server=sql-server;integrated security=SSPI;database=pm005";
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
try
{
con.Open();
cmd.ExecuteNonQuery();
return true;
}
catch (Exception ex)
{
Response.Write(ex.Message);
return false;
}
finally
{
con.Close();
con.Dispose();
}
}
This i believe works fine, because the insert returns true, and i can see the data in the database.
However i cant for the life of me see how i'm supposed to get this image back out. Specifically what i want is to be able to call my web service, pass it the imageID and have the image (and only the image) returned to me. Much like its done with PHP. THis is the code im using now.
[WebMethod]
[ScriptMethod(UseHttpGet = true)]
public System.Drawing.Image getImage(int imageID, string uName, string pword)
{
string str="";
try
{
SqlCommand cmd = getSQLCommand("SELECT img FROM pm005.images WHERE id="+imageID);
byte[] Img = (byte[])cmd.ExecuteScalar();
// Convert the image record to file stream and display it to picture control
str = Convert.ToString(DateTime.Now.ToFileTime());
FileStream fs = new FileStream(str, FileMode.CreateNew, FileAccess.Write);
fs.Write(Img, 0, Img.Length);
fs.Flush();
fs.Close();
}
catch
{
}
finally
{
}
System.Drawing.Image theImage = System.Drawing.Image.FromFile(str);
return theImage;
}
Which gives the error:
System.ArgumentException: The path is not of a legal form.
at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength)
at System.IO.Path.GetFullPathInternal(String path)
at System.IO.Path.GetFullPath(String path)
at System.Drawing.IntSecurity.UnsafeGetFullPath(String fileName)
at System.Drawing.IntSecurity.DemandReadFileIO(String fileName)
at System.Drawing.Image.FromFile(String filename, Boolean useEmbeddedColorManagement)
at WebService2.Service1.getImage(Int32 imageID, String uName, String pword)
I've looked at so many tutorials, and not find any solid answer except "use PHP". If i have to i will, but surely there must be a way to do it in ASP.NET?
Try specifying the Full FilePath:
FileStream fs = new FileStream(#"C:\Temp\YourFile.jpg", FileMode.CreateNew, FileAccess.Write);
Edit:
Rather than using the File System it sounds like you want to do it in memory:
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
...
System.Drawing.Image theImage = null;
try
{
SqlCommand cmd = getSQLCommand("SELECT img FROM pm005.images WHERE id="+imageID);
byte[] Img = (byte[])cmd.ExecuteScalar();
theImage = byteArrayToImage(Img);
}
catch
{
}
finally
{
}
return theImage;
}

Categories

Resources