I'm developing a rather simple visual WebPart for SharePoint Foundation Server 2010.
It's supposed to upload an image file to the SharePoint server and display it afterwards.
While I can successfully upload the file to a previously created document library, the file cannot be displayed (IE shows the red cross). When I upload an exact copy of the file using SharePoint frontend, it can be opened. I hope that someone can tell me what I'm missing.
Below you can find the code that successfully uploads a file to the server:
SPContext.Current.Web.AllowUnsafeUpdates = true;
string path = "";
string[] fileName = filePath.PostedFile.FileName.Split('\\');
int length = fileName.Length;
// get the name of file from path
string file = fileName[length - 1];
SPWeb web = SPContext.Current.Web;
SPFolderCollection folders = web.Folders;
SPFolder folder;
SPListCollection lists = web.Lists;
SPDocumentLibrary library;
SPList list = null;
Guid guid = Guid.Empty;
if (lists.Cast<SPList>().Any(l => string.Equals(l.Title, "SPUserAccountDetails-UserImages")))
{
list = lists["SPUserAccountDetails-UserImages"];
}
else
{
guid = lists.Add("SPUserAccountDetails-UserImages", "Enthält Mitarbeiter-Fotos", SPListTemplateType.DocumentLibrary);
list = web.Lists[guid];
}
library = (SPDocumentLibrary)list;
folder = library.RootFolder.SubFolders.Add("SPUserAccountDetails");
SPFileCollection files = folder.Files;
Stream fStream = filePath.PostedFile.InputStream;
byte[] MyData = new byte[fStream.Length];
Stream stream = new MemoryStream();
stream.Read(MyData, 0, (int)fStream.Length);
fStream.Close();
bool bolFileAdd = true;
for (int i = 0; i < files.Count; i++)
{
SPFile tempFile = files[i];
if (tempFile.Name == file)
{
folder.Files.Delete(file);
bolFileAdd = true;
break;
}
}
if (bolFileAdd)
{
SPFile f = files.Add(file, MyData);
f.Item["ContentTypeId"] = "image/jpeg";
f.Item["Title"] = file;
f.Item.SystemUpdate();
SPContext.Current.Web.AllowUnsafeUpdates = false;
imgPhoto.ImageUrl = (string)f.Item[SPBuiltInFieldId.EncodedAbsUrl];
}
Never mind. My code seems to mess with the file content. I'll post the solution later.
edit:
I'm stupid and sorry :-/
I replaced this:
Stream fStream = filePath.PostedFile.InputStream;
byte[] MyData = new byte[fStream.Length];
Stream stream = new MemoryStream();
stream.Read(MyData, 0, (int)fStream.Length);
fStream.Close();
with this:
Stream fStream = filePath.PostedFile.InputStream;
byte[] MyData = new byte[fStream.Length];
BinaryReader binaryReader = new BinaryReader(fStream);
MyData = binaryReader.ReadBytes((Int32)fStream.Length);
fStream.Close();
binaryReader.Close();
and suddenly it all worked ;-)
Related
I'm trying to generate an excel file / stream in my web api and return it in a HttpResponseMessage to serve it to the client in Angular 5 as a download.
The generation succeeds and an xlsx file is generated and saved on the server, but when I return it in the Content of my httpResponseMessage, my browser shows just some json instead of the whole excel file.
{"version":{"major":1,"minor":1,"build":-1,"revision":-1,"majorRevision":-1,"minorRevision":-1},"content":{"headers":[{"key":"Content-Disposition","value":["attachment; filename=636742856488421817.xlsx"]},{"key":"Content-Type","value":["application/ms-excel"]},{"key":"Content-Length","value":["22780"]}]},"statusCode":200,"reasonPhrase":"OK","headers":[],"requestMessage":null,"isSuccessStatusCode":true}
This is how I create the excel file and returns it:
var dataBytes = File.ReadAllBytes(fileName);
var dataStream = new MemoryStream(dataBytes);
HttpResponseMessage httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK);
httpResponseMessage.Content = new StreamContent(dataStream);
httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileName;
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/ms-excel");
httpResponseMessage.Content.Headers.ContentLength = dataStream.Length;
I solved this:
Here is what I did
Helper class which creates the excel package and converts it to a Stream
var fileName = DateTime.Now.Ticks + ".xlsx";
FileInfo file = new FileInfo(fileName);
FileInfo templateFile = new FileInfo(#"Templates/ReportTemplate.xlsx");
ExcelPackage package = new ExcelPackage(file, templateFile);
ExcelWorksheet worksheet = package.Workbook.Worksheets.FirstOrDefault();
... filling rows and cells goed here ...
var dataBytes = package.GetAsByteArray();
Stream dataStream = new MemoryStream(dataBytes);
dataStream.Seek(0, SeekOrigin.Begin);
return dataStream;
In the controller I return the file to the Angular client like this:
var stream = _helperClass.GenerateReport(exportDate, exportTitle);
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"Report-{DateTime.Now.ToShortDateString()}.xlsx");
In the Angular component I do this after I receive the response:
var blob = new Blob([res], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
var blobURL = window.URL.createObjectURL(blob);
var anchor = document.createElement("a");
anchor.download = `Report-${new Date().toISOString()}.xlsx`;
anchor.href = blobURL;
anchor.click();
Try this following code:
For conroller:
[Route("DownLoadExcel")]
public IActionResult DownLoadExcel()
{
var pack = new ExcelPackage();
ExcelWorksheet worksheet = pack.Workbook.Worksheets.Add("sample");
//First add the headers
worksheet.Cells[1, 1].Value = "ID";
worksheet.Cells[1, 2].Value = "Name";
//Add values
worksheet.Cells["A2"].Value = 1000;
worksheet.Cells["B2"].Value = "Jon";
return File(pack.GetAsByteArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Sample.xlsx");
}
For client side:
window.open("../.../DownLoadExcel");
I have the below code to save the data in excel sheet as .xls
public ActionResult ExportToExcel()
{
DataTable tbl = CopyGenericToDataTable(res);
tbl.TableName = "InvalidInvoices";
using (XLWorkbook wb = new XLWorkbook())
{
wb.Worksheets.Add(tbl);
wb.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
wb.Style.Font.Bold = true;
Response.Clear();
Response.Buffer = true;
Response.Charset = "";
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename= "+fileName + ".xls");
using (MemoryStream MyMemoryStream = new MemoryStream())
{
wb.SaveAs(MyMemoryStream);
MyMemoryStream.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
}
}
}
Above is code which download the xls excel sheet at client side. It works fine the data gets saved in excel sheet.
Problem is if I try to upload this same file using below code -
if (files != null)
{
HttpPostedFileBase upload = files.FirstOrDefault();
Stream stream = upload.InputStream;
DataSet result = new DataSet();
if (upload != null && upload.ContentLength > 0)
{
if (upload.FileName.EndsWith(".xls") || upload.FileName.EndsWith(".xlsx"))
{
// ExcelDataReader works with the binary Excel file, so it needs a FileStream
// to get started. This is how we avoid dependencies on ACE or Interop:
// We return the interface, so that
IExcelDataReader reader = null;
if (upload.FileName.EndsWith(".xls"))
{
reader = ExcelReaderFactory.CreateBinaryReader(stream);
}
else if (upload.FileName.EndsWith(".xlsx"))
{
reader = ExcelReaderFactory.CreateOpenXmlReader(stream);
}
reader.IsFirstRowAsColumnNames = false;
result = reader.AsDataSet();
reader.Close();
}
}
}
In above code I am getting error in ExcelReaderFactory.CreateBinaryReader(stream);
In stream it has the values in bytes too just on using createBinaryreader of excelreaderfactory reader has error message as 'Invalid file signature'.
Any help will be highly appreciated.
ClosedXML generates .xlsx files, not .xls files.
Check your code:
Response.AddHeader("content-disposition", "attachment;filename= "+fileName + ".xls");
I am calling Sharepoint web service methond GetListItems, and don't see anything about file/folder size being returned. Am I missing something, or is there another way to get the size of the file/folder. Many thanks in advance.
the field you need is called ows_FileSizeDisplay, this returns an int for the number of bytes.
here is some code to put you on the rigth track
List<File> files = new List<File>(1);
File tempFile;
#region Get SharePointItems
SharePointListService.Lists svc = new SharePointListService.Lists();
XmlNode spItemsNode;
try
{
svc.Credentials = System.Net.CredentialCache.DefaultCredentials;
svc.Url = baseSharePointPath+"/_vti_bin/Lists.asmx";
XmlDocument xmlDoc = new System.Xml.XmlDocument();
XmlNode queryOptions =
xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
queryOptions.InnerXml = "<QueryOptions><IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns><DateInUtc>TRUE</DateInUtc><Folder>" +
baseSharePointPath + "/"+ listName + "/"+ folderName + "</Folder></QueryOptions>";
XmlNode query =
xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
query.InnerXml = "<Where><Eq><FieldRef Name='Usage'/><Value Type='Text'>%%usage%%</Value></Eq></Where>";
query.InnerXml = query.InnerXml.Replace("%%usage%%", ConvertFileUsageToString(usage));
spItemsNode = svc.GetListItems(listName,
null, query, null, null, queryOptions, null);
}
finally
{
svc.Dispose();
}
// load the response into an xml document
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(spItemsNode.OuterXml);
// create a namespace manager
XmlNamespaceManager ns = new XmlNamespaceManager(xDoc.NameTable);
// add all the special SharePoint Namespaces in
ns.AddNamespace("rs", "urn:schemas-microsoft-com:rowset");
ns.AddNamespace("z", "#RowsetSchema");
ns.AddNamespace("sp", "http://schemas.microsoft.com/sharepoint/soap/");
ns.AddNamespace("s", "uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882");
ns.AddNamespace("dt", "uuid:C2F41010-65B3-11d1-A29F-00AA00C14882");
XmlNodeList Items = xDoc.SelectNodes(#"/sp:listitems/rs:data/z:row", ns);
#endregion
foreach (XmlNode currentFile in Items)
{
tempFile = new File();
tempFile.Name = currentFile.Attributes["ows_NameOrTitle"].Value;
tempFile.Type = currentFile.Attributes["ows_DocIcon"].Value;
tempFile.Usage = ConvertToFileUsage(currentFile.Attributes["ows_Usage"].Value);
tempFile.Data = getFileBytes(currentFile.Attributes["ows_RequiredField"].Value, baseSharePointPath);
files
Here is a nice code snippet that will do the job shout if you have any questions
Folder folder = getFolder(serverRelitiveURL);
FileCollection files = folder.Files;
folder.Context.Load(files);
folder.Context.ExecuteQuery();
int folderSize;
foreach(file in files)
{
ListItem li = file.ListItemAllFields;
Console.writeline(li["File_x0020_Size"]);
folderSize = li["File_x0020_Size"]+folderSize;
}
Console.writeline(folderSize);
On button click event or on Link button click, I want to download document from sharepoint document library and save it to the user's local disk.
Plz help me on this,If you have any code sample then please share
The problem with outputting a direct link to the file, is that for some content types it may just open in the browser window. If that is not the desired outcome, and you want to force the save file dialog, you'll need to write an ASP/PHP page that you could pass a filename to via the querystring. This page could then read the file and set some headers on the response to indicate that the content-disposition is and attachment.
For ASP.net, if you create a simple aspx page called download.aspx, add the following code into it, then put this file on a server somewhere you can download files by calling this page like this:
http://yourserveraddress/download.aspx?path=http://yoursharepointserver/pathtodoclibrary/file.ext
protected void Page_Load(object sender, EventArgs e)
{
string path = "";
string fileName = "";
path = Request.QueryString["path"];
if (path != null && path.Length > 0)
{
int lastIndex = path.LastIndexOf("/");
fileName = path.Substring(lastIndex + 1, (path.Length - lastIndex - 1));
byte[] data;
data = GetDataFromURL(path);
Response.Clear();
Response.AppendHeader("Content-Disposition", "attachment; filename=" + fileName);
Response.BinaryWrite(data);
Response.Flush();
}
}
protected byte[] GetDataFromURL(string url)
{
WebRequest request = WebRequest.Create(url);
byte[] result;
byte[] buffer = new byte[4096];
//uncomment this line if you need to be authenticated to get to the files on SP
//request.Credentials = new NetworkCredential("username", "password", "domain");
using (WebResponse response = request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (MemoryStream ms = new MemoryStream())
{
int count = 0;
do
{
count = responseStream.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, count);
} while (count != 0);
result = ms.ToArray();
}
}
}
return result;
}
I'd create a LinkButton and set the URL to the document's url programmatically.
I have a SharePoint calendar event that can have any type of file as attachment. Is there any way to access the contents of the file/ download them? I have to calculate the check sum of these files.
string siteURL = "http://yourserver/yourpathtothesite";
using (SPSite site = new SPSite(siteURL))
{
using (SPWeb web = site.OpenWeb())
{
string listName = "Events";
SPList calendarList = web.Lists[listName];
// get whatever item you are interested in
SPListItem item = calendarList.GetItemById(1);
foreach (String attachmentname in item.Attachments)
{
String attachmentAbsoluteURL = item.Attachments.UrlPrefix + attachmentname;
// To get the SPSile reference to the attachment just use this code
SPFile attachmentFile = web.GetFile(attachmentAbsoluteURL);
// To read the file content simply use this code
Stream stream = attachmentFile.OpenBinaryStream();
StreamReader reader = new StreamReader(stream);
String fileContent = reader.ReadToEnd();
}
}
}
Source: http://www.dotnetking.com/TechnicalComments.aspx?LogID=352