I am creating an asp.net Core API with an endpoint to export data as excel file.
I have added the nuget package EPPlus.Core.
This is my code so far:
using OfficeOpenXml;
...
Public class DataService
{
...
public Byte[] Export(ExportRequest request){
var data = _repository(request);
using (var package = new ExcelPackage())
{
package.Workbook.Properties.Title = "Persons";
var worksheet = package.Workbook.Worksheets.Add("Persons");
//Headers
worksheet.Cells[1, 1].Value = "Id";
worksheet.Cells[1, 2].Value = "Name";
//Values
var row = 2;
foreach (var person in data.Persons)
{
worksheet.Cells[row, 1].Value = person.Id;
worksheet.Cells[row, 2].Value = person.Name;
row++;
}
return package.GetAsByteArray();
}
}
public class PersonController : Controller
{
[HttpPost]
[Route("{version:apiVersion}/[controller]/Export")]
[SwaggerResponse(400, typeof(Exception), "Error in request")]
[SwaggerResponse(500, typeof(Exception), "Error on server")]
public IActionResult Export([FromBody] ExportRequest request)
{
Byte[] byteArray = _projectService.ExportRegistrations(request);
if (byteArray != null)
{
return File(byteArray, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "persons.xlsx");
}
return BadRequest("Failure");
}
}
I test my API using swagger and get a file downloaded named persons.xlsx.
But I am not able to open it.
I get the two following promts:
We found a problem in some of the contents of "persons.xlsx", should we try to restore as much as possible? If you trust the source of the workbook, click Yes.
The file "persons.xlsx" can not be opened because the file format or file type name is invalid. Verify that the file is not corrupted and that the file type name matches the file format.
And then an empty excel document.
i have also facing the same problem,
The workaround is directly open the url via browser or using postman.
Related
I am facing en enconding issue when downloading a file from Sharepoint Online by an Azure function. So I have an Azure HTTP triggered function that calls Sharepoint Online to retrieve a file and download it. Here is how I call Sharepoint:
public dynamic DownloadFile(Guid fileUniqueId)
{
const string apiUrl = "{0}/_api/web/GetFileById('{1}')/$value";
try
{
var fileInfo = GetFileInfo(fileUniqueId);
if (string.IsNullOrEmpty(_sharepointSiteUrl)) return null;
string api = string.Format(apiUrl, _sharepointSiteUrl, fileUniqueId.ToString());
string response = new TokenHelper().GetAPIResponse(api);
if (string.IsNullOrEmpty(response)) return null;
return new {
fileInfo.FileName,
Bytes = Encoding.UTF8.GetBytes(response)
};
}
catch (Exception ex)
{
throw ex;
}
}
And Here is the Azure App function that is called:
string guidString = req.Query["id"];
if (!Guid.TryParse(guidString, out var fileId))
return new BadRequestResult();
var fileManager = new FileManager();
dynamic fileData = fileManager.DownloadFile(fileId);
if (null == fileData) return new NotFoundResult();
var contentType = (((string)fileData.FileName).ToUpper().EndsWith(".PNG") || ((string)fileData.FileName).ToUpper().EndsWith(".JPEG") || ((string)fileData.FileName).ToUpper().EndsWith(".JPG")) ? "image/jpeg" : "application/octet-stream";
return new FileContentResult(fileData.Bytes, contentType)
{
FileDownloadName = fileData.FileName
};
The file is succesfully downloaded but it seems corrupted as it says that the file type is not recognised. I think that it's an issue related to encoding. Does somebody sees what I'm doing wrong ?
Your code is using UTF8.GetBytes() to try and get the file content from SharePoint Online. You should instead use the CSOM method OpenBinaryDirect() like this:
var fileRef = file.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
using (var fileStream = System.IO.File.Create(fileName))
{
fileInfo.Stream.CopyTo(fileStream);
}
I am trying to load a file stream into the Infragistics workbook via the Workbook.Load(Filestream stream) function. And i am doing this in a dot net core 3.1 application using the latest package version 20.1.123 of the Infragistics.Web.Documents.Excel nuget package. But i am unable to load .xlsx and .xlsm files into the workbook and i end up getting an exception --> Invalid or unrecognized file format. (Parameter 'stream').
var client = new SftpClient("ConnString");
client.Connect();
using (client)
{
if (client.Exists("filename.xlsm"))
{
var fileContents = client.OpenRead("filename.xlsm");
var workbook = Workbook.Load(fileContents);
}
}
ArgumentException: Invalid or unrecognized file format. (Parameter
'stream')
Exception is from this line: var workbook = Workbook.Load(fileContents);
From the source code we can see,
public static Workbook Load(Stream stream, WorkbookLoadOptions loadOptions = null);
pblic SftpFileStream OpenRead(string path);
SftpFileStream from OpenRead() is not correspond to Stream Workbook.Load().
Solution : Using DownloadFile to get Steam. And it works for me.
Codes of Controllers:
public string loadExcel()
{
StringBuilder sb = new StringBuilder();
// Path to file on SFTP server
string pathRemoteFile = "/";
var client = new SftpClient("127.0.0.1", 23, "admin","123456");
client.Connect();
using (client)
{
if (client.Exists("filename.xlsm"))
{
//var fileContents = client.OpenRead("/filename.xlsm");
var fileContents = new MemoryStream();
client.DownloadFile("filename.xlsm", fileContents);
var workbook = Workbook.Load(fileContents);
var worksheet = workbook.Worksheets[0];
sb.AppendLine(String.Format("{0} \t\t {1}",
worksheet.Rows[0].Cells[0].GetText(),
worksheet.Rows[0].Cells[1].GetText()));
}
}
return sb.ToString();
}
Test environment
SFTP
filename.xlsm
Screenshot of result
Iam trying to write a xls download for my Spring boot application. In order to generate the file Iam using POI. If I download the file directly from my Controller without passing it to the front-end like so:
//Wrote this one just for testing if the file is already corrupt here.
FileOutputStream fos = new FileOutputStream("C:\\dev\\directDownload.xls");
fos.write(byteArray);
fos.flush();
fos.close();
}
It works just fine and the file looks like this:
xls when downloaded from the backend without passing it to angular:
However thats not my goal. I intend to pass the Outputstream to my angular component. The Component calls a function from a service class. This class gets the response from the controller and passes it back to my component. In the UI the downloading dialog opens. The problem is, that the downloaded file looks like this (doesnt matter if its opened via excel or open office):
Currupt xls:
My Java Controller:
#CrossOrigin(exposedHeaders = "Content-Disposition")
#RequestMapping(value = "/report/file", produces = "application/vnd.ms-excel;charset=UTF-8")
public void getReportFile(#RequestParam(name = "projectNumber") final String projectNumber,
#RequestParam(name = "month") final int month, #RequestParam(name = "year") final int year,
#RequestParam(name = "employee") final int employee,
#RequestParam(name = "tsKey") final String tsKey,
final HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
String excelFileName = "test.xls";
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"",
excelFileName);
response.setHeader(headerKey, headerValue);
//Here I create the workbook that I want to download
ProjectMonthReport report = reportService.getReport(projectNumber, month, year);
//ExcelService builts the workbook using POI
Workbook workbook = excelService.exportExcel(report, employee, tsKey);
//The response is stored in an outputstream
OutputStream out = response.getOutputStream();
response.setContentType("application/vnd.ms-excel");
byte[] byteArray = ((HSSFWorkbook)workbook).getBytes();
out.write(byteArray);
out.flush();
out.close();
//Wrote this one just for testing if the file is already corrupt here. --> It's fine.
FileOutputStream fos = new FileOutputStream("C:\\dev\\directDownload.xls");
fos.write(byteArray);
fos.flush();
fos.close();
}
The Java Service method that builds the file using POI:
public Workbook exportExcel(final ProjectMonthReport report, final int employee, final String tsKey) throws IOException,
InvalidFormatException {
Workbook workbook = new HSSFWorkbook();
CreationHelper createHelper = workbook.getCreationHelper();
// Create a Sheet
Sheet sheet = workbook.createSheet("Employee");
// Create a Font for styling header cells
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setFontHeightInPoints((short) 14);
headerFont.setColor(IndexedColors.RED.getIndex());
// Create a CellStyle with the font
CellStyle headerCellStyle = workbook.createCellStyle();
headerCellStyle.setFont(headerFont);
Row headeRow = sheet.createRow(0);
Cell dateHeader = headeRow.createCell(0);
dateHeader.setCellValue("Datum");
Cell startHeader = headeRow.createCell(1);
startHeader.setCellValue("Beginn");
Cell endHeader = headeRow.createCell(2);
endHeader.setCellValue("Ende");
Cell activityHeader = headeRow.createCell(3);
activityHeader.setCellValue("Tätigkeitsbereit");
Cell cardHeader = headeRow.createCell(4);
cardHeader.setCellValue("Kartennummer");
List<WorkDescriptionDetail> details = report.getEmployees().get(employee).getKeyDetailMap().get(Integer.valueOf(tsKey)).getDetailList();
int counter = 1;
for (WorkDescriptionDetail detail : details) {
List <String> stringList= detail.toStringList();
Row row = sheet.createRow(counter);
Cell cellDate = row.createCell(0);
cellDate.setCellValue(stringList.get(0));
Cell cellStart = row.createCell(1);
cellStart.setCellValue(stringList.get(1));
Cell cellEnd = row.createCell(2);
cellEnd.setCellValue(stringList.get(2));
Cell cellActivity = row.createCell(3);
cellActivity.setCellValue(stringList.get(3));
counter ++;
}
return workbook;
}
My angular component:
saveFile(employee: string, tsKey:string) {
this.subscription = this.reportService.saveXlsFile(this.projectNumber, this.year, this.month, employee, tsKey)
.subscribe(response=> {
console.log(response);
let mediatype = 'application/vnd.ms-excel;charset=UTF-8';
const data = new Blob(["\ufeff",response.arrayBuffer()], {type: mediatype});
console.log(data);
saveAs(data, 'test.xls');
},
error => console.log("error downloading the file"));
}
The Ts Service Function that is called:
saveXlsFile(projectNumber:string, year:string, month:string, empId: string, tsKey:string) {
let params:URLSearchParams = new URLSearchParams();
params.set('projectNumber', projectNumber);
console.log(projectNumber);
params.set('month', month);
console.log(month);
params.set( 'year', year);
console.log(year);
params.set('employee', empId);
console.log(empId);
params.set('tsKey', tsKey);
console.log(tsKey);
return this.http.get(this.baseUrl + "/file", { search: params } );
}
I tried to retrieve the response via Postman and directly download the file. When I do that the file can't be opened by excel (Excel just crashed), however I can open the file in the OpenOffice version and it works fine. Its also not corrupted.
I've been searching the web for the last couple of days and I think it may be an enconding problem caused in the frontend. But maybe it is also SpringBoot thats playing me here. Any suggestions?
Thank you for your help!
Hey I found the solution to this problem yesterday myself. Adding the following in the angular service:
return this.http.get(this.baseUrl + "/file", { search: params, responseType: ResponseContentType.Blob }).map(
(res) => {
return new Blob([res.blob()], { type: 'application/vnd.ms-excel' });
});
After that you'll need to modify the component like so:
saveFile(employee: string, tsKey:string) {
this.subscription = this.reportService.saveXlsFile(this.projectNumber, this.year, this.month, employee, tsKey)
.subscribe(response=> {
console.log(response);
let mediatype = 'application/vnd.ms-excel';
saveAs(response, 'test.xlsx');
},
error => console.log("error downloading the file"));
}
So the Problem was that I was not getting a blob Object in my response....
while I was trying to upload an excel file with kendo ui I found a code on the internet. It is using a keyword named "Constants" but this keyword does not recognize the ".xls" file extension. I am stuck at this and did some research but have no answer to solve this. Here is my code:
public ActionResult Submit(IEnumerable<HttpPostedFileBase> files)
{
if(files!= null)
{
string fileName;
string filePath;
string fileExtension;
foreach(var f in files)
{
//Set file details
SetFileDetails(f, out fileName, out filePath, out fileExtension);
if(fileExtension == Constants.xls || fileExtension == Constants.xlsx)
{
//Save the uploaded file to app folder
string savedExcelFiles = Constants.UploadedFolder + fileName;
f.SaveAs(Server.MapPath(savedExcelFiles));
ReadDataFromExcelFiles(savedExcelFiles);
}
else
{
//file not supported send alert
}
}
}
return RedirectToActionPermanent("Index","Connect");
}
private static void SetFileDetails(HttpPostedFileBase f,out string fileName,out string filePath,out string fileExtension)
{
fileName=Path.GetFileName(f.FileName);
fileExtension=Path.GetExtension(f.FileName);
filePath = Path.GetFullPath(f.FileName);
}
private void ReadDataFromExcelFiles(string savedExcelFiles)
{
var connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=Excel 12.0;",Server.MapPath(savedExcelFiles));
//fill the DataSet by the sheets
var adapter = new OleDbDataAdapter("SELECT * FROM [Sheet1$]",connectionString);
var ds = new DataSet();
List<UploadExcel> uploadExl = new List<UploadExcel>();
adapter.Fill(ds,"Subscriber");
DataTable data=ds.Tables["Subscriber"];
GetSetUploadExcelData(uploadExl,data);
}
private static void GetSetUploadExcelData (List<UploadExcel> uploadExl,DataTable data)
{
for(int i=0;i<data.Rows.Count-1;i++)
{
UploadExcel NewUpload = new UploadExcel();
NewUpload.ID = Convert.ToInt16(data.Rows[i]["ID"]);
NewUpload.CostCenter = Convert.ToString(data.Rows[i]["CostCenter"]);
NewUpload.FirstName = Convert.ToString(data.Rows[i]["FirstName"]);
NewUpload.LastName = Convert.ToString(data.Rows[i]["LastName"]);
NewUpload.MobileNo = Convert.ToString(data.Rows[i]["MobileNo"]);
NewUpload.EmailID = Convert.ToString(data.Rows[i]["EmailID"]);
NewUpload.Services = Convert.ToString(data.Rows[i]["Services"]);
NewUpload.UsageType = Convert.ToString(data.Rows[i]["UsageType"]);
NewUpload.Network = Convert.ToString(data.Rows[i]["Network"]);
NewUpload.UsageIncluded = Convert.ToInt16(data.Rows[i]["UsageIncluded"]);
NewUpload.Unit = Convert.ToString(data.Rows[i]["Unit"]);
uploadExl.Add(NewUpload);
}
}
}
I suspect that the Constants.xls relates to a static class or enum that the original code author is using to hold the .xls/.xlsx extensions.
If you create a constants class something like:
public static class Constants
{
public static string xls = "xls";
public static string xlsx = "xlsx";
}
This would then should help.
If you need any more assistance then please let me know.
edit: Just reviewing the code it seems they are also putting in constant mapping for the uploadfolder location as well so I suspect this is just a static class rather than an enum with application specific details. in a way a bit like using the appSettings within webconfig
I want to download the files from a sharepoint document library through code as there are thousand of files in the document library.
I am thinking of creating console application, which I will run on sharepoint server and download files. Is this approach correct or, there is some other efficient way to do this.
Any help with code will be highly appreciated.
Like SigarDave said, it's perfectly possible to achieve this without writing a single line of code. But if you really want to code the solution for this, it's something like:
static void Main(string[] args)
{
// Change to the URL of your site
using (var site = new SPSite("http://MySite"))
using (var web = site.OpenWeb())
{
var list = web.Lists["MyDocumentLibrary"]; // Get the library
foreach (SPListItem item in list.Items)
{
if (item.File != null)
{
// Concat strings to get the absolute URL
// to pass to an WebClient object.
var fileUrl = string.Format("{0}/{1}", site.Url, item.File.Url);
var result = DownloadFile(fileUrl, "C:\\FilesFromMyLibrary\\", item.File.Name);
Console.WriteLine(result ? "Downloaded \"{0}\"" : "Error on \"{0}\"", item.File.Name);
}
}
}
Console.ReadKey();
}
private static bool DownloadFile(string url, string dest, string fileName)
{
var client = new WebClient();
// Change the credentials to the user that has the necessary permissions on the
// library
client.Credentials = new NetworkCredential("Username", "Password", "Domain");
var bytes = client.DownloadData(url);
try
{
using (var file = File.Create(dest + fileName))
{
file.Write(bytes, 0, bytes.Length); // Write file to disk
return true;
}
}
catch (Exception)
{
return false;
}
}
another way without using any scripts is by opening the document library using IE then in the ribbon you can click on Open in File Explorer where you can then drag and drop the files right on your desktop!