I am creating an excel file on the fly for sending it an an attachment in an email. The relevant code snippet is provided below (It's a console app)
public static void SendEmailWithExcelAttachment(DataTable dt)
{
try
{
string smptHost = smptTuple.Item1;
MailMessage mailMsg = new MailMessage();
.............................................
.............................................
byte[] data = GetData(dt);
//save the data to a memory stream
System.IO.MemoryStream ms = new System.IO.MemoryStream(data);
mailMsg.Attachments.Add(new System.Net.Mail.Attachment(ms, attachmentName, "application/vnd.ms-excel"));
....................................
....................................
//send email
smtpClient.Send(mailMsg); }
catch (Exception ex)
{
throw ex;
}
}
private static byte[] GetData(DataTable dt)
{
string strBody = DataTable2ExcelString(dt);
byte[] data = Encoding.ASCII.GetBytes(strBody);
return data;
}
private static string DataTable2ExcelString(System.Data.DataTable dt)
{
string excelSheetName = "Sheet1";
StringBuilder sbTop = new StringBuilder();
sbTop.Append("<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" ");
sbTop.Append("xmlns=\" http://www.w3.org/TR/REC-html40\"><head><meta http-equiv=Content-Type content=\"text/html; charset=windows-1252\">");
sbTop.Append("<meta name=ProgId content=Excel.Sheet ><meta name=Generator content=\"Microsoft Excel 9\"><!--[if gte mso 9]>");
sbTop.Append("<xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>" + excelSheetName + "</x:Name><x:WorksheetOptions>");
sbTop.Append("<x:Selected/><x:ProtectContents>False</x:ProtectContents><x:ProtectObjects>False</x:ProtectObjects>");
sbTop.Append("<x:ProtectScenarios>False</x:ProtectScenarios></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets>");
sbTop.Append("<x:ProtectStructure>False</x:ProtectStructure><x:ProtectWindows>False</x:ProtectWindows></x:ExcelWorkbook></xml>");
sbTop.Append("<![endif]-->");
sbTop.Append("</head><body><table>");
string bottom = "</table></body></html>";
StringBuilder sbHeader = new StringBuilder();
//Header
sbHeader.Append("<tr>");
for (int i = 0; i < dt.Columns.Count; i++)
{
sbHeader.Append("<td>" + dt.Columns[i].ColumnName + "</td>");
}
sbHeader.Append("</tr>");
//Items
for (int x = 0; x < dt.Rows.Count; x++)
{
sbHeader.Append("<tr>");
for (int i = 0; i < dt.Columns.Count; i++)
{
sbHeader.Append("<td>" + dt.Rows[x][i] + "</td>");
}
sbHeader.Append("</tr>");
}
string data = sbTop.ToString() + sbHeader.ToString() + bottom;
return data;
}
This works but when I tried to open the excel file from the attachement, I receive:
I checked an found some solution in SO Post but could not make it to work. I tried like <x:DisplayAlerts>False</x:DisplayAlerts> but didn't work.
If the file you want to create and send doesn't have to be in exactly ".xls" format.. and if you are comfortable with ".xlsx" format... I think you might wanna try with EPPlus library, as it was mentioned Here. As I said you have to work with ".xlsx" (you can work with other excel formats but you'll get the same message about the file format when you open the file). So you can create the Excel file in temp folder with EPPlus using the DataTable as sorce and send the temp file by email... something like this for example:
public static void SendEmailWithExcelAttachment(DataTable dt)
{
try
{
string smptHost = smptTuple.Item1;
MailMessage mailMsg = new MailMessage();
string temp = Path.GetTempPath(); // Get %TEMP% path
string file = "fileNameHere.xlsx";
string path = Path.Combine(temp, file); // Get the whole path to the file
FileInfo fi = new FileInfo(path);
using (ExcelPackage pck = new ExcelPackage(fi))
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Table");
ws.Cells["A1"].LoadFromDataTable(dt, true);
pck.Save();
}
mailMsg.Attachments.Add(new System.Net.Mail.Attachment(path, "application/vnd.ms-excel"));
try
{
//send email
smtp.Send(mailMsg);
}
catch (Exception)
{
//do smth..
}
finally
{
File.Delete(path);
}
}
catch (Exception ex)
{
throw ex;
}
}
I created a simple DataTable, sent it to myself in ".xlsx" format and was able to open it without any "Format warnings". I hope that helps.
The warning is display by MS Excel application because your file is not a real Excel file. It is an HTML with XLS extension. An XLS file is a binary file. MS Excel recognizes the HTML file and it display the file in its spreadsheet grid.
MS Excel displays security warnings for files that comes from external sources like email or internet.
The best solution is to use an Excel library that saves real Excel files in xls (old Excel file format) or xlsx (new Excel file format).
You can choose between free libraries like NPOI, EPPlus or commercial libraries like EasyXLS. Some of them saves only xls files, other only xlsx files and a few of them supports both file formats.
Solution to the warning / error “The file you are trying to open is in a different format than specified by the file extension”
Cause :
This happens because in the traditional Export to Excel method, the GridView is first converted to an HTML string and then that HTML string is exported to Excel. Thus originally it is not an Excel file hence the Excel Application throws the warning / error “The file you are trying to open is in a different format than specified by the file extension”.
Solution :
The solution to this problem is using ClosedXML library which is wrapper over the DocumentFormat.OpenXml library.
Dependency : OpenXml SDK 2.0 must be installed in system
You can get more help here :)
Related
I am converting excel file .xlsx with phonetic text (Japanese text) but the output file gives out warning that there are unreadable contents, and the data are missing from the file.
It seems that the issues were because NPOI can't process the phonetic guide from Microsoft Excel in Japanese language.
This only applies on .xlsx files and not .xls files.
I'm not sure how to attach the sample excel file but the image above shows what it looks like. Basically, if you use Microsoft Excel in Japanese version, there will be automatic phonetic guide for every kanji (Chinese character).
public void writeoutput(string val)
{
try
{
IWorkbook book;
string outPath = "<path for input file>";
using (FileStream file = new FileStream(outPath, FileMode.Open, FileAccess.Read))
{
try
{
book = new XSSFWorkbook(file);
}
catch (Exception e)
{
book = null;
}
if (book == null)
{
book = new HSSFWorkbook(file);
}
file.Close();
}
//ISheet sheet = outputSheet.GetSheet("Sheet1");
ISheet sheet = book.GetSheetAt(0);
sheet.CopySheet("NewSheet", false);
IRow dataRow = sheet.GetRow(35) ?? sheet.CreateRow(35);
ICell cell = dataRow.GetCell(8) ?? dataRow.CreateCell(8);
cell.SetCellValue(val);
//File.Delete(outPath);
outPath = "<path for output file>";
using (FileStream file = new FileStream(outPath, FileMode.OpenOrCreate, FileAccess.Write))
{
book.Write(file);
file.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
textBox2.Text = "done";
}
}
I tried disable the phonetic guide in Microsoft Excel and the processing of the .xlsx file works with no issues but I can only disable the phonetic guide on the text one by one and it is very time consuming.
Using .net core & c# here.
I have a UI from which user can upload the Excel or CSV files. Once they upload this goes to my web api which handles the reading of the data from these files and returns json.
My Api code as:
[HttpPost("upload")]
public async Task<IActionResult> FileUpload(IFormFile file)
{
JArray data = new JArray();
using (ExcelPackage package = new ExcelPackage(file.OpenReadStream()))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
//Process, read from excel here and populate jarray
}
return Ok(data );
}
In my above code I am using EPPlus for reading the excel file. For excel file it works all fine but it cannot read csv file which is the limitation of EPPlus.
I searched and found another library CSVHelper: https://joshclose.github.io/CsvHelper/ The issue with this is it does vice versa and can read from CSV but not from Excel.
Is there any library available which supports reading from both.
Or would it be possible use EPPlus only but convert uploaded CSV to excel on the fly and then read. (please note I am not storing the excel file anywhere so cant use save as to save it as excel)
Any inputs please?
--Updated - Added code for reading data from excel---
int rowCount = worksheet.Dimension.End.Row;
int colCount = worksheet.Dimension.End.Column;
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= colCount; col++)
{
var rowValue = worksheet.Cells[row, col].Value;
}
}
//With the code suggested in the answer rowcount is always 1
You can use EPPLus and a MemoryStream for opening csv files into an ExcelPackage without writing to a file. Below is an example. You may have to change some of the the parameters based on your CSV file specs.
[HttpPost("upload")]
public async Task<IActionResult> FileUpload(IFormFile file)
{
var result = string.Empty;
string worksheetsName = "data";
bool firstRowIsHeader = false;
var format = new ExcelTextFormat();
format.Delimiter = ',';
format.TextQualifier = '"';
using (var reader = new System.IO.StreamReader(file.OpenReadStream()))
using (ExcelPackage package = new ExcelPackage())
{
result = reader.ReadToEnd();
ExcelWorksheet worksheet =
package.Workbook.Worksheets.Add(worksheetsName);
worksheet.Cells["A1"].LoadFromText(result, format, OfficeOpenXml.Table.TableStyles.Medium27, firstRowIsHeader);
}
}
Here's using Aspose, which is unfortunately not free, but wow it works great. My API is using the streaming capability with Content-Type: multipart/form-data rather than the IFormFile implementation:
[HttpPut]
[DisableFormValueModelBinding]
public async Task<IActionResult> UploadSpreadsheet()
{
if (!MultipartRequestHelper.IsMultipartContentType(Request.ContentType))
{
return BadRequest($"Expected a multipart request, but got {Request.ContentType}");
}
var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
var section = (await reader.ReadNextSectionAsync()).AsFileSection();
//If you're doing CSV, you add this line:
LoadOptions loadOptions = new LoadOptions(LoadFormat.CSV);
var workbook = new Workbook(section.FileStream, loadOptions);
Cells cells = workbook.Worksheets[0].Cells;
var rows = cells.Rows.Cast<Row>().Where(x => !x.IsBlank);
//Do whatever else you want here
Please try with below code
private string uploadCSV(FileUpload fl)
{
string fileName = "";
serverLocation = Request.PhysicalApplicationPath + "ExcelFiles\\";
fileName = fl.PostedFile.FileName;
int FileSize = fl.PostedFile.ContentLength;
string contentType = fl.PostedFile.ContentType;
fl.PostedFile.SaveAs(serverLocation + fileName);
string rpath = string.Empty, dir = string.Empty;
HttpContext context = HttpContext.Current;
string baseUrl = context.Request.Url.Scheme + "://" + context.Request.Url.Authority + context.Request.ApplicationPath.TrimEnd('/') + '/';
try
{
rpath = serverLocation + fileName;//Server.MapPath(dir + fileName);
using (Stream InputStream = fl.PostedFile.InputStream)
{
Object o = new object();
lock (o)
{
byte[] buffer = new byte[InputStream.Length];
InputStream.Read(buffer, 0, (int)InputStream.Length);
lock (o)
{
File.WriteAllBytes(rpath, buffer);
buffer = null;
}
InputStream.Close();
}
}
}
catch (Exception ex)
{
lblSOTargetVal.Text = ex.Message.ToString();
}
return rpath;
}
Use the Open XML SDK package and add insert working solution for it.
I am using below code to get values (which include invalid characters) from SQL Table and to generate an excel file. But when I open the file it is giving error - "We have found a problem with content..."
I am not able to paste that character here.
Is there any way to write those invalid characters in excel using code and after that when I open the file, it should open properly.
FileInfo NewFile = new FileInfo(#"D:\pg\splchar.xls");
using (OfficeOpenXml.ExcelPackage xlPackage = new OfficeOpenXml.ExcelPackage(NewFile))
{
OfficeOpenXml.ExcelWorksheet worksheet1 = xlPackage.Workbook.Worksheets.Add("Test1");
int rowId = 0;
string str="";
for (int i = 0; i < resultTable.Rows.Count; i++)
{
rowId++;
str=resultTable.Rows[i]["Value"].ToString();
worksheet1.Cell(rowId, 1).Value = str;
}
xlPackage.Save();
}
invalid char
I have a method were I create an Excelsheet. When the file is created I need to open it and save it manually in Excel before I can read it with Excel Data Reader. If I open and save the exact same file without changeing anything I can read it like I wan't it to work. Does anyone know how I can:
a) Save it properly when creating the file (using EPPlus)?
or
b) Open the already created file and save it properly by using C# before I try to read it?
My create method:
public void CreateAnnuityExcelSheet(List<Calculation> cList, FormCollection form, int DTCyear)
{
string fileName = "test";
string path = #"C:\ExcelFiles\" + fileName + ".xlsx"; //Path for the file
FileInfo info = new FileInfo(path);
info.Directory.Create(); //If C:\ExcelFiles does not exist, create it
if (!info.Exists)
{
using (ExcelPackage package = new ExcelPackage(info))
{
ExcelWorksheet ws = package.Workbook.Worksheets.Add(fileName);
//Filling the worksheet with values here...
package.SaveAs(info);
}
}
}
My read method:
[HttpPost]
public ActionResult ShowExcelFile(GetExcel model)
{
List<Calculation> cList = new List<Calculation>();
DataSet result = null;
var file = model.Files[0];
if (file != null && file.ContentLength > 0)
{
// .xlsx
IExcelDataReader reader = ExcelReaderFactory.CreateOpenXmlReader(file.InputStream);
reader.IsFirstRowAsColumnNames = true;
result = reader.AsDataSet();
reader.Close();
var PV = Convert.ToDecimal(data.Table.Rows[1][6]); //Works fine if the file is opened and saved in Excel. Else null..
//Work with the dataset here. When the file is not opened and saved it gets null everywhere. Else it works fine
}
return View("ShowExcelFile", model);
}
I have also tried using WriteAllBytes instead of using package.SaveAs():
byte[] data = package.GetAsByteArray();
System.IO.File.WriteAllBytes(path, data);
This gets my the exact same result. I still need to open and save the file manually.
I am using VS2005 C# and im trying to convert a pipe delimited text file to excel workbook format. Below is my code:
public partial class TextToExcel : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void SaveAsExcelBtn_Click(object sender, EventArgs e)
{
string xlExtension = ".csv";
string strExcelOutputFilename = "C:/Documents and Settings/rhlim/My Documents/" + DateTime.Now.ToString("yyyyMMddHHmmss") + xlExtension;
// Before attempting to import the file, verify
// that the FileUpload control contains a file.
if (TextFile.HasFile)
{
// Get the name of the Excel spreadsheet.
string strFileName = Server.HtmlEncode(TextFile.FileName);
// Get the extension of the text.
string strExtension = Path.GetExtension(strFileName);
// Validate the file extension.
if (strExtension != ".TXT" && strExtension!=".txt")
{
Response.Write("<script>alert('Failed to import. Cause: Invalid text file.');</script>");
return;
}
// Generate the file name to save the text file.
//string strUploadFileName = "C:/Documents and Settings/rhlim/My Documents/Visual Studio 2005/WebSites/SoD/UploadFiles/" + DateTime.Now.ToString("yyyyMMddHHmmss") + strExtension;
using (StreamWriter outputWriter = new StreamWriter(File.Create(strExcelOutputFilename)))
{
StreamReader inputReader = new StreamReader(TextFile.FileContent);
string fileContent = inputReader.ReadToEnd();
fileContent = fileContent.Replace('|', ';');
outputWriter.Write(fileContent);
TextFile.SaveAs(strExcelOutputFilename);
inputReader.Close();
}
//string strExcelOutputFilename = "C:/Documents and Settings/rhlim/My Documents/" + DateTime.Now.ToString("yyyyMMddHHmmss")+xlExtension;
// Save the Excel spreadsheet on server.
//TextFile.SaveAs (strExcelOutputFilename);
}
else Response.Write("<script>alert('Failed to import. Cause: No file found');</script>");
}
}
Currently I am having some file saving errors
Any suggestions? Thanks a lot!
That's because Excel doesnt support pipelines you have to convert it so comma's or semicolumns like:
using (StreamWriter outputWriter = new StreamWriter(File.Create(strExcelOutputFilename)))
{
StreamReader inputReader = new StreamReader(TextFile.FileContent);
string fileContent = inputReader.ReadToEnd();
fileContent = fileContent.Replace('|', ',');
outputWriter.Write(fileContent);
}
I googled and hope it will help you: http://csharp.net-informations.com/excel/csharp-create-excel.htm
Or, already answered: Create Excel (.XLS and .XLSX) file from C#
At the first link, the line xlWorkSheet.Cell[x,y] to put element in the dedicated cell.
FYI, xlsx format(new from Office 2007) will give you a great manipulation capability with code.
For generating and manipulating excel files, I personally prefer the NPOI library. Download it from Codeplex, add reference to the NPOI dlls to your project. Store a “template” excel file you would like in a known location, with the any column headers/formatting that you need. Then you just use npoi to make a copy of the template file and manipulate it at a sheet/row/column level and put whatever data you want.
The sample code snippet looks something like this. Assuming you have split your input into a List of strings
const string ExcelTemplateFile = "~/Resources/ExcelInputTemplate.xls";
const string ExcelWorksheetName = "Output Worksheet";
const int RequiredColumn = 1;
private HSSFWorkbook CreateExcelWorkbook(IEnumerable<String> inputData)
{
FileStream fs = new FileStream(Server.MapPath(ExcelTemplateFile), FileMode.Open, FileAccess.Read);
// Getting the complete workbook...
HSSFWorkbook templateWorkbook = new HSSFWorkbook(fs, true);
// Getting the worksheet by its name...
HSSFSheet sheet = templateWorkbook.GetSheet(ExcelWorksheetName);
int startRowIterator = 1;
foreach (string currentData in inputData)
{
sheet.CreateRow(startRowIterator).CreateCell(RequiredColumn).SetCellValue(currentData);
}
}