Reputation: 1195
I'm developing an app which can generate a excel file using html table. Up to now I developed html table download as excel file part. (This happens in client side with javascript). Now I need to send email with that attachment (The excel file) to particular person's email address. So I'm confuse how to do this, because up to now I generate excel in client side and need to send that file via email. In this case is it needed to copy client side excel to the server? If so how to do this? Please give me a direction.
Update 1 (Adding codes)
This is the javascript, that I used to download html table as excel to client side.
var tablesToExcel = (function () {
var uri = 'data:application/vnd.ms-excel;base64,'
, tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">'
+ '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author><Created>{created}</Created></DocumentProperties>'
+ '<Styles>'
+ '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>'
+ '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>'
+ '</Styles>'
+ '{worksheets}</Workbook>'
, tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table>{rows}</Table></Worksheet>'
, tmplCellXML = '<Cell{attributeStyleID}{attributeFormula}><Data ss:Type="{nameType}">{data}</Data></Cell>'
, base64 = function (s) { return window.btoa(unescape(encodeURIComponent(s))) }
, format = function (s, c) { return s.replace(/{(\w+)}/g, function (m, p) { return c[p]; }) }
return function (tables, wsnames, wbname, appname) {
var ctx = "";
var workbookXML = "";
var worksheetsXML = "";
var rowsXML = "";
for (var i = 0; i < tables.length; i++) {
if (!tables[i].nodeType) tables[i] = document.getElementById(tables[i]);
for (var j = 0; j < tables[i].rows.length; j++) {
rowsXML += '<Row>'
for (var k = 0; k < tables[i].rows[j].cells.length; k++) {
var dataType = tables[i].rows[j].cells[k].getAttribute("data-type");
var dataStyle = tables[i].rows[j].cells[k].getAttribute("data-style");
var dataValue = tables[i].rows[j].cells[k].getAttribute("data-value");
dataValue = (dataValue) ? dataValue : tables[i].rows[j].cells[k].innerHTML;
var dataFormula = tables[i].rows[j].cells[k].getAttribute("data-formula");
dataFormula = (dataFormula) ? dataFormula : (appname == 'Calc' && dataType == 'DateTime') ? dataValue : null;
ctx = {
attributeStyleID: (dataStyle == 'Currency' || dataStyle == 'Date') ? ' ss:StyleID="' + dataStyle + '"' : ''
, nameType: (dataType == 'Number' || dataType == 'DateTime' || dataType == 'Boolean' || dataType == 'Error') ? dataType : 'String'
, data: (dataFormula) ? '' : dataValue
, attributeFormula: (dataFormula) ? ' ss:Formula="' + dataFormula + '"' : ''
};
rowsXML += format(tmplCellXML, ctx);
}
rowsXML += '</Row>'
}
ctx = { rows: rowsXML, nameWS: wsnames[i] || 'Sheet' + i };
worksheetsXML += format(tmplWorksheetXML, ctx);
rowsXML = "";
}
ctx = { created: (new Date()).getTime(), worksheets: worksheetsXML };
workbookXML = format(tmplWorkbookXML, ctx);
var link = document.createElement("A");
link.href = uri + base64(workbookXML);
link.download = wbname || 'Workbook.xls';
link.target = '_blank';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
})();
Still I do not have idea to save generated excel to server and send it as email.
Upvotes: 1
Views: 3675
Reputation: 11
AS per our discussion: 1. you need to send data from client to server you can use this code to do this sending headers and values to server using ajax and you can also filter columns as you want
function SaveToServer() {
var gov = GetHeaders('tbl');
$.ajax({
url: '@Url.Content("~/Home/ReciveData")',
data: { headers: JSON.stringify(gov.heasers), data: JSON.stringify(gov.data) },
success: function (data) {
// Success
},
error: function (xhr) {
}
});
}
function GetHeaders(tableName) {
table = document.getElementById(tableName);
var tbl_Hdata = [];
var tbl_Data = [];
for (var i = 0, row; row = table.rows[i]; i++) {
var rowData = [];
for (var j = 0, col; col = row.cells[j]; j++) {
// add column filter
if (i == 0) {
tbl_Hdata.push(col.innerHTML);
}
else {
rowData.push(col.innerHTML);
}
}
if (i > 0) {
tbl_Data.push(rowData);
}
}
return { heasers: tbl_Hdata, data: tbl_Data };
}
now we want to recive this data and convert it to datatable to save it to excel in server side using NPOI
public void ReciveData(string headers, string data)
{
#region Read Data
List<string> tbl_Headers = new List<string>();
List<List<string>> tbl_Data = new List<List<string>>();
tbl_Headers = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(headers);
tbl_Data = Newtonsoft.Json.JsonConvert.DeserializeObject<List<List<string>>>(data);
#endregion
#region Create Data Table
DataTable dataTable = new DataTable("Data");
foreach (var prop in tbl_Headers)
{
dataTable.Columns.Add(prop);
}
DataRow row;
foreach (var rw in tbl_Data)
{
row = dataTable.NewRow();
for (int i = 0; i < rw.Count; i++)
{
row[tbl_Headers[i]] = rw[i];
}
dataTable.Rows.Add(row);
}
#endregion
#region Save To excel
string path = @"D:\";
string fileName = "";
GenerateExcelSheetWithoutDownload(dataTable, path, out fileName);
#endregion
}
public bool GenerateExcelSheetWithoutDownload(DataTable dataTable, string exportingSheetPath, out string exportingFileName)
{
#region Validate the parameters and Generate the excel sheet
bool returnValue = false;
exportingFileName = Guid.NewGuid().ToString() + ".xls";
if (dataTable != null && dataTable.Rows.Count > new int())
{
string excelSheetPath = string.Empty;
#region Check If The directory is exist
if (!Directory.Exists(exportingSheetPath))
{
Directory.CreateDirectory(exportingSheetPath);
}
excelSheetPath = exportingSheetPath + exportingFileName;
FileInfo fileInfo = new FileInfo(excelSheetPath);
#endregion
#region Write stream to the file
MemoryStream ms = DataToExcel(dataTable);
byte[] blob = ms.ToArray();
if (blob != null)
{
using (MemoryStream inStream = new MemoryStream(blob))
{
FileStream fs = new FileStream(excelSheetPath, FileMode.Create);
inStream.WriteTo(fs);
fs.Close();
}
}
ms.Close();
returnValue = true;
#endregion
}
return returnValue;
#endregion
}
private static MemoryStream DataToExcel(DataTable dt)
{
MemoryStream ms = new MemoryStream();
using (dt)
{
#region Create File
HSSFWorkbook workbook = new HSSFWorkbook();//Create an excel Workbook
ISheet sheet = workbook.CreateSheet("data");//Create a work table in the table
int RowHeaderIndex = new int();
#endregion
#region Table Headers
IRow headerTableRow = sheet.CreateRow(RowHeaderIndex);
if (dt != null)
{
foreach (DataColumn column in dt.Columns)
{
headerTableRow.CreateCell(column.Ordinal).SetCellValue(column.Caption);
}
RowHeaderIndex++;
}
#endregion
#region Data
foreach (DataRow row in dt.Rows)
{
IRow dataRow = sheet.CreateRow(RowHeaderIndex);
foreach (DataColumn column in dt.Columns)
{
dataRow.CreateCell(column.Ordinal).SetCellValue(row[column].ToString());
}
RowHeaderIndex++;
}
#endregion
workbook.Write(ms);
ms.Flush();
//ms.Position = 0;
}
return ms;
}
Now you can send this file as attachment in mail
Upvotes: 1
Reputation: 131483
You can't create Excel files with HTML tables. This is a hack that's used to fake actual Excel files. Excel isn't fooled, it recognizes the HTML file and tries to import the data using defaults. This will easily break for any number of reasons, eg different locale settings for decimals and dates.
Excel files are just zipped XML files. You can create them using XML manipulation, the Open XML SDK or a library like EPPlus.
Creating an Excel file with EPPlus is as easy as calling the LoadFromCollection
or LoadFromDatatable
method. The sheet can be saved to any stream, including FileStream or MemoryStream. A MemoryStream can be used to send the data to a web browser as shown in this answer:
public ActionResult ExportData()
{
//Somehow, load data to a DataTable
using (ExcelPackage package = new ExcelPackage())
{
var ws = package.Workbook.Worksheets.Add("My Sheet");
//true generates headers
ws.Cells["A1"].LoadFromDataTable(dataTable, true);
var stream = new MemoryStream();
package.SaveAs(stream);
string fileName = "myfilename.xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
stream.Position = 0;
return File(stream, contentType, fileName);
}
}
Mail attachments can also be created from a MemoryStream. The Attachment(Stream, string,string) constructor accepts any stream as input. The example above could be modified to create an attachment instead of sending the data to the browser:
public void SendData(string server, string recipientList)
{
//Same as before
using (ExcelPackage package = new ExcelPackage())
{
var ws = package.Workbook.Worksheets.Add("My Sheet");
ws.Cells["A1"].LoadFromDataTable(dataTable, true);
var stream = new MemoryStream();
package.SaveAs(stream);
string fileName = "myfilename.xlsx";
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
stream.Position = 0;
SendExcel(server,recipientList);
}
}
void SendExcel(string server, string recipientList)
{
//Send the file
var message = new MailMessage("[email protected]", recipientList);
message.Subject = "Some Data";
Attachment data = new Attachment(stream, name, contentType);
// Add the attachment to the message.
message.Attachments.Add(data);
// Send the message.
// Include credentials if the server requires them.
var client = new SmtpClient(server);
client.Credentials = CredentialCache.DefaultNetworkCredentials;
client.Send(message);
}
}
UPDATE
Generating an XSLX table on the client side becomes a lot easier if you use a library like js-xlsx. There's even a sample that generates an XLSX file from an HTML table
Upvotes: 0