Exporting OpenXML created Excel Spreadsheet to client side - c#

I am trying to get the API to start a download of the excel spreadsheet that has been created. Although, i seem to be running into some hassle. I have tried to also send the Byte array of the Spreadsheets memory stream through to the front-end and go from there, but the excel file is corrupt and does not contain any data.
Controller:
[HttpPost]
[Route("CreateExcelDocument")]
public ActionResult CreateExcelDocument([FromBody] List<BarBillList> model)
{
try
{
byte[] tmp;
using (ExcelController ex = new ExcelController())
{
tmp = ex.createExcelSpreadsheet(barBillExport);
}
string fileName = "xxx.xlsx";
return File(tmp, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
}
catch (Exception e)
{
return null;
}
}
ExcelController class with the spreadsheet creation method:
public byte[] createExcelSpreadsheet(List<BarBillList> barBillExport)
{
DateTime today = DateTime.Today;
using (MemoryStream ms = new MemoryStream())
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook))
{
//Creating the initial document
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
workbookPart.Workbook.Save();
//Styling the doucment
WorkbookStylesPart stylesPart = workbookPart.AddNewPart<WorkbookStylesPart>();
stylesPart.Stylesheet = GenerateStyleSheet();
stylesPart.Stylesheet.Save();
//Adding width to the columns
DocumentFormat.OpenXml.Spreadsheet.Columns columns = new DocumentFormat.OpenXml.Spreadsheet.Columns();
columns.Append(new DocumentFormat.OpenXml.Spreadsheet.Column() { Min = 1, Max = 6, Width = 20, CustomWidth = true });
worksheetPart.Worksheet.Append(columns);
//Creating the worksheet part to add the data to
Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());
Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "BarBill" };
sheets.Append(sheet);
SheetData sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());
//Creating the first Header Row
Row row = new Row();
row.Append(
ConstructCell("Name", CellValues.String, true),
ConstructCell("Last Payment Date", CellValues.String, true),
ConstructCell("Last Payment Amount", CellValues.String, true),
ConstructCell("Current Balance", CellValues.String, true));
sheetData.AppendChild(row);
//Appending the data into their respective columns
foreach (var ent in barBillExport)
{
row = new Row();
row.Append(
ConstructCell(ent.Name.ToString(), CellValues.String, false),
ConstructCell((ent.LastPaymentDate.ToString().Length > 0) ? ent.LastPaymentDate.ToString() : "", CellValues.String, false),
ConstructCell((ent.LastPayment.ToString().Length > 0) ? ent.LastPayment.ToString() : "", CellValues.String, false),
ConstructCell((ent.TotalBalance.ToString().Length > 0) ? ent.TotalBalance.ToString() : "", CellValues.String, false));
sheetData.AppendChild(row);
}
worksheetPart.Worksheet.Save();
}
return ms.ToArray();
}
}
EDIT
Front End Service:
createExcelDocument(model: BillList[]): any {
return this.http.post(this.getBarBillsUrl + "/CreateExcelDocument", model)
.map(this.helper.extractData)
.catch(this.helper.handleError);
}
I am aware that the mapper does not need to be there. But im keeping it there should i need to bring the byte array through to the front and go from there.
Any direction or guidance on the matter would be greatly appreciated.
Thanks.
Solution Found for those interested or facing a similar issue(Please see below answers for author)
I added the { responseType: ResponseContentType.Blob } to the service call in TypeScript.
It then returned me a blob of the spreadsheet. From there, within the typescript i ran it through another method:
private saveAsBlob(data: any) {
const year = this.today.getFullYear();
const month = this.today.getMonth();
const date = this.today.getDate();
const dateString = year + '-' + month + '-' + date;
const file = new File([data], 'BarBill ' + dateString + '.xlsx',
{ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
FileSaver.saveAs(file);
}
To then get my file to download client side.
Thanks very much to all. Especially the author of the answer.

You need to tell Angular that the response is not JSON format , and so it will not try to parse it. Try changing your code to:
createExcelDocument(model: BillList[]): any {
return this.http.post(this.getBarBillsUrl + "/CreateExcelDocument",
model, { responseType: ResponseContentType.Blob })
.map(this.helper.extractData)
.catch(this.helper.handleError);
}
The above code for binary format, but for excel files you should use this below code:
const httpOptions = {
headers: new HttpHeaders({ 'responseType': 'ResponseContentType.Blob',
'Content-Type': 'application/vnd.ms-excel'})};
createExcelDocument(model: BillList[]): any {
return this.http.post(this.getBarBillsUrl + "/CreateExcelDocument",
model, httpOptions )
.map(this.helper.extractData)
.catch(this.helper.handleError);
}

Your "return ms.ToArray();" line needs to move inside the using and possibly add "document.Close();":
public byte[] createExcelSpreadsheet(List<BarBillList> barBillExport)
{
DateTime today = DateTime.Today;
using (MemoryStream ms = new MemoryStream())
{
using (SpreadsheetDocument document = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook))
{
//Creating the initial document
...
//Styling the doucment
...
//Adding width to the columns
...
//Creating the worksheet part to add the data to
...
SheetData sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());
//Creating the first Header Row
...
//Appending the data into their respective columns
foreach (var ent in barBillExport)
{
...
}
worksheetPart.Worksheet.Save();
document.Close();
return ms.ToArray();
}
}
}

Related

OpenXML - How can I insert a value into a specific worksheet?

I'm fairly new to creating Excel spreadsheets in C# and I'm looking for advice.
I've spent 2 or 3 days now looking through documentation and blogs etc but I cannot seem to find an answer to a common task.
I need to insert a text value into a specific worksheet. I cant easily post my code at the moment but it appears to be an issue with every example I've seen of the definition of a sheet, it always gets the first child.
I need to iterate through all sheets and dependant on the sheet name then go and insert a value.
I.e. If the sheet name = "testA" then write TestA, if the sheet name = "testB" then write "TestB".
Currently I can insert a value for the workbook but it inserts the same value for every sheet.
Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>();
[Microsoft documentation] (https://learn.microsoft.com/en-us/office/open-xml/how-to-insert-text-into-a-cell-in-a-spreadsheet)
Please note I'm not just giving up on this I've just reached a bit of a wall with it and need some pointers.
Many Thanks, J
Namespaces I'm using:
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
private void btnExport_Click(object sender, EventArgs e)
{
//Using Microsofts Interop class to create Excel files gives mixed resuts and requires excel to be installed.
// This uses OpenXML library to achieve this and doesnt require excel to be installed: https://medium.com/swlh/openxml-sdk-brief-guide-c-7099e2391059
string filepath = "Test.xlsx";
// Create a spreadsheet document by supplying the filepath.
// By default, AutoSave = true, Editable = true, and Type = xlsx.
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.
Create(filepath, SpreadsheetDocumentType.Workbook);
// Add a WorkbookPart to the document.
WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
workbookpart.Workbook = new Workbook();
// Add a WorksheetPart to the WorkbookPart.
WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
// Add Sheets to the Workbook.
Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.
AppendChild<Sheets>(new Sheets());
// Append a new worksheet and associate it with the workbook.
Sheet sheetOne = new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "Sheet1"
};
Sheet sheetTwo= new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 2,
Name = "Sheet2"
};
Sheet sheetParameters = new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 3,
Name = "Parameters"
};
Sheet sheetFour= new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 4,
Name = "Sheet4"
};
Sheet sheetFive= new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 5,
Name = "Sheet5"
};
sheets.Append(sheetOne);
sheets.Append(sheetTwo);
sheets.Append(sheetParameters);
sheets.Append(sheetFour);
sheets.Append(sheetFive);
workbookpart.Workbook.Save();
// Close the document.
spreadsheetDocument.Close();
//InsertTextExistingExcel(filepath, "test1", "A", 1, "Parameters");
InsertInSheet(filepath, "test1", "A", 1, "Parameters");
//Any of these lists empty?
}
public static void InsertInSheet(string filePath, string value, string columnName, uint rowIndex, string sheetName)
{
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(filePath, true))
{
getSheetDetails(spreadSheet);
}
}
//work here
public static void getSheetDetails(SpreadsheetDocument doc)
{
WorksheetPart worksheetPart;
//iterate through sheets
foreach (Sheet sheetDetail in doc.WorkbookPart.Workbook.Sheets)
{
if (sheetDetail.Name == "Parameters")
{
//each sheet has a worksheetPart
worksheetPart = (WorksheetPart)doc.WorkbookPart.GetPartById(sheetDetail.Id);
Cell cell = InsertCellInWorksheet("A", 1, worksheetPart);
cell.CellValue = new CellValue("test");
cell.DataType = new EnumValue<CellValues>(CellValues.String);
worksheetPart.Worksheet.Save();
}
}
}
private static Cell InsertCellInWorksheet(string columnName, uint rowIndex, WorksheetPart worksheetPart)
{
//fix earlier worksheetPart only has a count of 1
Worksheet worksheet = worksheetPart.Worksheet;
//fix this to point to sheet
//SheetData sheetData = worksheet.Descendants<SheetData>();
SheetData sheetData = worksheet.GetFirstChild<SheetData>();
MessageBox.Show(sheetData.InnerXml.ToString());
string cellReference = columnName + rowIndex;
Row row;
if (sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
{
row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
}
else
{
row = new Row() { RowIndex = rowIndex };
sheetData.Append(row);
}
Cell refCell = row.Descendants<Cell>().LastOrDefault();
Cell newCell = new Cell() { CellReference = cellReference };
row.InsertAfter(newCell, refCell);
worksheet.Save();
return newCell;
}

Export to excel returns Blank sheet

I am trying to export a datatable using closed xml but it gives me blank sheet.
Here is my code
[HttpPost]
public FileResult ExportExcel()
{
List<ProductModel> productDetails = (List<ProductModel>)Session["CartItems"];
System.Data.DataTable dtExcel = CategoryDAL.ToDataTable(productDetails);
using (XLWorkbook wb = new XLWorkbook())
{
wb.Worksheets.Add(dtExcel);
using (MemoryStream stream = new MemoryStream())
{
wb.SaveAs(stream);
return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Grid.xlsx");
}
}
}
When I debug I can see that datatable has the data but it exports a blank one
Hey I've written an excelexporter for our proposes on my own.
I used this tutorial to get started with excel exporting:
http://www.dispatchertimer.com/tutorial/how-to-create-an-excel-file-in-net-using-openxml-part-2-export-a-collection-to-spreadsheet/
http://www.dispatchertimer.com/tutorial/how-to-create-an-excel-file-in-net-using-openxml-part-3-add-stylesheet-to-the-spreadsheet/ (for styling proposes)
and here is a code snippet how I run an excel export in a controller:
public async Task<FileResult> DownloadExcel(long id, CancellationToken token)
{
var entites= await _someRepository.GetSomethingAsync(id, token).ConfigureAwait(false);
var report = _excelExporter.Export(entites.OrderByDescending(d => d.Date));
return File(report, MimeTypes.GetMimeType("excel.xlsx"), $"entities.xlsx");
}
Generating the excel spreadsheet is done with a memory stream. Here are some lines how I begin creating the excel file:
using (MemoryStream mem = new MemoryStream())
{
using (var document = SpreadsheetDocument.Create(mem, SpreadsheetDocumentType.Workbook))
{
var workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
var sheets = workbookPart.Workbook.AppendChild(new Sheets());
var sheet = new Sheet
{
Id = workbookPart.GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "Report"
};
sheets.Append(new[] { sheet });
workbookPart.Workbook.Save();
var sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());
// Constructing header
var row = new Row();
// This needs to get adjusted for your needs
// it returns IEnumerable<Cell>
row.Append(GenerateHeaderCells(/*FillMe*/));
// Insert the header row to the Sheet Data
sheetData.AppendChild(row);
foreach (var entity in data)
{
row = new Row();
//This needs to get adjusted
// it returns IEnumerable<Cell>
row.Append(GenerateCells(/*FillMe*/));
sheetData.AppendChild(row);
}
worksheetPart.Worksheet.Save();
}
return mem.ToArray();
}
I had no MS-Office installed on my system and my requirement was to generate the file and send it to email. So ultimate goal was to send the excel to admin user. When i wrote the code to send it to email and checked email, excel showed the data but when I was returning it from the same code, It was blank sheet. Maybe I should have used interop dlls.

Simple excel creation does not open file is corrupt

I am trying to create a simple excel file with multiple sheets using open xml, unfortunately the file does not open after it's being created.
After the file is generated, when I open it with Microsoft Excel it says
We found a problem, do you want to recover as much as we can?
using (SpreadsheetDocument spreedDoc = SpreadsheetDocument.Create(filePath,
DocumentFormat.OpenXml.SpreadsheetDocumentType.Workbook))
{
WorkbookPart wbPart = spreedDoc.WorkbookPart;
wbPart = spreedDoc.AddWorkbookPart();
wbPart.Workbook = new Workbook();
Sheets sheets = wbPart.Workbook.AppendChild(new Sheets());
foreach (var sheetData in excelSheetData)
{
// Add a blank WorksheetPart.
WorksheetPart worksheetPart = wbPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
string relationshipId = wbPart.GetIdOfPart(worksheetPart);
// Get a unique ID for the new worksheet.
uint sheetId = 1;
if (sheets.Elements<Sheet>().Count() > 0)
{
sheetId = sheets.Elements<Sheet>().Select(s => s.SheetId.Value).Max() + 1;
}
// Give the new worksheet a name.
string sheetNameToWrite = sheetName;
if (string.IsNullOrWhiteSpace(sheetNameToWrite))
{
sheetNameToWrite = "Sheet"+sheetId;
}
// Append the new worksheet and associate it with the workbook.
Sheet sheet = new Sheet() { Id = relationshipId, SheetId = sheetId, Name = sheetName };
sheets.AppendChild(sheet);
}
//wbPart.Workbook.Sheets.AppendChild(sheet);
wbPart.Workbook.Save();
}
On trying to Repair in excel gives below message
-<repairedRecords summary="Following is a list of repairs:">
<repairedRecord>Repaired Records: Worksheet properties from /xl/workbook.xml part (Workbook)</repairedRecord>
</repairedRecords>
</recoveryLog>
Have you seen this?
http://www.mikesknowledgebase.com/pages/CSharp/ExportToExcel.htm
The necessary steps to create a functional excel file with multiple worksheets in OpenXML (that work for me) are as follows:
using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Create(path, SpreadsheetDocumentType.Workbook))
{
spreadsheet.AddWorkbookPart();
spreadsheet.WorkbookPart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook();
spreadsheet.WorkbookPart.Workbook.Append(new BookViews(new WorkbookView()));
WorkbookStylesPart workbookStylesPart = spreadsheet.WorkbookPart.AddNewPart<WorkbookStylesPart>("rIdStyles");
Stylesheet stylesheet = new Stylesheet();
workbookStylesPart.Stylesheet = stylesheet;
workbookStylesPart.Stylesheet.Save();
for (int worksheetNo = 1; worksheetNo < worksheetCountYouWantToCreate; worksheetNo++)
{
string workSheetID = "rId" + worksheetNo;
string worksheetName = "worksheet" + worksheetNo;
WorksheetPart newWorksheetPart = spreadsheet.WorkbookPart.AddNewPart<WorksheetPart>();
newWorksheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet();
newWorksheetPart.Worksheet.AppendChild(new DocumentFormat.OpenXml.Spreadsheet.SheetData());
// write data here
// ...
// ...
newWorksheetPart.Worksheet.Save();
if (worksheetNo == 1)
spreadsheet.WorkbookPart.Workbook.AppendChild(new DocumentFormat.OpenXml.Spreadsheet.Sheets());
spreadsheet.WorkbookPart.Workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>().AppendChild(new DocumentFormat.OpenXml.Spreadsheet.Sheet()
{
Id = spreadsheet.WorkbookPart.GetIdOfPart(newWorksheetPart),
SheetId = (uint)worksheetNo,
Name = worksheetName
});
}
spreadsheet.WorkbookPart.Workbook.Save();
}

'The file is corrupt and cannot be opened' OpenXML

I got that code from OpenXML sdk and instead of SpreadsheetDocument.Create, I used SpreadsheetDocument.Open
This code is working and add an image in .xlsx, after image added to the file. I open the file which shows ->
The file is corrupt and cannot be opened
If you want more details Please! let me know.
Reference URL -> https://code.msdn.microsoft.com/office/How-to-insert-image-into-93964561
Thanks for the help!
/// <summary>
/// add sheet in xlsx then add image into it.
/// </summary>
/// <param name="sFile"></param>
/// <param name="imageFileName"></param>
public void InsertimginExcel(string sFile, string imageFileName)
{
try
{
// Create a spreadsheet document by supplying the filepath.
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.
Open(sFile, true))
{
// Add a WorkbookPart to the document.
//WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
//workbookpart.Workbook = new Workbook();
// Add a WorksheetPart to the WorkbookPart.
WorksheetPart worksheetPart = spreadsheetDocument.WorkbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
// Add Sheets to the Workbook.
Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.
AppendChild<Sheets>(new Sheets());
// Append a new worksheet and associate it with the workbook.
Sheet sheet = new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "mySheet"
};
sheets.Append(sheet);
var drawingsPart = worksheetPart.AddNewPart<DrawingsPart>();
if (!worksheetPart.Worksheet.ChildElements.OfType<DocumentFormat.OpenXml.Spreadsheet.Drawing>().Any())
{
worksheetPart.Worksheet.Append(new DocumentFormat.OpenXml.Spreadsheet.Drawing { Id = worksheetPart.GetIdOfPart(drawingsPart) });
}
if (drawingsPart.WorksheetDrawing == null)
{
drawingsPart.WorksheetDrawing = new WorksheetDrawing();
}
var worksheetDrawing = drawingsPart.WorksheetDrawing;
var imagePart = drawingsPart.AddImagePart(ImagePartType.Jpeg);
using (var stream = new FileStream(imageFileName, FileMode.Open))
{
imagePart.FeedData(stream);
}
Bitmap bm = new Bitmap(imageFileName);
DocumentFormat.OpenXml.Drawing.Extents extents = new DocumentFormat.OpenXml.Drawing.Extents();
var extentsCx = (long)bm.Width * (long)((float)914400 / bm.HorizontalResolution);
var extentsCy = (long)bm.Height * (long)((float)914400 / bm.VerticalResolution);
bm.Dispose();
var colOffset = 0;
var rowOffset = 0;
int colNumber = 5;
int rowNumber = 10;
var nvps = worksheetDrawing.Descendants<Xdr.NonVisualDrawingProperties>();
var nvpId = nvps.Count() > 0 ?
(UInt32Value)worksheetDrawing.Descendants<Xdr.NonVisualDrawingProperties>().Max(p => p.Id.Value) + 1 :
1U;
var oneCellAnchor = new Xdr.OneCellAnchor(
new Xdr.FromMarker
{
ColumnId = new Xdr.ColumnId((colNumber - 1).ToString()),
RowId = new Xdr.RowId((rowNumber - 1).ToString()),
ColumnOffset = new Xdr.ColumnOffset(colOffset.ToString()),
RowOffset = new Xdr.RowOffset(rowOffset.ToString())
},
new Xdr.Extent { Cx = extentsCx, Cy = extentsCy },
new Xdr.Picture(
new Xdr.NonVisualPictureProperties(
new Xdr.NonVisualDrawingProperties { Id = nvpId, Name = "Picture " + nvpId, Description = imageFileName },
new Xdr.NonVisualPictureDrawingProperties(new A.PictureLocks { NoChangeAspect = true })
),
new Xdr.BlipFill(
new A.Blip { Embed = drawingsPart.GetIdOfPart(imagePart), CompressionState = A.BlipCompressionValues.Print },
new A.Stretch(new A.FillRectangle())
),
new Xdr.ShapeProperties(
new A.Transform2D(
new A.Offset { X = 0, Y = 0 },
new A.Extents { Cx = extentsCx, Cy = extentsCy }
),
new A.PresetGeometry { Preset = A.ShapeTypeValues.Rectangle }
)
),
new Xdr.ClientData()
);
worksheetDrawing.Append(oneCellAnchor);
//workbookpart.Workbook.Save();
// Close the document.
spreadsheetDocument.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
//log.Error("error occur while creating sheet and adding image --> " + ex.Message.ToString());
}
}
Not sure how many workbookparts and worksheetparts a xlsx file can handle and if the SheetId must be document unique for all Sheets. Try changing the Id to e.g. 5 if that does not help: do not create a new workbookpart for the sheet, use existig one, if possible.
The file is corrupt and cannot be opened
Uncheck all the options under Protected View and confirm by pressing OK.
Restart Excel and try to open the broken Excel documents.
Ref: https://answers.microsoft.com/en-us/office/forum/office_2010-excel/the-file-is-corrupt-and-cannot-be-opened-error-on/93af59c1-946c-4f5f-83c1-bd6f58dbd94f
If that doesn't work, typically when you create XSLX files and there is an error, you see this:
Can you check your Temporary Internet Files for the log. The log file should have info on what is malformed. Please update your question with any additional info.

openxml 2.5, how to insert a string into a cell?

I have been trying for a couple of days now to insert a string into an openxml spreadsheet. Everything else (so far) works, everything but that.
This is the code i'm currently running (note, this is purely for testing purposes and is pretty basic):
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Create(file + "test.zip", SpreadsheetDocumentType.Workbook))
{
spreadSheet.AddWorkbookPart();
spreadSheet.WorkbookPart.Workbook = new Workbook();
spreadSheet.WorkbookPart.AddNewPart<SharedStringTablePart>();
spreadSheet.WorkbookPart.SharedStringTablePart.SharedStringTable = new SharedStringTable() {Count=1, UniqueCount=1};
spreadSheet.WorkbookPart.SharedStringTablePart.SharedStringTable.AppendChild(new SharedStringItem(new Text("test")));
spreadSheet.WorkbookPart.SharedStringTablePart.SharedStringTable.Save();
preadSheet.WorkbookPart.AddNewPart<WorksheetPart>();
spreadSheet.WorkbookPart.WorksheetParts.First().Worksheet = new Worksheet();
spreadSheet.WorkbookPart.WorksheetParts.First().Worksheet.AppendChild(new SheetData());
spreadSheet.WorkbookPart.WorksheetParts.First().Worksheet.First().AppendChild(new Row());
Row r2 = new Row() { RowIndex = 5 };
spreadSheet.WorkbookPart.WorksheetParts.First().Worksheet.First().AppendChild(r2);
r2.AppendChild(new Cell() { CellReference = "A5", CellValue = new CellValue("0"), DataType = new EnumValue<CellValues>(CellValues.SharedString) });
spreadSheet.WorkbookPart.WorksheetParts.First().Worksheet.Save();
spreadSheet.WorkbookPart.Workbook.GetFirstChild<Sheets>().AppendChild(new Sheet()
{
Id = spreadSheet.WorkbookPart.GetIdOfPart(spreadSheet.WorkbookPart.WorksheetParts.First()),
SheetId = 1,
Name = "test"
});
spreadSheet.WorkbookPart.Workbook.Save();
}
Everything seems to work, the file saves where i want it to and, generally, looks the way i expect it to. The "only" issue is that, when i add the string to the cell, excel will give me an error saying that the file is corrupt and continues to delete said cell.
Am i doing something wrong?
Try this, in your method..
if (spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
{
shareStringPart = spreadSheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
}
else
{
shareStringPart = spreadSheet.WorkbookPart.AddNewPart<SharedStringTablePart>();
}
index = InsertSharedStringItem(cell_value, shareStringPart);
cell.CellValue = new CellValue(index.ToString());
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
InsertSharedString Method:
private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
{
// If the part does not contain a SharedStringTable, create one.
if (shareStringPart.SharedStringTable == null)
{
shareStringPart.SharedStringTable = new SharedStringTable();
}
int i = 0;
// Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>())
{
if (item.InnerText == text)
{
return i;
}
i++;
}
// The text does not exist in the part. Create the SharedStringItem and return its index.
shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
shareStringPart.SharedStringTable.Save();
return i;
}
I think you should create a spreadsheet (using Excel), add the text into the cell and then open this spreadsheet in "OpenXML 2.5 Productivity Tool". There is a "Reflect code" button in the productivity tool that would help you replicate in code what needs to be done. That's the easiest way, I've found to solve such bugs.

Categories