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?
Related
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.
Here is what I'm doing:
public static MVC_Picture GetPictureRecord(int pictureID)
{
int pictureId = pictureID;
MVC_Picture _picture = new MVC_Picture(); //object that stores name and array
var connString = db.connString;
string cmdText = "SELECT PictureName, PictureImage FROM Picture WHERE CONVERT(INT, ID) =#pictureId;";
using (var connection = new SqlConnection(connString))
{
using (var sqlCmd = new SqlCommand(cmdText, connection))
{
SqlParameter param1 = new SqlParameter();
param1.ParameterName = "#pictureId";
param1.Value = pictureId;
sqlCmd.Parameters.Add(param1);
connection.Open();
SqlDataReader dr = sqlCmd.ExecuteReader();
while (dr.Read())
{
_picture.Id = pictureId;
_picture.PictureName = Convert.ToString(dr["PictureName"]);
_picture.PictureImage = (byte[])(dr["PictureImage"]); //Problem
}
connection.Close();
}
}
return _picture;
}
When I convert to byte[] I get something like: {byte[4354567]}
I'm then trying to convert array to Image like so:
Image img = (Image)converter.ConvertFrom(_picture.PictureImage);
ViewModel.FeaturedImage = img;
And in View I use:
<img src="#ViewModel.FeaturedImage" alt="Featured Image" />
What am I missing?
<img src=... has to point to an image file by its path, eg <img src="/myImage.jpg">. You can't stick a binary representation of the image in the src and have it work.
So you could either write those binary images out to disk somewhere (you probably don't want to do that, as then you're duplicating the data, and would have to manage synchronizing).
Or you could create some kind of image handler, so the <img src= would be something like: <img src="/myHandler/imageId", and then have the handler read the binary data from the database and respond with the image.
This is an MVC controller action that I've used in the past to read a binary PDF out of the DB, and return it as a file. This is in my Competition controller. If this was returning an image, you could call it something like:
<img src="Competition/ViewJobDescription?competitionId=1234" />
public ActionResult ViewJobDescription(int competitionId)
{
string errorMsg = "";
var competition = new DBModel.Competition();
try
{
competition = DBModel.Competition.GetCompetition(competitionId);
if (competition != null && competition.AttachmentContent != null)
{
byte[] fileData = competition.AttachmentContent;
string filename = competition.AttachmentTitle + ".pdf";
return File(fileData, "application/pdf", filename);
}
}
catch (Exception ex)
{
errorMsg += "An error occured: " + ex.Message;
LogFile err = new LogFile();
err.CreateErrorLog(errorMsg);
ModelState.AddModelError(string.Empty, errorMsg);
}
return RedirectToAction("Index", "Home");
}
I currently studying web development using asp.net mvc5, now working on my school project. I would like to store and display image from database. I encountered this error.
Here is my code this is the controller:
public ActionResult AddItems()
{
return View();
}
[HttpPost]
public ActionResult AddItems(FormCollection form)
{
StoreItems i = new StoreItems();
//i.ID = int.Parse(form["AlbumID"]);
i.AlbumName = form["AlbumName"];
i.Artist = form["AlbumArtist"];
i.Genre = form["AlbumGenre"];
i.DateReleased = DateTime.Parse(form["AlbumDateReleased"]);
i.Price = int.Parse(form["AlbumPrice"]);
i.Downloads = int.Parse(form["AlbumDownloads"]);
i.Listens = int.Parse(form["AlbumListens"]);
i.RecordLabel = form["RecordLabel"];
HttpPostedFileBase file = Request.Files[0];
i.PicturePath = file.FileName.ToString();
DAL.AddItems(i);
return RedirectToAction("ItemLists");
}
And here is the model:
public static void AddItems(StoreItems i)
{
byte[] bytes;
if (string.IsNullOrEmpty(i.PicturePath))
{
string filename = System.Web.HttpContext.Current.Server.MapPath("~/Content/Images/default-artwork.png");
bytes = System.IO.File.ReadAllBytes(filename);
}
else
{
string filename = i.PicturePath;
bytes = System.IO.File.ReadAllBytes(filename);
}
SqlConnection con = new SqlConnection(DAL.cs);
con.Open();
SqlCommand com = new SqlCommand(
"INSERT INTO AlbumsTb ( AlbumName, Artist, Genre, DateReleased, Price, Downloads, Listens, RecordLabel, DateAdded, AlbumArt) VALUES( #AlbumName, #Artist, #Genre, #DateReleased, #Price, #Downloads, #Listens, #RecordLabel, #DateAdded, #AlbumArt)", con);
//com.Parameters.AddWithValue("#ID", i.ID);
com.Parameters.AddWithValue("#AlbumName", SqlDbType.VarChar).Value = i.AlbumName;
com.Parameters.AddWithValue("#Artist", SqlDbType.VarChar).Value = i.Artist;
com.Parameters.AddWithValue("#Genre", SqlDbType.VarChar).Value = i.Genre;
com.Parameters.AddWithValue("#DateReleased", SqlDbType.Date).Value = i.DateReleased;
com.Parameters.AddWithValue("#Price",i.Price);
com.Parameters.AddWithValue("#Downloads", i.Downloads);
com.Parameters.AddWithValue("#Listens", i.Listens);
com.Parameters.AddWithValue("#RecordLabel", SqlDbType.VarChar).Value = i.RecordLabel;
com.Parameters.AddWithValue(#"DateAdded", DateTime.Now.ToString());
com.Parameters.AddWithValue("#AlbumArt", SqlDbType.VarBinary).Value = bytes;
com.ExecuteNonQuery();
con.Close();
}
There is no file posted with the request. Which means the array is empty. Hence the index out of range error. You should also practice defensive coding and check to make sure the array is populated. If the file is mandatory then you can gracefully error out and return relevant error message (BadRequest..etc)
[HttpPost]
public ActionResult AddItems(FormCollection form)
{
StoreItems i = new StoreItems();
//i.ID = int.Parse(form["AlbumID"]);
i.AlbumName = form["AlbumName"];
i.Artist = form["AlbumArtist"];
i.Genre = form["AlbumGenre"];
i.DateReleased = DateTime.Parse(form["AlbumDateReleased"]);
i.Price = int.Parse(form["AlbumPrice"]);
i.Downloads = int.Parse(form["AlbumDownloads"]);
i.Listens = int.Parse(form["AlbumListens"]);
i.RecordLabel = form["RecordLabel"];
var files = Request.Files;
if(files.Count > 0) {
var file = files[0];
i.PicturePath = file.FileName.ToString();
} else {
//...return some error code or validation message.
}
DAL.AddItems(i);
return RedirectToAction("ItemLists");
}
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.
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)