I have few tests which run three times and there average is calculated through c# code.I am able to write the three test times and there average to the xls file if created before in the below picture format . But now I have to run each test every hour everyday through a batch file using windows scheduler. I want to create the xls file dynamically in every hour in below mentioned format with a specific name so that at the first iteration the file is created and for next 19 iteration it should write in the same file then next hour new file created with a specific name.How to create and write the excel file dynamically ?????
If there is any other simple procedure plz suggest that. The code which I was using to write in already created xls file is :`/*
using System;
using System.IO;
using Ranorex;
namespace PEPI_Performance.Utility
{
/// <summary>
/// Description of ExcelWriter.
/// </summary>
public class ExcelWriter
{
/// <summary>
/// Constructs a new instance.
/// </summary>
public ExcelWriter()
{
// Do not delete - a parameterless constructor is required!
}
public void Driver(int row , int col, string time, string sheetName){
string sDataFile = "Ranorex_Reports.xls";
string sFilePath = Path.GetFullPath(sDataFile);
string sOldvalue = "Automation\\bin\\Debug\\" + sDataFile;
sFilePath = sFilePath.Replace(sOldvalue,"")+
"PEPI_Performance\\ExecutionReport\\" + sDataFile;
fnOpenExcel(sFilePath,sheetName);
writeExcel(row,col,time);
fnCloseExcel();
}
Excel.Application exlApp ;
Excel.Workbook exlWB ;
Excel.Sheets excelSheets ;
Excel.Worksheet exlWS;
//Open Excel file
public int fnOpenExcel(string sPath, string iSheet){
int functionReturnValue = 0;
try {
exlApp = new Excel.ApplicationClass();
exlApp.Visible = true;
exlWB=
exlApp.Workbooks.Open(sPath,Type.Missing,Type.Missing,
Type.Missing,Type.Missing,Type.Missing,Type.Missing,
Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing,Type.Missing);
// get all sheets in workbook
excelSheets = exlWB.Worksheets;
// get some sheet
//string currentSheet = "Cycle1";
exlWS = (Excel.Worksheet)excelSheets.get_Item(iSheet);
functionReturnValue = 0;
}
catch (Exception ex) {
functionReturnValue = -1;
Report.Error(ex.Message);
}
return functionReturnValue;
}
// Close the excel file and release objects.
public int fnCloseExcel(){
//exlWB.Close();
try{
exlApp.ActiveWorkbook.Save();
exlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(exlWS);
System.Runtime.InteropServices.Marshal.ReleaseComObject(exlWB);
System.Runtime.InteropServices.Marshal.ReleaseComObject(exlApp);
GC.GetTotalMemory(false);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.GetTotalMemory(true);
}catch(Exception ex){
Report.Error(ex.Message);
}
return 0;
}
public void writeExcel(int i, int j , string time){
Excel.Range exlRange = null;
exlRange = (Excel.Range)exlWS.UsedRange;
((Excel.Range)exlRange.Cells[i,j]).Formula = time;
}
}
}
`
In all honesty you might be better off using a csv file, that way from your ranorex tests you can simply use system.IO.File to write the output text to the file, and the nice thing about the csv format is it can then be opened in excel
There is a way to handle this using a data grid.
The example below accepts a DataSet (you could pass a list or table).
Then on the FLY a GridView is created and exported to Excel. I use this method on many sites.
public static void ExportDataSetToExcel(DataSet ds, string filename)
{
try
{
HttpResponse response = HttpContext.Current.Response;
// first let's clean up the response.object
response.Clear();
response.Charset = "";
// set the response mime type for excel
response.ContentType = "application/vnd.ms-excel";
response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
// create a string writer
using (StringWriter sw = new StringWriter())
{
using (HtmlTextWriter htw = new HtmlTextWriter(sw))
{
// instantiate a datagrid
DataGrid dg = new DataGrid();
dg.DataSource = ds;
dg.DataBind();
dg.RenderControl(htw);
response.Write(sw.ToString());
response.End();
}
}
}
catch { }
}
Related
I have a scenario, where i have a storage Blob which will have the Excel file, so in code level there is no Physical File path i have, so its Stream of file i will get the code. I need to Convert the same to CSV & push it back to the storage.
Tried below:-
Tried with Microsoft.Office.Interop.Excel
Excel.Application app = new Excel.Application();
app.DisplayAlerts = false;
// Open Excel Workbook for conversion.
Excel.Workbook excelWorkbook = app.Workbooks.Open(sourceFile);
// Save file as CSV file.
excelWorkbook.SaveAs(destinationFile, Excel.XlFileFormat.xlCSV);
Issue:- in the SourcePath , i don't have a physical location, and moreover there is no overload seems to take Byte or stream of file.
Tried https://github.com/youngcm2/CsvHelper.Excel , Demo code as follows.
using var reader = new CsvReader(new ExcelParser(FileContent, "JOB STATUSES", new CsvConfiguration(CultureInfo.CurrentCulture)));
Tried Below code even:-
using var parser = new ExcelParser(FileContent,CultureInfo.InvariantCulture); using var reader = new CsvReader(parser);
But here the ExcelParser is failing with Corrupterdfile with a valid CSV :(
Issue:- Here although there is a OverLoad to pass the Stream but is critical in my case. As there is no specific file format i have. It can be any Random EXCEL file. There no Specific class i can define.
I am missing something , can anyone help on this.
Scenario in my case:-
No Physical path to the File location . it's in Storage account, so Stream/Byte .
EXCEL File can be of any number of rows or columns no Fixed Model i can have but single sheet.
Use ExcelDataReader. It's available in NuGet.
using (var reader = ExcelReaderFactory.CreateReader(memoryStream, excelConfig))
{
var spreadsheet = reader.AsDataSet();
var table = spreadsheet.Tables[0];
var csv = table.ToCSV();
var bytes = Encoding.UTF8.GetBytes(csv);
return new StreamDataSource(bytes, table.TableName);
}
public static class TableExtension
{
public static string ToCSV(this DataTable dtDataTable)
{
var builder = new StringBuilder();
foreach (DataRow dr in dtDataTable.Rows)
{
for (int i = 0; i < dtDataTable.Columns.Count; i++)
{
if (!Convert.IsDBNull(dr[i]))
{
string value = dr[i].ToString();
if (value.Contains(","))
{
value = string.Format("\"{0}\"", value);
builder.Append(value);
}
else
{
builder.Append(dr[i].ToString());
}
}
if (i < dtDataTable.Columns.Count - 1)
{
builder.Append(",");
}
}
builder.Append(Environment.NewLine);
}
var csv = builder.ToString();
return csv;
}
}
I used to export data to excel in asp.net mvc using below code
Response.AppendHeader("content-disposition", "attachment;filename=ExportedHtml.xls");
Response.Charset = "";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = "application/vnd.ms-excel";
this.EnableViewState = false;
Response.Write(ExportDiv.InnerHtml);
Response.End();
When this Code Run it create a file and ask for a location to save
I tried working with NPOI and create Excel file very well but cant save file on client location .
Is there any way to make above code works on asp.net core 2.0 or any other way where I can save data in excel format on client machine ?
There are many ways to achieve that.
Option 1: save to wwwroot
You can generate the Excel and save it to the wwwroot folder. And then you can serve it as static content on the page.
For example you have a folder called 'temp' inside the wwwroot folder to contain all the newly generated excels.
<a href="\temp\development\user1\2018\5\9\excel1.xlsx" download>Download</a>
There are limitations on this approach. 1 of them is the new download attribute. It only works on modern browsers.
Option 2: byte array
Another way is to generate the Excel, convert it into byte array and send it back to the controller. For that I use a library called "EPPlus" (v: 4.5.1) which supports .Net Core 2.0.
The following is just some sample codes I put together to give you an idea. It's not production ready.
using OfficeOpenXml;
using OfficeOpenXml.Style;
namespace DL.SO.Web.UI.Controllers
{
public class ExcelController : Controller
{
public IActionResult Download()
{
byte[] fileContents;
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add("Sheet1");
// Put whatever you want here in the sheet
// For example, for cell on row1 col1
worksheet.Cells[1, 1].Value = "Long text";
worksheet.Cells[1, 1].Style.Font.Size = 12;
worksheet.Cells[1, 1].Style.Font.Bold = true;
worksheet.Cells[1, 1].Style.Border.Top.Style = ExcelBorderStyle.Hair;
// So many things you can try but you got the idea.
// Finally when you're done, export it to byte array.
fileContents = package.GetAsByteArray();
}
if (fileContents == null || fileContents.Length == 0)
{
return NotFound();
}
return File(
fileContents: fileContents,
contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
fileDownloadName: "test.xlsx"
);
}
}
}
Agreed with David Liang's answer.
Slide modifications if want to export whole DataTable.
string export="export";
DataTable dt = new DataTable();
//Fill datatable
dt = *something*
byte[] fileContents;
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add(export);
worksheet.Cells["A1"].LoadFromDataTable(dt, true);
fileContents = package.GetAsByteArray();
}
if (fileContents == null || fileContents.Length == 0)
{
return NotFound();
}
return File(
fileContents: fileContents,
contentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
fileDownloadName: export + ".xlsx"
);
Here is our solution to this:
using OfficeOpenXml;
public class XmlService
{
// [...]
public void getXlsxFile(SomeTableObject tbl, ref byte[] bytes)
{
using (ExcelPackage pck = new ExcelPackage())
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add(tbl.name);
ws.Cells["A1"].LoadFromDataTable(tbl, true);
bytes = pck.GetAsByteArray();
}
}
}
More information on EPPlus is available here and the source code above can be found at our open source repo (GPL).
Just use this code instead of your own:
Response.Clear();
Response.ContentType = "application/vnd.ms-excel";
Response.Headers[HeaderNames.ContentDisposition] = "attachment; filename=ExportedHtml.xls";
Response.WriteAsync(sb.ToString()).Wait();
I tried to export the dataset which have 2 tables to the excel sheet, unfortunately I can't.
I have code to export data table to excel. So instead of dataset, I called the ExportToExcel function which I have in my code to export datatable to excel 4 times. But once it created the first sheet, it stops the control flow. Control doesn't call the second function
ExportToExcel(getReports.Tables[1], "ConsumerBookedSlots");
Here is the code:
public ActionResult GetCuratorsAvailability(string availabilitydate)
{
string fromDate = "";
string endDate = "";
if (availabilitydate != "")
{
fromDate = availabilitydate.Split('-')[0];
endDate = availabilitydate.Split('-')[1];
if (DateTime.Parse(endDate) >= DateTime.Parse(fromDate))
{
DataSet getReports = AdminBLL.GetCuratorsAvailability(fromDate, endDate);
ExportToExcel(getReports.Tables[0], "CuratorsAvailableSlots");
ExportToExcel(getReports.Tables[1], "ConsumerBookedSlots");
}
}
return View("Reports");
}
public void ExportToExcel(DataTable dt, string FileName)
{
if (dt.Rows.Count > 0)
{
if (System.Web.HttpContext.Current.Response.RedirectLocation == null)
{
string filename = FileName + ".xls";
System.IO.StringWriter tw = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter hw = new System.Web.UI.HtmlTextWriter(tw);
DataGrid dgGrid = new DataGrid();
dgGrid.DataSource = dt;
dgGrid.DataBind();
//Get the HTML for the control.
dgGrid.RenderControl(hw);
//Write the HTML back to the browser.
//Response.ContentType = application/vnd.ms-excel;
Response.AppendHeader("Content-Disposition", "attachment; filename=" + filename + "");
Response.ContentType = "application/vnd.ms-excel";
Response.Write(tw.ToString());
Response.Flush();
Response.End();
}
}
}
I am unable to download getReports.Tables[1] data because I am getting this error:
server cannot append header after http headers have been sent. mvc
And it is downloading firstfile after error in the browser.
After the download of the first file, the execution hits this line-
Response.End();
That means, the response is ended, and headers have been sent to the client. There's no way you can initiate the download of the second file. If you want to download multiple files in a single button click, you need to zip it into one, and then initiate the download.
To zip the files you can do this-
using System;
using System.IO;
using System.IO.Compression;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
string startPath = #"c:\example\start";
string zipPath = #"c:\example\result.zip";
string extractPath = #"c:\example\extract";
ZipFile.CreateFromDirectory(startPath, zipPath);
ZipFile.ExtractToDirectory(zipPath, extractPath);
}
}
}
Snippet from here.
If you want to make both excel spreadsheets a part of single excel document by putting each one of them as a worksheet, you can use ClosedXML.
I've used ClosedXML (an OpenXML implementation) several times, including in an ASP.NET MVC application and it works like a charm.
Exporting data is a breeze:
using (var memoryStream = new MemoryStream())
{
using (XLWorkbook workbook = new XLWorkbook())
{
using (IXLWorksheet worksheet = workbook.AddWorksheet("WorksheetName"))
{
var toExport = GetData();
worksheet.Row(1).Style.Font.Bold = true;
worksheet.Cell(1, 1).Value = "Column 1";
worksheet.Cell(1, 2).Value = "Column 2";
worksheet.Cell(1, 3).Value = "Column 3";
// Export the data and set some properties
worksheet.Cell(2, 1).Value = toExport.AsEnumerable();
worksheet.RangeUsed().SetAutoFilter();
worksheet.Columns().AdjustToContents();
workbook.SaveAs(memoryStream);
memoryStream.Position = 0;
return File(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "filename.xlsx");
}
}
}
How do I get the Path or the file name of workbook in the below code so that I can get the work book that is edited. I have used ExpertXLS – Excel Spreadsheet Library for .NET - C#/VB.NET here
using ExpertXls;
namespace IQC
{
public class CSFB
{
public static string GenerateTemplateForCurrentGridView(IQO[] items, string colname, int icol)
{
/*Some Code here*/
string pathSource = HttpContext.Current.Server.MapPath("~/pdf/ExportTemplate.xlsx");
ExpertXls.ExcelLib.ExcelWorkbook workbook = new ExpertXls.ExcelLib.ExcelWorkbook(#pathSource);
workbook.LicenseKey = Inq.Configuration.Settings.Value("ExpertPdfLicenseKey");
ExpertXls.ExcelLib.ExcelWorksheet ws = workbook.Worksheets["ImportTemplate"];
ExpertXls.ExcelLib.ExcelCellStyle Style1 = workbook.Styles.AddStyle("Style1");
Style1.Fill.FillType = ExpertXls.ExcelLib.ExcelCellFillType.SolidFill;
Style1.Fill.SolidFillOptions.BackColor = Color.Yellow;
foreach (string cols in colname.Split(','))
{
ws[cols].Style = Style1;
}
/*Some Code here*/
}
}
}
You may use Application.ActiveWorkbook.FullName if the workbook is active workbook. Also you can try using workbook.Path. Refer the link.
Adding below code worked. I have saved the worked book in "pathsource"
System.IO.FileStream fs = new FileStream(pathSource, FileMode.OpenOrCreate, FileAccess.ReadWrite);
string fileName = fs.Name;
try
{
workbook.Save(fs);
}
catch (Exception ex)
{
Logger.Error(" Error:", ex);
}
finally
{
workbook.Close();
}
I am trying to develop an extension method which uses excel interop and converts any given input file into a new file in accord with an additional xlfileFormat input parametre.
The problem that I have found so far is that SaveAs method bypasses any arbitrary extension that I set, and sets It in accord with xlFileFormat options.
For example:
xlFileFormat = xlCsv, fileName= foo.arbitrary => saves it as
foo.arbitrary.csv
xlFileFormat = xlExcel8, fileName= extensionLessFoo => saves it
as extensionLessFoo.xls
xlFileFormat = xlOpenWorkbook, fileName= foo.xlsx => saves it as foo.xlsx (this one is OK)
I have been able to overcome this problem by specifying random GUID-based file names, and introducing this name as a SaveAs FileName parametre. Later, i will read final input workbook fullName, and return the recently created FileInfo
I would prefer not to depend on temporary files, but allow for specifying the file name AND the extension. so far, nor SaveCopyAs nor SaveAs have provided me a proper solution.
This is the method have been developing so far:
public static FileInfo InteropConvertTo(this FileInfo inputFile, XlFileFormat format)
{
var outputFileName = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "Random SaveAs File -" + System.Guid.NewGuid().ToString());
var outputFile = new FileInfo(outputFileName);
try
{
//creation of a new, silent application
var hiddenApp = new Application();
hiddenApp.Visible = false;
hiddenApp.ScreenUpdating = false;
hiddenApp.DisplayAlerts = false;
//adding workbook, saving as new format, closing
var inputWorkbook = hiddenApp.Workbooks.Add(inputFile);
inputWorkbook.DoNotPromptForConvert = true;
inputWorkbook.SaveAs(Filename: outputFileName,
FileFormat: format , AccessMode:XlSaveAsAccessMode.xlNoChange, CreateBackup: false);
outputFile = new FileInfo(inputWorkbook.FullName);
outputFile.IsReadOnly = false;
xlWorkBook.Close(false);
xlApp.Quit();
releaseObject(hiddenApp );
releaseObject(inputWorkbook);
}
finally
{
GC.Collect();
}
return outputFile;
}
private static void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
}
catch (Exception ex)
{
}
finally
{
obj = null;
GC.Collect();
}
}
Is there any way to use SaveAs forcing your own output file extension?