How to write data into Excel file and save it? EPPlus C# - asp.net

I have the code to execute multiple stored procedures from SQl. However, I am having an issue on how to write the data from the stored procedures into the Excel file. After writing the data into the excel file, I would like to save the Excel workbook. How can I achieve this? Any help is very much appreciated.
This is what I have so far:
public static void ExecuteStoredProcedures()
{
using (SqlConnection connection = new SqlConnection("Data Source=the connection goes here.."))
{
SqlTransaction transaction;
connection.Open();
transaction = connection.BeginTransaction();
try
{
SqlCommand cmdOne = new SqlCommand("exec ", connection);
SqlCommand cmdTwo = new SqlCommand("exec", connection);
SqlCommand cmdThree = new SqlCommand("exec", connection);
cmdOne.ExecuteNonQuery();
cmdTwo.ExecuteNonQuery();
cmdThree.ExecuteNonQuery();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
connection.Close();
}
}
}
public static void SaveExcelFile()
{
string SheetLocation = ConfigurationManager.AppSettings["SheetLocation"];
if (!System.IO.Directory.Exists(SheetLocation))
{
System.IO.Directory.CreateDirectory(SheetLocation);
}
ExecuteStoredProcedures(); //Should I call the method to load the data that comes from the stored procedures? Or what should I do to write the data into the file?
var newFile = new FileInfo(#"C:\Users\");
using (ExcelPackage xlPackage = new ExcelPackage(newFile))
{
xlPackage.Save();
}
}

Get data from stored procedures in the form of a Dataset or DataTables.
Create worksheet:
using (ExcelPackage xlPackage = new ExcelPackage(newFile))
{
ExcelWorksheet ws = xlPackage.Workbook.Worksheets.Add(AnyName);
}
Loop in Datatable rows and columns like a 2d array and create cells in the worksheet and add data in the created cells:
int rowIndex = 0
foreach (DataRow DataTableRow in dt.Rows)
{
int colIndex = 1;
rowIndex++;
foreach (DataColumn DataTableColumn in dt.Columns)
{
var cell = ws.Cells[rowIndex, colIndex];
cell.Value = DataTableRow[DataTableColumn.ColumnName];
colIndex++;
}
}

Related

An exception of type 'System.IndexOutOfRangeException' occurred in System.Data.dll : Cannot find column 3

I have try this code to import data to SQL table but it is showing up the error:
This error occurs when I upload an Excel file, but when I upload Notepad file the information imported to SQL table.
the place of error:
dt.Rows[dt.Rows.Count - 1][i] = cell;
So Please can anyone try to figure out the error and can send me the correct code
protected void Upload(object sender, EventArgs e)
{
string csvPath = Server.MapPath("~/Files/") + Path.GetFileName(FileUpload1.PostedFile.FileName);
FileUpload1.SaveAs(csvPath);
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[3] { new DataColumn("PersonId", typeof(string)),
new DataColumn("Name", typeof(string)), new DataColumn("Salary",typeof(string))});
string csvData = File.ReadAllText(csvPath);
foreach (string row in csvData.Split('\n'))
{
if (!string.IsNullOrEmpty(row))
{
dt.Rows.Add();
int i = 0;
foreach (string cell in row.Split(','))
{
dt.Rows[dt.Rows.Count - 1][i] = cell;
i++;
}
}
}
using (SqlConnection con = new SqlConnection("Data Source=Server Name;Initial Catalog=AD;Integrated Security=True"))
{
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(con))
{
//Set the database table name.
sqlBulkCopy.DestinationTableName = "dbo.Employee";
con.Open();
sqlBulkCopy.WriteToServer(dt);
con.Close();
}
}
}
}
}

How do I change the format of a specific column in EPPlus?

I've used EPPlus to download my datatable from my website / database to an Excel sheet and the first picture is the result I get. The second picture is what I would like it to be.
Questions:
How do I change the format of my Timestamp to "time"?
Obviously title would still be a string format.
How do I make the width of the columns to match the longest word inside?
So that 80% of the message isn't hidden and you have to drag the column out to read the entire message.
Edit: Completely forgot to add my code...
public ActionResult ExportData()
{
DataTable dataTable = GetData();
using (ExcelPackage package = new ExcelPackage())
{
var ws = package.Workbook.Worksheets.Add("My Sheet");
//true generates headers
ws.Cells["1:1"].Style.Font.Bold = true;
ws.Cells["A1"].LoadFromDataTable(dataTable, true);
ws.Cells[ws.Dimension.Address].AutoFitColumns();
var stream = new MemoryStream();
package.SaveAs(stream);
string fileName = "Log.xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
stream.Position = 0;
return File(stream, contentType, fileName);
}
}
public DataTable GetData()
{
DataTable dt = new DataTable();
if (ModelState.IsValid)
{
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MySqlConnection"].ConnectionString))
{
using (SqlCommand comm = conn.CreateCommand())
{
comm.Parameters.AddWithValue("#val1", Session["myID"]);
comm.Parameters.AddWithValue("#val2", "%" + Session["mySearchString"] + "%");
comm.CommandText = "SELECT * FROM dbo.Log WHERE CustomerId = #val1 AND Message LIKE #val2";
try
{
conn.Open();
dt.Load(comm.ExecuteReader());
}
catch (SqlException e)
{
throw new Exception(e.ToString());
}
}
}
}
return dt;
}
Just need to set the Numberformat.Format string. Like this:
ws.Column(2).Style.Numberformat.Format = "hh:mm:ss";
If you want to customize the actual just there are plenty of resource online like http://www.ozgrid.com/Excel/excel-custom-number-formats.htm. Or you can just open it in excel, set the format to Custom and experiment with the string.

Populate web form edit page C# ASP.NET

I am trying to select a single row on a gridview and have that selection take me to a separate edit page with the data populated. I have the idea of using a session variable to hold the row id and then retrieving the data on page load and populating the text boxes. My question is whether or not this is the best method to go about doing this? I would prefer to not use the inline edit option in gridview as I have too many columns that would require scrolling horizontally. Here is my page load method using the session variable:
if (Session["editID"] != null)
{
dbCRUD db = new dbCRUD();
Recipe editRecipe = new Recipe();
var id = Convert.ToInt32(Session["editID"]);
Session.Remove("editID");
editRecipe = db.SelectRecord(id);
addName.Text = editRecipe.Name;
}
Here is the SelectRecord method that is used to retrieve the row:
public Recipe SelectRecord(int id)
{
Recipe returnedResult = new Recipe();
var dbConn = new SqlConnection(connString);
var dbCommand = new SqlCommand("dbo.selectRecipe", dbConn);
dbCommand.CommandType = CommandType.StoredProcedure;
dbCommand.Parameters.Add("#ID", SqlDbType.Int).Value = id;
dbConn.Open();
SqlDataReader reader = dbCommand.ExecuteReader();
while (reader.HasRows)
{
while (reader.Read())
{
returnedResult.Name = reader["Name"].ToString();
}
}
dbConn.Close();
return returnedResult;
}
I'm probably not utilizing the SQLDataReader appropriately, but my result is no data in the reader therefore no returned data when calling the method. Any help is appreciated - thanks in advance!
Few things you should be aware of here:
1.
You should use while (reader.HasRows) in case your stored procedure returns multiple resultsets. In that case you have to iterate through the result sets. See Retrieving Data Using a DataReader. So, if selectRecipe returns multiple resultsets (I am assuming this is not the case), change your code to this:
while (reader.HasRows)
{
while (reader.Read())
{
returnedResult.Name = reader["Name"].ToString();
}
reader.NextResult();
}
2.If selectRecipe returns single result set, change the while loop to if(){}:
if(reader.HasRows)
{
while (reader.Read())
{
returnedResult.Name = reader["Name"].ToString();
}
}
3. I would probably use using to manage the connection better (using Statement) :
public Recipe SelectRecord(int id)
{
Recipe returnedResult = new Recipe();
using (SqlConnection dbConn = new SqlConnection(connString))
{
var dbCommand = new SqlCommand("dbo.selectRecipe", dbConn);
dbCommand.CommandType = CommandType.StoredProcedure;
dbCommand.Parameters.AddWithValue("#ID", id);
dbConn.Open();
SqlDataReader reader = dbCommand.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
returnedResult.Name = reader["Name"].ToString();
}
}
reader.Close();
}
return returnedResult;
}

OleDb - Retrieving Excel worksheet names also retrieves Defined Names

I am trying to retrieve a list of the worksheets in an Excel workbook, but the collection I get back has both the sheet names and the data column id's, which seem to be called 'Defined Names' in the original xlsx xml. Can you tell me how to return only the worksheet names?
The code I'm using is along the lines of:
OleDbConnection connExcel = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;"
+ #"Data Source=" + FilePath + ";"
+ #"Extended Properties=""Excel 8.0;HDR=Yes;""");
OleDbCommand cmdExcel = new OleDbCommand();
cmdExcel.Connection = connExcel;
connExcel.Open();
DataTable testTable = connExcel.GetSchema("Tables");
The contents of the resulting testTable collection contain entries under TABLE_NAME of:
DATA1
DATA2
DATA3
DATA4
DATA5
Sheet1$
TEST1
-TEST2
TESTHKEY
TESTKEYS
TESTVKEY
They all have a TABLE_TYPE of TABLE.
The original workbook corresponding to the above would have 1 worksheet containing 5 columns, the first row would contain a header. I'm only interested in the Sheet1$ entry. The spreadsheet is
created in Excel 2010, I'm trying to process it in an ASP.NET 4 app written in C#. Potentially, the worksheet name may have been changed so I can't guarrantee that it will always be Sheet1$.
My first thoughts were wrong so I came up with this as a workaround. The actual worksheet names returned should always end with $, so I hacked it to check for that. Messy but you get the general idea I'm sure.
OleDbConnection connExcel = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;"
+ #"Data Source=c:\test.xlsx;"
+ #"Extended Properties=""Excel 12.0 Xml;HDR=Yes;""");
OleDbCommand cmdExcel = new OleDbCommand();
cmdExcel.Connection = connExcel;
connExcel.Open();
DataTable testTable = connExcel.GetSchema("Tables");
String[] excelSheets = new String[testTable.Rows.Count];
int i = 0;
foreach (DataRow row in testTable.Rows)
{
excelSheets[i] = row["TABLE_NAME"].ToString();
if (excelSheets[i].EndsWith("$"))
{
Console.WriteLine(excelSheets[i] = row["TABLE_NAME"].ToString());
i++;
}
else
{
i++;
}
}
Console.ReadLine();
I had a similar issue but with the exception that it showed me Sheets that didn't exist in Excel. Even though this post is a bit old now, maybe somebody finds this and finds it helpful.
My Code:
//OpenFileDialog
try
{
OpenFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
OpenFileDialog.Filter = "XLSX Files(*.xlsx)|*.xlsx|All Files (*.*)|*.*";
OpenFileDialog.ShowDialog();
}
catch (Exception ex)
{
//some Error Message
}
//read into Combobox
try
{
OleDbConnection con = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + OpenFileDialog.FileName + ";Extended Properties=Excel 12.0;");
con.Open();
DataTable dt = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
con.Close();
this.Combobox.Items.Clear();
for (int i = 0; i < dt.Rows.Count; i++)
{
String sheetName = dt.Rows[i]["TABLE_NAME"].ToString();
sheetName = sheetName.Substring(0, sheetName.Length - 1);
//cheap Filter to filter out unneeded/wrong sheets
if (sheetName.Replace("'", " ").Replace("$", " ").TrimStart().TrimEnd().Contains("#") != true)
{
this.Combobox.Items.Add(sheetName.Replace("'", " ").Replace("$", " ").TrimStart().TrimEnd());
}
}
}
catch (Exception Ex)
{
//some Error Message
}
This might not be the best solution, but it works quite well for me.
private static string EXCEL_CONNECTIONSTRING = string.Format("Provider=Microsoft.ACE.OLEDB.12.0; data source={0}; Extended Properties=Excel 12.0;", "#{FILENAME}");
private IEnumerable<string> GetWorksheetNames(string excelFile)
{
var currentConnectionString = EXCEL_CONNECTIONSTRING.Replace("#{FILENAME}", excelFile);
using (OleDbConnection connection = new OleDbConnection(currentConnectionString))
{
OleDbCommand cmdExcel = new OleDbCommand();
cmdExcel.Connection = connection;
connection.Open();
DataTable dt = connection.GetSchema("Tables");
IEnumerable<string> excelSheets = dt.Rows.Cast<DataRow>().Select(row => row["TABLE_NAME"].ToString());
dt.Dispose();
connection.Close();
return excelSheets;
}
}

Download multiple excel files from the DataTable

I am trying to execute a query using for loop. For each loop it should download an excel file. The solution works perfectly, but only the first file is downloaded and the other two files are not downloaded. I have also attached the complete code below.
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Btn_Click(object sender, EventArgs e)
{
DataTable it = GetList();
foreach(DataRow dr in it.Rows)
{
string a = dr[0].ToString();
for (int i = 0; i < 3; i++)
{
string inm = it.Rows[i][0].ToString();
DataTable gt = GetData(inm);
ExportToSpreadsheet(gt, "Samples");
}
}
}
public DataTable GetData(string i)
{
SqlCommand command = null;
SqlConnection conn = null;
conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
conn.Open();
command = new SqlCommand("SELECT id, name, class FROM StudentTable WHERE (id = " + i + ") ORDER BY name";
DataTable dt = new DataTable();
SqlDataAdapter ada = new SqlDataAdapter(command);
ada.Fill(dt);
return dt;
}
public static void ExportToSpreadsheet(DataTable table, string name)
{
HttpContext context = HttpContext.Current;
context.Response.ClearContent();
context.Response.ContentType = "text/vnd.ms-excel";
context.Response.AppendHeader("Content-Disposition", "attachment; filename=" + name + ".xls");
string tab = "";
foreach (DataColumn dc in table.Columns)
{
context.Response.Write(tab + dc.ColumnName);
tab = "\t";
}
context.Response.Write("\n");
context.Response.Write("\n");
int i;
foreach (DataRow dr in table.Rows)
{
tab = "";
for (i = 0; i < table.Columns.Count; i++)
{
context.Response.Write(tab + dr[i].ToString());
tab = "\t";
}
context.Response.Write("\n");
}
context.Response.End();
}
I have seen posts similar to this. Some people have recommended that, zip files can be created on the server and download multiple excel files in "zip" folder. If it is possible, how can I implement it to the above solution?
You're calling response.end after creating the first file - which aborts the rest of the process.
I don't think you'll be able to create 3 excel files for download using this method.
As an alternative you could create 3 CSV files on disk, then use a zip library to zip them up.
see zipping files
Or you could use JET with an Excel connection string and use SQL Insert statements to push your data into an empty excel file. And use a different worksheet for each of your tables
write to excel with JET (but this limits you to 32bit)
Or you could use a third part control to write an excel file with the three tables as worksheets
Infragistics excel control
But if I were you - I'd just present the user with 3 different links they could click on.

Resources