On my local machine everything works well but..
After publishing my MVC4 web project there is a problem with an uploaded Excel file.
I load an HttpPostedFileBase and send the path to my BL. There I load it to dataTable and on my second call I get it to a list.
Here is the code..
Controller:
[HttpPost]
public ActionResult UploadCards(HttpPostedFileBase file, string sheetName, int ProductID)
{
try
{
if (file == null || file.ContentLength == 0)
throw new Exception("The user not selected a file..");
var fileName = Path.GetFileName(file.FileName);
var path = Server.MapPath("/bin");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
path = Path.Combine(path, fileName);
file.SaveAs(path);
DataTable cardsDataTable = logic.LoadXLS(path, sheetName);
cardsToUpdate = logic.getUpdateCards(cardsDataTable, ProductID);
foreach (var item in cardsToUpdate)
{
if (db.Cards.ToList().Exists(x => x.SerialNumber == item.SerialNumber))
cardsToUpdate.Remove(item);
}
Session["InfoMsg"] = "click update to finish";
}
catch (Exception ex)
{
Session["ErrorMsg"] = ex.Message;
}
return View("viewUploadCards", cardsToUpdate);
}
BL:
public DataTable LoadXLS(string strFile, String sheetName)
{
DataTable dtXLS = new DataTable(sheetName);
try
{
string strConnectionString = "";
if (strFile.Trim().EndsWith(".xlsx"))
strConnectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0 Xml;HDR=YES;IMEX=1\";", strFile);
else if (strFile.Trim().EndsWith(".xls"))
strConnectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\";", strFile);
OleDbConnection SQLConn = new OleDbConnection(strConnectionString);
SQLConn.Open();
OleDbDataAdapter SQLAdapter = new OleDbDataAdapter();
string sql = "SELECT * FROM [" + sheetName + "$]";
OleDbCommand selectCMD = new OleDbCommand(sql, SQLConn);
SQLAdapter.SelectCommand = selectCMD;
SQLAdapter.Fill(dtXLS);
SQLConn.Close();
}
catch (Exception ex)
{
string res = ex.Message;
return null;
}
return dtXLS;
}
and:
public List<Card> getUpdateCards(DataTable dt, int prodId)
{
List<Card> cards = new List<Card>();
try
{
Product product = db.Products.Single(p => p.ProductID == prodId);
foreach (DataRow row in dt.Rows)
{
cards.Add(new Card
{
SerialNumber = row[0].ToString(),
UserName = row[1].ToString(),
Password = row[2].ToString(),
Activated = false,
Month = product.Months,
Bandwidth = product.Bandwidth,
ProductID = product.ProductID,
// Product = product
});
}
}
catch (Exception ex)
{
db.Log.Add(new Log { LogDate = DateTime.Now, LogMsg = "Error : " + ex.Message });
}
return cards;
}
Now I think Windows Azure doesn't let me save this file because on the middle view when I supposed to see the data - I don't see it.
I thought of some ways...
one - not saving the file, but I don't see how to complete the ConnectionString...
second maybe there is a way to save the file there.
I'd love to get suggestions for solving this problem...
10x and sorry for my bad English =)
I'm embarrassed but I found a similar question here.. Not exactly but it gave me a good direction.
Hare the finally result:
[HttpPost]
public ActionResult UploadCards(HttpPostedFileBase file, string sheetName, int ProductID)
{
IExcelDataReader excelReader = null;
try
{
if (file == null || file.ContentLength == 0)
throw new Exception("The user not selected a file..");
if (file.FileName.Trim().EndsWith(".xlsx"))
excelReader = ExcelReaderFactory.CreateOpenXmlReader(file.InputStream);
else if (file.FileName.Trim().EndsWith(".xls"))
excelReader = ExcelReaderFactory.CreateBinaryReader(file.InputStream);
else
throw new Exception("Not a excel file");
cardsToUpdate = logic.getUpdateCards(excelReader.AsDataSet().Tables[sheetName], ProductID);
foreach (var item in cardsToUpdate)
{
if (db.Cards.ToList().Exists(x => x.SerialNumber == item.SerialNumber))
cardsToUpdate.Remove(item);
}
Session["InfoMsg"] = "Click Update to finish";
}
catch (Exception ex)
{
Session["ErrorMsg"] = ex.Message;
}
finally
{
excelReader.Close();
}
return View("viewUploadCards", cardsToUpdate);
}
10q all.
EDIT: download, reference and using
the dll is avalibale hare
i add the reference to the Excel.dll and i add the using Excel;
The problem might be caused by writing the file to the disk. Cloud providers usually do not allow the applications to write to the disk.
In your case it seems that the file is written to the disk only temporary and is loaded directly to the DB. You should be able to open the stream from the uploaded file directly and write it directly to the DB - without writing to the disk.
Check the exception which you are stocking in the Session - you should find more information there.
#hoonzis is right, writing files to disk in the cloud is not permited(you can't event get or set a path for the file). You should use blob storage, much more efficient for files and is cheaper than sql. I recommend to use the table storage service, it is noSQL but it's more cheaper than azure sql.
Use azure sql only if it is a must for your solution.
Blob storage see more details here: http://www.windowsazure.com/en-us/develop/net/how-to-guides/blob-storage/
Table storage: http://www.windowsazure.com/en-us/develop/net/how-to-guides/table-services/
Some more information about choosing the right storage you can find here: http://www.windowsazure.com/en-us/develop/net/fundamentals/cloud-storage-scenarios/
Related
I have decided to develop desktop program with usage of SQLite datatbase and with help of C# programming language. One of the necessary functions that must be present is uploding the doc file into SQLite database and downloding the same type of files from it. But I cannot download the word document from db programically. It does not appear in the needed directory. So I have a doubt about the correctness of the code.
Accordingly the plan, first and foremost I should create doc file and perform some manipulations on it. It's another topic and it's related to DocX. The file could be create in some particular directory, but after full editing the file should be deleted and uploaded previously to SQLite db in the field marked with blob data type. In any moment user must have ability to download the document into some chosen directory.
byte[] file;
using (var stream = new FileStream(varFilePath, FileMode.Open, FileAccess.Read))
{
using (var reader = new BinaryReader(stream))
{
file = reader.ReadBytes((int)stream.Length);
}
}
SQLiteConnection m_dbConn = new SQLiteConnection();
try
{
GetDB cl = new GetDB();
m_dbConn = new SQLiteConnection("Data Source=" + cl.dbFileName + ";Version=3;");
m_dbConn.Open();
if (m_dbConn.State != ConnectionState.Open)
{
MessageBox.Show("Open connection with database");
return;
}
else
{
string Q = "INSERT INTO file_" + Convert.ToString(IdOrganization) +
"(id, file_contract) VALUES(" + last_rowid + ", #File);";
SQLiteCommand m_sqlCmd = new SQLiteCommand();
m_sqlCmd.Connection = m_dbConn;
m_sqlCmd.CommandText = Q;
m_sqlCmd.Parameters.Add("#File", (DbType)SqlDbType.VarBinary, file.Length).Value = file;
m_sqlCmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
MessageBox.Show("1" + ex.Message);
}
m_dbConn.Close();
File.Delete("Договір_підряду.doc");
m_dbConn = new SQLiteConnection();
try
{
GetDB cl = new GetDB();
m_dbConn = new SQLiteConnection("Data Source=" + cl.dbFileName + ";Version=3;");
m_dbConn.Open();
if (m_dbConn.State != ConnectionState.Open)
{
MessageBox.Show("Open connection with database");
return;
}
else
{
using (var sqlQuery = new SQLiteCommand(#"SELECT file_contract FROM file_" +
Convert.ToString(IdOrganization) + " WHERE " +
"id = #varID", m_dbConn))
{
sqlQuery.Parameters.AddWithValue("#varID", last_rowid);
using (var sqlQueryResult = sqlQuery.ExecuteReader())
if (sqlQueryResult != null)
{
sqlQueryResult.Read();
var blob = new Byte[(sqlQueryResult.GetBytes(0, 0, null, 0, int.MaxValue))];
sqlQueryResult.GetBytes(0, 0, blob, 0, blob.Length);
using (var fs = new FileStream(#"C:\Users\Default\Desktop\1.doc",
FileMode.Create, FileAccess.Write))
fs.Write(blob, 0, blob.Length);
}
}
}
}
catch(Exception ex)
{
MessageBox.Show("2" + ex.Message);
}
I have no opportunity to download db file because of the exception "Specified cast is not valid". This error occurs on the part where I'm trying to download the file from db. (Where the digit 2 is present in the text of MessageBox) Probably the value of the field is empty, but according to the Database Management System the column is not null. Also there's no complaints about the uploading document into database.
I'm allowing users to upload data from an Excel file to my database, and want to display friendly error messages if one of their cells is in the wrong format. In total, there will be 20 or so cells to upload, but right now I'm just trying two. The Excel upload I'm trying has some random text in the MedicalTotal field, which should instead be formatted as a decimal. I verified that my code is looking at the right field. The following controller code does nothing. Nothing is written to the database, and the same view is reloaded.
In the watch window, I get a message of "Convert.ToDecimal(table[0]) threw an exception of type System.FormatException" I have tried the code with both Exception and FormatException. I'm open to other methods of catching errors, keeping in mind that I'll be repeating the try/catch process about 20 times.
[Authorize]
[HttpPost]
public ActionResult CreateBenefitSummary(HttpPostedFileBase FileUpload, Guid ResponseId)
{
BenefitsUploadViewModel model = new BenefitsUploadViewModel();
if (FileUpload != null)
{
// tdata.ExecuteCommand("truncate table OtherCompanyAssets");
if (FileUpload.ContentType == "application/vnd.ms-excel" || FileUpload.ContentType == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{
string filename = FileUpload.FileName;
string targetpath = Server.MapPath("~/Doc/");
FileUpload.SaveAs(targetpath + filename);
string pathToExcelFile = targetpath + filename;
var connectionString = "";
if (filename.EndsWith(".xls"))
{
connectionString = string.Format("Provider=Microsoft.Jet.OLEDB.4.0; data source={0}; Extended Properties=Excel 8.0;", pathToExcelFile);
}
else if (filename.EndsWith(".xlsx"))
{
connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0 Xml;HDR=YES;IMEX=1\";", pathToExcelFile);
}
var excelFile = new ExcelQueryFactory(pathToExcelFile);
var table = (from a in excelFile.WorksheetRangeNoHeader("B2", "B32", "Benefits Template") select a[0]).ToList();
TempData["ResponseId"] = ResponseId;
try
{
Benefits b = new Benefits();
b.ResponseId = ResponseId;
try
{
b.MedicalTotal = Convert.ToDecimal(table[0]);
}
catch (FormatException)
{
model.ErrorList.Add("Medical Total cell must use Number, Currency, or Accounting format.");
}
b.StdSicknessAccident = Convert.ToDecimal(table[1]);
if (model.ErrorList.Count > 0) {
return View(model);
}
db.benefits.Add(b);
db.SaveChanges();
}
catch (SqlException ex)
{
ViewBag.Message = ex.Message;
}
catch (Exception ex)
{
ViewBag.Message = ex.Message;
}
//deleting excel file from folder
if ((System.IO.File.Exists(pathToExcelFile)))
{
System.IO.File.Delete(pathToExcelFile);
}
TempData["ResponseId"] = ResponseId;
return RedirectToAction("CreateBenefitSummary", "Surveys");
}
}
return View();
}
Your convert.ToDecimal should probably use a Decimal.TryParse instead, then showing the error message after an if statement seeing if the results parsed. Using try/catch for flow control is generally considered bad practice.
something like:
Decimal decVal;
if (Decimal.TryParse(table[0], out decVal))
{
b.MedicalTotal = decVal;
}
else
{
model.ErrorList.Add("Medical Total cell must use Number, Currency, or Accounting format.");
}
I want to upload the excel file of record 2500. This process takes time more than 5 minutes approximate. I want to optimize it to less than a minute maximum.
Find the best way of optimization of that code. I am using Dbgeography for location storing. File is uploaded and save the data properly. Everything is working find but I need optimization.
public ActionResult Upload(HttpPostedFileBase FileUpload)
{
if (FileUpload.ContentLength > 0)
{
string fileName = Path.GetFileName(FileUpload.FileName);
string ext = fileName.Substring(fileName.LastIndexOf('.'));
Random r = new Random();
int ran = r.Next(1, 13);
string path = Path.Combine(Server.MapPath("~/App_Data/uploads"), DateTime.Now.Ticks + "_" + ran + ext);
try
{
FileUpload.SaveAs(path);
ProcessCSV(path);
ViewData["Feedback"] = "Upload Complete";
}
catch (Exception ex)
{
ViewData["Feedback"] = ex.Message;
}
}
return View("Upload", ViewData["Feedback"]);
}
Here is other method from where the file is uploaded and save it to the database..
private void ProcessCSV(string filename)
{
Regex r = new Regex(",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))");
StreamReader sr = new StreamReader(filename);
string line = null;
string[] strArray;
int iteration = 0;
while ((line = sr.ReadLine()) != null)
{
if (iteration == 0)
{
iteration++;
continue; //Because Its Heading
}
strArray = r.Split(line);
StoreLocation store = new StoreLocation();
store.Name = strArray[0];
store.StoreName = strArray[1];
store.Street = strArray[2];
store.Street2 = strArray[3];
store.St_City = strArray[4];
store.St_St = strArray[5];
store.St_Zip = strArray[6];
store.St_Phone = strArray[7];
store.Office_Phone = strArray[8];
store.Fax = strArray[9];
store.Ownership = strArray[10];
store.website = strArray[11];
store.Retailer = check(strArray[12]);
store.WarehouseDistributor = check(strArray[13]);
store.OnlineRetailer = check(strArray[14]);
string temp_Add = store.Street + "," + store.St_City;
try
{
var point = new GoogleLocationService().GetLatLongFromAddress(temp_Add);
string points = string.Format("POINT({0} {1})", point.Latitude, point.Longitude);
store.Location = DbGeography.FromText(points);//lat_long
}
catch (Exception e)
{
continue;
}
db.StoreLocations.Add(store);
db.SaveChanges();
}
The obvious place to start would be your external call to the Geo Location service, which it looks like you are doing for each iteration of the loop. I don't know that service, but is there any way you can build up a list of addresses in memory, and then hit it once with multiple addresses, then go back and amend all the records you need to update?
The call to db.SaveChanges() which updates the database, this is happening for every line.
while (...)
{
...
db.StoreLocations.Add(store);
db.SaveChanges(); // Many database updates
}
Instead, just call it once at the end:
while (...)
{
...
db.StoreLocations.Add(store);
}
db.SaveChanges(); // One combined database update
This should speed up your code nicely.
Can anyone help me exporting in excel as number and not text? Also, I want to freeze the first row. This is the function I am using to export to excel. Also, I want the rows to be in alternate color:
public FilePathResult ExportToExcel(){
log.Info("Action ExportToExcel for user " + User.Identity.GetUserName());
List<string> dataTypes = new List<string>();
NameValueCollection parameters = Request.Params;
string query = QueryUtility.ConstructQueryForExcel(parameters);
DataSet ds = new DataSet();
DataTable dt = DaoUtilitySingleton.Instance.ExecuteQueryToGetDataTable(query);
ds.Tables.Add(dt);
log.Info("Query for export " + query);
log.Info("Column names : " + parameters["columnNames"]);
string guid = Guid.NewGuid().ToString();
string fileName = guid;
fileName += System.DateTime.Now.Ticks.ToString();
fileName += ".xlsx";
string destinationPath = Path.Combine(
Server.MapPath("~/App_Data/ExcelExports"));
if (!Directory.Exists(destinationPath))
{
log.Info("Directory does not exist. Creating Directory first");
Directory.CreateDirectory(destinationPath);
}
destinationPath = Path.Combine(destinationPath, fileName);
log.Info("Excel file will be saved as " + destinationPath);
//currently , this function return data which is in text and not number
try
{
if (!(new ExcelUtility()).CreateExcelDocumentFromDataset(ds,
destinationPath))
{
log.Error("Excel file could not be created");
return null;
}
}
catch (Exception ex)
{
GeneralUtility.LogException(log,
"Excel file could not be created",
ex);
throw;
}
log.Info("FIle created successfully");
FilePathResult file = File(destinationPath, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", Properties.Instance.FileForExcel);
return file;
//return the file
}
You can help yourself with an OpenXML wrapper. Rigth now I'm using SpreadLight. It handles most of the interaction with excel, You can digg into the examples to it's advanced features.
Suppose I have this method from one class:
private void btnChangeImage_Click(object sender, EventArgs e)
{
using (var openFileDialogForImgUser = new OpenFileDialog())
{
string location = null;
string fileName = null;
openFileDialogForImgUser.Filter = "Image Files (*.jpg, *.png, *.gif, *.bmp)|*.jpg; *.png; *.gif; *.bmp|All Files (*.*)|*.*"; // filtering only picture file types
var openFileResult = openFileDialogForImgUser.ShowDialog(); // show the file open dialog box
if (openFileResult == DialogResult.OK)
{
using (var formSaveImg = new FormSave())
{
var saveResult = formSaveImg.ShowDialog();
if (saveResult == DialogResult.Yes)
{
imgUser.Image = new Bitmap(openFileDialogForImgUser.FileName); //showing the image opened in the picturebox
location = openFileDialogForImgUser.FileName;
fileName = openFileDialogForImgUser.SafeFileName;
FileStream fs = new FileStream(location, FileMode.Open, FileAccess.Read); //Creating a filestream to open the image file
int fileLength = (int)fs.Length; // getting the length of the file in bytes
byte[] rawdata = new byte[fileLength]; // creating an array to store the image as bytes
fs.Read(rawdata, 0, (int)fileLength); // using the filestream and converting the image to bits and storing it in an array
MySQLOperations MySQLOperationsObj = new MySQLOperations("localhost", "root", "myPass");
MySQLOperationsObj.saveImage(rawdata);
fs.Close();
}
else
openFileDialogForImgUser.Dispose();
}
}
}
}
And this method from another class (MySQLOperations):
public void saveImage(byte[] rawdata)
{
try
{
string myConnectionString = "Data Source = " + server + "; User = " + user + "; Port = 3306; Password = " + password + ";";
MySqlConnection myConnection = new MySqlConnection(myConnectionString);
string currentUser = FormLogin.userID;
string useDataBaseCommand = "USE " + dbName + ";";
string updateTableCommand = "UPDATE tblUsers SET UserImage = #file WHERE Username = \'" + currentUser + "\';";
MySqlCommand myCommand = new MySqlCommand(useDataBaseCommand + updateTableCommand, myConnection);
myCommand.Parameters.AddWithValue("#file", rawdata);
myConnection.Open();
myCommand.ExecuteNonQuery();
myConnection.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
If I must, this is my constructor for the MySQLOperations class:
public MySQLOperations(string server, string user, string password)
{
this.server = server;
this.user = user;
this.password = password;
}
What I'm trying to do is save an image file (which the user selects through the open file dialog box) to the database. Problem is I get this error: "You have an error in your SQL syntax; check the manual that correponds to your MySQL server version for the right syntax to use near ';UPDATE tblUsers SET UserImage = _binary'?PNG ... (and so on with some random characters). So, I can't really save the file in the database. I would love to post a picture on how the error is seen at the MessageBox, but I guess my account is not given the privilege to do so yet.
I'm not really sure where the syntax error is in that. I'm thinking, it's in the #file - but that's just a guess. Your help would be very much appreciated.
And oh, the table column UserImage has a type of LONGBLOB.
Other things I'm interested to know about also:
Is it necessary that I add another column for my table to store the
size of the file (because I'm going to need to retrieve the file
to display the image later on)?
Is it okay that I used the using statement that way in the method
btnChangeImage_Click?
Thank you very much.
EDIT: Got the problem solved. Such a simple thing not given attention to. Thanks to everybody who tried to help. I'm still willing to hear your opinion on the questions at the bottom (those on bullets).
I think the problem is in the following line of code:
WHERE Username = \'" + currentUser + "\';"
It should change to the following one:
WHERE Username = " + currentUser;
Or better (to avoid sql injections) to the following one:
WHERE Username = #Username";
myCommand.Parameters.AddWithValue("#Username", currentUser);
Do not store binary files in a MySQL table. Instead, save it to disk and save path to PNG file to MySQL database. Also, use Christos advice to avoid SQL injections.