Upload File and Save to Database - c#

I am trying to upload a file from disk and then insert the file into a varbinary db column.
I can't seem to figure out how to insert the binary file.
I am using C# and Linq to Sql in a WPF application.
Here is what I am trying so far! Any suggestions or advice would be appreciated.
private void UploadFile()
{
DatabaseData.DataClassesDataContext context = new DatabaseData.DataClassesDataContext();
{
OpenFileDialog dlgOpen = new OpenFileDialog();
dlgOpen.Title = "Select file";
FileData fd = new FileData();
if (dlgOpen.ShowDialog() ?? false)
{
FileStream inStream = File.OpenRead(dlgOpen.FileName);
//FileStream outStream = File.OpenWrite(dlgOpen.FileName + ".xlsx");
int b;
while ((b = inStream.ReadByte()) > -1)
// outStream.WriteByte((byte)b);
fd.FileId = Guid.NewGuid();
//fd.DataFile = inStream;//DataFile is the Varbinary column in the db
fd.Title = dlgOpen.FileName;
fd.FileExtension = txtExtension.text;
context.FileDatas.InsertOnSubmit(fd);
context.SubmitChanges();
//outStream.Flush();
//outStream.Close();
inStream.Close();
}
}
}

Not sure if this will work, but try this
if (dlgOpen.ShowDialog() ?? false)
{
byte[] bytes = System.IO.File.ReadAllBytes(dlgOpen.FileName);
fd.FileId = Guid.NewGuid();
fd.DataFile = bytes;
fd.Title = dlgOpen.FileName;
context.FileDatas.InsertOnSubmit(fd);
context.SubmitChanges();

To fix the compile error, remove the while statement. You're trying to create a new FileData() which can never be used until b > -1.
I don't know that the code will work after that, but it will fix this one compile error.
private void UploadFile()
{
DatabaseData.DataClassesDataContext context = new DatabaseData.DataClassesDataContext();
{
OpenFileDialog dlgOpen = new OpenFileDialog();
dlgOpen.Title = "Select file";
if (dlgOpen.ShowDialog() ?? false)
{
FileStream inStream = File.OpenRead(dlgOpen.FileName);
FileData fd = new FileData();
fd.FileId = Guid.NewGuid();
fd.DataFile = inStream;
fd.Title = dlgOpen.FileName;
fd.FileExtension = txtExtension.text;
context.FileDatas.InsertOnSubmit(fd);
context.SubmitChanges();
inStream.Close();
}
}
}

Well, you read my disclaimer in your comments. I can't guarantee any pros here would agree with the approach it's per your request. I am just learning C# the right way and got the idea to convert a working non-database program. I needed this to convert all my existing data into a new database that was to take over storage:
/* Spawned from a button click
...
*/
//
// Here I bring in the directory which you'll likely replace with
// a single file
//
string[] files =
Directory.GetFiles(
#"yourDicectory");
//
// At this point you may disregard my loop if needed
//
foreach (string file in files)
{
//
// Here the entire files are read and split
// Handle your data how you like
//
StreamReader fileReader = new StreamReader( file );
string lines = fileReader.ReadToEnd();
string[] entries = lines.Split( ',' );
//
// Here, omitted, I declare variables of types to insert "holders"
// Every CSV has to go to a corresponding holder of the
// the appropriate type (i.e., DateTime, decimal(money), or yourType)
//
SqlCeConnection con = new SqlCeConnection( "Data Source = YourDataSource.sdf" );
con.Open();
SqlCeCommand cmd = con.CreateCommand();
//
// The insert command that takes the parsed values - value1, value2, ...
// which are the named and omitted declarations from above
// You're providing a signature of the table you're inserting into
//
cmd.CommandText = "INSERT INTO YourTable ([Column1], [Column2], [Column3], ... , [Column(n)]) VALUES (value1, value2, value3, ... , value(n))";
//
// Here, omitted, I parse and convert the values and store them in the holders
//
// Now execute and catch if needed
try
{
cmd.ExecuteNonQuery();
}
catch( SqlCeException sqle )
{
myTextbox.Text += sqle.Errors.ToString() + "\n";
}
}
//
// Update my view - May not apply
//
myGridView1.Update();
con.Close();
}
/* Do whatever else you'd like ... */

File operations in C# (my blog link will help you)

Related

SQLiteDataReader Appears to be Holding DB Connection Open

Synopsis
I have a small local SQLite DB with a set records that are used to populate a ComboBoxList. The list is populated, and the DB connection released. No DB locking issues observed.
Then when a record is selected from the list, that record is retrieved and used to populate a LocalDBInstallRecord object. However, after populating the object, the DB connection seems to remain open and prevents any further access.
The Code
public LocalDBInstallRecord GetRecord(string recordID)
{
LocalDBInstallRecord lir = new LocalDBInstallRecord();
string query = "SELECT * FROM InstallationRecords WHERE RecordID = " + recordID;
using (SQLiteConnection localDBConnection = new SQLiteConnection(ConnectionStr))
{
localDBConnection.Open();
using (SQLiteCommand cmd = new SQLiteCommand(query, localDBConnection))
{
using (SQLiteDataReader rdr = cmd.ExecuteReader(CommandBehavior.KeyInfo))
{
while (rdr.Read())
{
lir.RecordID = (uint)rdr.GetInt32(rdr.GetOrdinal("RecordID"));
lir.DateCreated = rdr.GetDateTime(rdr.GetOrdinal("DateCreated"));
lir.Model = CheckDBNull(rdr, "Model");
lir.SCFirmwareVer = CheckDBNull(rdr, "SCFirmwareVer");
lir.DispFirmwareVer = CheckDBNull(rdr, "DispFirmwareVer");
lir.UCCFirmwareVer = CheckDBNull(rdr, "UCCFirmwareVer");
lir.Title = CheckDBNull(rdr, "Title");
lir.FOC = rdr.GetBoolean(rdr.GetOrdinal("FOC"));
lir.MCManufacturer = CheckDBNull(rdr, "MCManufacturer");
lir.MCType = CheckDBNull(rdr, "MCType");
lir.RailConvertor = CheckDBNull(rdr, "RailConvertor");
lir.PlantID = CheckDBNull(rdr, "PlantID");
lir.PlantOwner = CheckDBNull(rdr, "PlantOwner");
lir.PlantOwnerID = CheckDBNull(rdr, "PlantOwnerID");
lir.BoomLength = rdr.GetFloat(rdr.GetOrdinal("BoomLength"));
lir.ArticLength = rdr.GetFloat(rdr.GetOrdinal("ArticLength"));
lir.DipperLength = rdr.GetFloat(rdr.GetOrdinal("DipperLength"));
lir.MachineRecord = ReadDBBlob(rdr, "MachineRecord");
lir.DutyRecord = ReadDBBlob(rdr, "DutyRecord");
lir.CalibRecord = ReadDBBlob(rdr, "CalibRecord");
}
}
}
}
return lir;
}
Called Functions...
CheckDBNull
private static string CheckDBNull(SQLiteDataReader rdr, string col)
{
string str = null;
if (!rdr.IsDBNull(rdr.GetOrdinal(col)))
str = rdr.GetString(rdr.GetOrdinal(col));
return str;
}
ReadDBBlob
private static byte[] ReadDBBlob(SQLiteDataReader rdr, string col)
{
byte[] data = null;
if (!rdr.IsDBNull(rdr.GetOrdinal(col)))
{
SQLiteBlob blob = rdr.GetBlob(rdr.GetOrdinal(col), true);
data = new byte[blob.GetCount()];
blob.Read(data, blob.GetCount(), 0);
}
return data;
}
My Thoughts
I'm sure there's easier ways to load the object, but that's not the issue...
I think the DB connection is being held open because the SQLiteDataReader can't be disposed of cleanly. I suspect that something in this function (in the LocalDBInstallRecord object) has got hold of an object by reference. I just can't see what.
I've tried not accessing the DateTime object in the record, but that's not it.
Should I be using a different method to access the DB in this case?
Any suggestions greatly appreciated, I think it needs a fresh set of eyes. Thanks.
Further Research...
I've found that if I try and us the SQLite DB with another tool, whilst the GetRecord() function has hold of the reader, I'm able to read the DB, but can't write. I get a database locked (RELEASE 'RESTOREPOINT';) error message from "DB Browser SQLite" application. But I think that's just because it's waiting for the reader to release.
The problem came in the function ReadDBBlob. The SQLiteBlob is IDisposable, and it's use wasn't encapsulated in a using clause. As a result the SQLiteBlob wasn't being diposed of, and this held the reader and hence kept the connection open...
New ReadDBBlob
private static byte[] ReadDBBlob(SQLiteDataReader rdr, string col)
{
byte[] data = null;
if (!rdr.IsDBNull(rdr.GetOrdinal(col)))
{
using (SQLiteBlob blob = rdr.GetBlob(rdr.GetOrdinal(col), true))
{
data = new byte[blob.GetCount()];
blob.Read(data, blob.GetCount(), 0);
}
}
return data;
}
I hope this saves someone some time.

C# parameter is not valid SQL

I have code that I copied from the tutorial that I watch and our code is so similar in the tutorial.
When the presenter runs the code, it runs ok, but when I try to run my code which is the same as in the tutorial, I get an error "the parameter is not valid".
Please help
private void Viewbutton_Click(object sender, EventArgs e)
{
conection.Open();
string sqlQuery = "select studnum, course, f_name, l_name, color_image from table3 where studnum='" + textBox1.Text + "'";
cmd = new SqlCommand(sqlQuery, conection);
SqlDataReader dataread = cmd.ExecuteReader();
dataread.Read();
if (dataread.HasRows)
{
lblstudnum.Text = dataread[0].ToString();
lblcourse.Text = dataread[1].ToString();
lblfname.Text = dataread[2].ToString();
lbllname.Text = dataread[3].ToString();
byte[] images = (byte[])dataread[4];
if(images==null)
{
pictureBox1.Image = null;
}
else
{
MemoryStream mstreem = new MemoryStream(images);
pictureBox1.Image = Image.FromStream(mstreem);
}
}
else
{
MessageBox.Show("this data not available");
}
}
The error line is the
pictureBox1.Image = Image.FromStream(mstreem);
Better to use parametric query and column name instead of using [0],[1] etc.. The Memory Stream is used by Data reader.So you shall use as below, provided a valid Image is saved in database
var con = new SqlConnection("the connection string to database");
con.Open();
SqlCommand cmd = new SqlCommand(#"sql query",con);
byte[] images = null;
using (SqlDataReader dataread = cmd.ExecuteReader())
{
if (dataread.Read())
{
//lblstudnum.Text = dataread[0].ToString();
//lblcourse.Text = dataread[1].ToString();
//lblfname.Text = dataread[2].ToString();
//lbllname.Text = dataread[3].ToString();
images = (byte[])dataread["color_image"];// column name is recommended
}
}
con.Close();
if (images == null)
{
pictureBox1.Image = null;
}
else
{
MemoryStream mstreem = new MemoryStream(images);
pictureBox1.Image = Image.FromStream(mstreem);
}
Probably not a valid image. Add some debugging code to your program (or set up a watch) that will output the length of the memory stream and its first few bytes. Make sure the length is what you were expecting. Make sure the file prefix is there, if any, e.g. bitmap files have a two-letter alphanumeric prefix. Make sure it didn't get truncated. Make sure it is an allowed file format. The problem may be that your instructor's database has data in it while yours doesn't.

LINQ file upload malfunction w EF

I am refactoring a section of my app to save a file to the Db in a bit field. In other places I have used the SqlCommand method but here I would like to latch on to my existing EF procedure, for many reasons not apparent. The uploader works fine but it breaks down when it gets to the LINQ. When I query the Db, instead of the usual "0x25504462D..." in the bit field, I get simply "0x". Attempting to view the file gets a message "file is empty". Am I close? The other fields are inserted perfectly, and there are no errors in the insert process. How do I "feed" the file to the fileUpload? Please advise.
HttpPostedFileBase file = Request.Files[inputTagName];
FileUpload fileUpload = new FileUpload();
using (DBEntities ode = new DBEntities())
{
(check if file exists...)
else
{
MyModels.File newfile = new MyModels.File();
newfile.ID = Guid.NewGuid();
newfile.Name = fn;
newfile.VirtualPath = filePath;
newfile.DateTimeUploaded = DateTime.Now;
newfile.binFile = fileUpload.FileBytes;
ode.AddToFiles(newfile);
}
ode.SaveChanges();
}
You could try getting the `byte[]' value of the uploaded file.
HttpPostedFileBase file = Request.Files[inputTagName];
var uploadedFile = new byte[file.InputStream.Length];
using (DBEntities ode = new DBEntities())
{
(check if file exists...)
else
{
MyModels.File newfile = new MyModels.File();
newfile.ID = Guid.NewGuid();
newfile.Name = fn;
newfile.VirtualPath = filePath;
newfile.DateTimeUploaded = DateTime.Now;
newfile.binFile = uploadedFile;
ode.AddToFiles(newfile);
}
ode.SaveChanges();
}
After much lamenting and gnashing of teeth (and encouragement from #denchu) it was apparent I needed to read the data:
HttpPostedFileBase file = Request.Files[inputTagName];
//var uploadedFile = new byte[file.InputStream.Length];
BinaryReader br = new BinaryReader(file.InputStream);
byte[] uploadedFile = br.ReadBytes(file.ContentLength);
using (DBEntities ode = new DBEntities())
{
(check if file exists...)
else
{
MyModels.File newfile = new MyModels.File();
newfile.ID = Guid.NewGuid();
newfile.Name = fn;
newfile.VirtualPath = filePath;
newfile.DateTimeUploaded = DateTime.Now;
newfile.binFile = uploadedFile;
ode.AddToFiles(newfile);
}
ode.SaveChanges();
}

How do I save the BLOB of an image into a sql database without saving it to the filesystem first?

what I've been trying to find out is how I can store the BLOB of an image into my database without saving it to the filesystem first, so directly from the server's memory.
I use an sql server and among other form information I have 2 images that need to be stored in the database. I would also like to know how I can read them out and convert them back to images.
In the db I have "Thumbnail" which is of type "image". That should be correct if I'm not wrong.
For the image upload I use the following asp control:
<asp:FileUpload ID="_imageUpload" runat="server" />
I have never done anything like this as I am quite new to working with databases especially together with websites.
Oh, and sorry if this question has been asked and answered already.
Thanks in advance!
[edit]
My entire code:
protected void _uploadImageBtn_Click(object sender, EventArgs e)
{
string extension;
// checks if file exists
if (!_imageUpload.HasFile)
{
_resultLbl.Text = "Please, Select a File!";
return;
}
// checks file extension
extension = System.IO.Path.GetExtension(_imageUpload.FileName).ToLower();
if (!extension.Equals(".jpg") && !extension.Equals(".jpeg") && !extension.Equals(".png"))
{
_resultLbl.Text = "Only image files (.JPGs and .PNGs) are allowed.";
return;
}
// checks if image dimensions are valid
if (!ValidateFileDimensions(140, 152))
{
_resultLbl.Text = "Maximum allowed dimensions are: width 1520px and height <= 140px.";
return;
}
int fileLen;
string displayString = "";
// Get the length of the file.
fileLen = _imageUpload.PostedFile.ContentLength;
// Create a byte array to hold the contents of the file.
byte[] input = new byte[fileLen - 1];
input = _imageUpload.FileBytes;
// Copy the byte array to a string.
for (int loop1 = 0; loop1 < fileLen; loop1++)
{
displayString = displayString + input[loop1].ToString();
}
try
{
SqlConnection sqlCn = new SqlConnection("Data Source=localhost;Initial Catalog=database;User ID=user;Password=pw");
string qry = "INSERT INTO Project (thumbnail) VALUES (#thumbnail)";
SqlCommand sqlCom = new SqlCommand(qry, sqlCn);
sqlCom.Parameters.Add("#thumbnail", SqlDbType.Image, input.Length).Value = input;
sqlCn.Open();
sqlCom.ExecuteNonQuery();
sqlCn.Close();
}
catch (Exception)
{
(...)
}
}
public bool ValidateFileDimensions(int aHeight, int aWidth)
{
using (System.Drawing.Image image = System.Drawing.Image.FromStream(_imageUpload.PostedFile.InputStream))
{
return (image.Height == aHeight && image.Width == aWidth);
}
}
You can save the returned byte array from FileUpload.FileBytes.
if(_imageUpload.HasFile)
{
byte[] imageData = _imageUpload.FileBytes;
using(SqlConnection sqlCn = new SqlConnection("Server=localhost;database=databaseName;uid=userName;pwd=password"))
{
string qry = "INSERT INTO Project (thumbnail) VALUES (#thumbnail)";
using(SqlCommand sqlCom = new SqlCommand(qry, sqlCn))
{
sqlCom.Parameters.Add("#thumbnail",
SqlDbType.Image,
imageData.Length).Value=imageData;
sqlCn.Open();
sqlCom.ExecuteNonQuery();
sqlCn.Close();
}
}
}
EDIT:
protected void _uploadImageBtn_Click(object sender, EventArgs e)
{
string extension;
// checks if file exists
if (!_imageUpload.HasFile)
{
_resultLbl.Text = "Please, Select a File!";
return;
}
// checks file extension
extension = System.IO.Path.GetExtension(_imageUpload.FileName).ToLower();
if (!extension.Equals(".jpg") && !extension.Equals(".jpeg") && !extension.Equals(".png"))
{
_resultLbl.Text = "Only image files (.JPGs and .PNGs) are allowed.";
return;
}
// checks if image dimensions are valid
if (!ValidateFileDimensions(140, 152))
{
_resultLbl.Text = "Maximum allowed dimensions are: width 1520px and height <= 140px.";
return;
}
byte []input = _imageUpload.FileBytes;
SqlConnection sqlCn = new SqlConnection("Data Source=localhost;Initial
Catalog=database;User ID=user;Password=pw");
string qry = "INSERT INTO Project (thumbnail) VALUES (#thumbnail)";
SqlCommand sqlCom = new SqlCommand(qry, sqlCn);
sqlCom.Parameters.Add("#thumbnail", SqlDbType.Image, input.Length).Value = input;
sqlCn.Open();
sqlCom.ExecuteNonQuery();
sqlCn.Close();
}

Error: The name 'Name' does not exist in the current context

I've gone editing code -> which is never a good thing!
the code is for a file uploader in MVC. The thing was I was uploading two files at a time which meant they were inserted into separate rows in a database. This is the original code:
public ActionResult Index()
{
ViewData["Message"] = "Convert your eBooks!";
foreach (string upload in Request.Files)
{
if (!Request.Files[upload].HasFile1()) continue;
string mimeType = Request.Files[upload].ContentType;
Stream fileStream = Request.Files[upload].InputStream;
string fileName = Path.GetFileName(Request.Files[upload].FileName);
int fileLength = Request.Files[upload].ContentLength;
byte[] fileData = new byte[fileLength];
fileStream.Read(fileData, 0, fileLength);
const string connect = #"Server=localhost;Database=Images;user id=taraw; password=siemensbs;";
using (var conn = new SqlConnection(connect))
{
var qry = "INSERT INTO FileStore (FileContent, MimeType, FileName) VALUES (#FileContent, #MimeType, #FileName)";
var cmd = new SqlCommand(qry, conn);
cmd.Parameters.AddWithValue("#FileContent", fileData);
cmd.Parameters.AddWithValue("#MimeType", mimeType);
cmd.Parameters.AddWithValue("#FileName", fileName);
conn.Open();
cmd.ExecuteNonQuery();
}
}
return View();
}
Here is my attempt at modifying the code in order to take in the files separately as opposed to using a loop, and inserting them into a single row in a database table:
public ActionResult Index()
{
if (!Request.Files["FileUpload1"].HasFile1())
{
string mimeTypePDF = Request.Files["FileUpload1"].ContentType;
Stream fileStreamPDF = Request.Files["FileUpload1"].InputStream;
string fileNamePDF = Path.GetFileName(Request.Files["FileUpload1"].FileName);
int fileLengthPDF = Request.Files["FileUpload1"].ContentLength;
byte[] fileDataPDF = new byte[fileLengthPDF];
fileStreamPDF.Read(fileDataPDF, 0, fileLengthPDF);
}
if(!Request.Files["FileUpload2"].HasFile1())
{
string mimeTypeCover = Request.Files["FileUpload2"].ContentType;
Stream fileStreamCover = Request.Files["FileUpload2"].InputStream;
string fileNameCover = Path.GetFileName(Request.Files["FileUpload2"].FileName);
int fileLengthCover = Request.Files["FileUpload2"].ContentLength;
byte[] fileDataCover = new byte[fileLengthCover];
fileStreamCover.Read(fileDataCover, 0, fileLengthCover);
}
const string connect = #"Server=localhost;Database=Images;user id=taraw; password=siemensbs;";
using (var conn = new SqlConnection(connect))
{
var qry = "INSERT INTO Book (FileContentPDF, MimeTypePDF, FileNamePDF, FileContentCover, MimeTypeCover, FileNameCover) VALUES (#FileContentPDF, #MimeTypePDF, #FileNamePDF, #FileContentCover, #MimeTypeCover, #FileNameCover)";
var cmd = new SqlCommand(qry, conn);
cmd.Parameters.AddWithValue("#FileContentPDF", fileDataPDF);
cmd.Parameters.AddWithValue("#MimeTypePDF", mimeTypePDF);
cmd.Parameters.AddWithValue("#FileNamePDF", fileNamePDF);
cmd.Parameters.AddWithValue("#FileContentCover", fileDataCover);
cmd.Parameters.AddWithValue("#MimeTypeCover", mimeTypeCover);
cmd.Parameters.AddWithValue("#FileNameCover", fileNameCover);
conn.Open();
cmd.ExecuteNonQuery();
}
return View();
}
Now I get the following errors for each cmd.Parameters.AddWithValue:
The name 'fileDataPDF' does not exist
in the current context
I'm presuming this is because it is outside of the IF statements but I'm a bit stuck on how to structure it. I eventually want to use linq to insert the files into the database as the above method is not ideal, but my main aim for now is to just get this bit working.
Any help would be appreciated greatly :)
You need to declare the variables outside of the if conditional scopes. e.g.
string mimeTypePDF;
string fileNamePDF;
byte[] fileDataPDF;
if (!Request.Files["FileUpload1"].HasFile1())
{
mimeTypePDF = Request.Files["FileUpload1"].ContentType;
Stream fileStreamPDF = Request.Files["FileUpload1"].InputStream;
fileNamePDF = Path.GetFileName(Request.Files["FileUpload1"].FileName);
int fileLengthPDF = Request.Files["FileUpload1"].ContentLength;
fileDataPDF = new byte[fileLengthPDF];
fileStreamPDF.Read(fileDataPDF, 0, fileLengthPDF);
}
(Fwiw, I think there are better ways to handle this multifile upload, but the above is simplest way to handle your question.)
You need to declare fileDataPDF outside the if statement, otherwise its only visible to the if block.
How about byte[] fileDataPDF; before if
and fileDataPDF = new byte[fileLengthPDF]; inside if?

Categories

Resources