I have been working with epplus on .NET desktop projects (C#) and using templates like this:
var package = new ExcelPackage(new FileInfo("C:\\Templates\\FormatoReporteSamsung.xlsx"))
But now I'working with a .NET Web Project (C#) and i don't know what make to refer to the template that exist like a web resource where the URI of that resource like this:
http://myownweb:29200/Content/excelTemplates/Formato.xlsx
At the end I pass the excel template as a stream using this code.
using (var package = new ExcelPackage(new MemoryStream(GetBytesTemplate(FullyQualifiedApplicationPath + "Content/excelTemplates/Format.xlsx"))))
{
//Write data to excel
//Read file like byte array to return a response
Response.Clear();
Response.ContentType = "application/xlsx";
Response.AddHeader("content-disposition", "attachment; filename=" + "myFileName" + ".xlsx");
Response.BinaryWrite(package.GetAsByteArray());
Response.End();
}
To read the excel file has bytes I use this
Error "This stream does not support seek operations" in C#
private byte[] GetBytesTemplate(string url)
{
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
WebResponse myResp = myReq.GetResponse();
byte[] b = null;
using (Stream stream = myResp.GetResponseStream())
using (MemoryStream ms = new MemoryStream())
{
int count = 0;
do
{
byte[] buf = new byte[1024];
count = stream.Read(buf, 0, 1024);
ms.Write(buf, 0, count);
} while (stream.CanRead && count > 0);
b = ms.ToArray();
}
return b;
}
And to get the name of the website i use
http://devio.wordpress.com/2009/10/19/get-absolut-url-of-asp-net-application/
public string FullyQualifiedApplicationPath
{
get
{
//Return variable declaration
string appPath = null;
//Getting the current context of HTTP request
HttpContext context = HttpContext.Current;
//Checking the current context content
if (context != null)
{
//Formatting the fully qualified website url/name
appPath = string.Format("{0}://{1}{2}{3}",
context.Request.Url.Scheme,
context.Request.Url.Host,
context.Request.Url.Port == 80
? string.Empty : ":" + context.Request.Url.Port,
context.Request.ApplicationPath);
}
if (!appPath.EndsWith("/"))
appPath += "/";
return appPath;
}
}
Related
I'm trying to download a ZIP file in ASP NET MVC. I have done in ASP NET Webforms, and it works correcly, but I do the same in MVC and I don't get the same result, I tried the following:
public ActionResult Download()
{
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(Server.MapPath("~/Directories/hello"));
zip.Save(Server.MapPath("~/Directories/hello/sample.zip"));
return File(Server.MapPath("~/Directories/hello/sample.zip"),
"application/zip", "sample.zip");
}
}
But I get the binary data in screen, not the downloaded zip file why this is not working in MVC?
I have found that this does not work if I do it from a partial class, if I execute the download code from the Index and send the file if it works, why?
I use this to download files. In your view:
var ext = Path.GetExtension(path);
string contentType = GetMimeType(ext);
using (var stream = fileManager.GetStream(path))
{
var filename = fileManager.GetFileName(path);
var response = System.Web.HttpContext.Current.Response;
TransmitStream(stream, response, path, filename, contentType);
return new EmptyResult();
}
Where GetMimeType is a method that return known MIME types:
public static string GetMimeType(string extension, string defaultValue = "application/octet-stream")
{
if (extension == null)
{
throw new ArgumentNullException(nameof(extension));
}
if (!extension.StartsWith("."))
{
extension = "." + extension;
}
string mime;
return _mappings.TryGetValue(extension, out mime) ? mime : defaultValue;
}
With _mappings as:
private static readonly IDictionary<string, string> _mappings =
new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase) {
{".323", "text/h323"},
{".3g2", "video/3gpp2"},
{".3gp", "video/3gpp"},
{".3gp2", "video/3gpp2"},
{".3gpp", "video/3gpp"},
{".7z", "application/x-7z-compressed"},
// Other types...
{".xwd", "image/x-xwindowdump"},
{".z", "application/x-compress"},
{".zip", "application/x-zip-compressed"},
};
And the TransmitStream:
public static void TransmitStream(
Stream stream, HttpResponse response, string fullPath, string outFileName = null, string contentType = null)
{
contentType = contentType ?? MimeMapping.GetMimeMapping(fullPath);
byte[] buffer = new byte[10000];
try
{
var dataToRead = stream.Length;
response.Clear();
response.ContentType = contentType;
if (outFileName != null)
{
response.AddHeader("Content-Disposition", "attachment; filename=" + outFileName);
}
response.AddHeader("Content-Length", stream.Length.ToString());
while (dataToRead > 0)
{
// Verify that the client is connected.
if (response.IsClientConnected)
{
// Read the data in buffer.
var length = stream.Read(buffer, 0, 10000);
// Write the data to the current output stream.
response.OutputStream.Write(buffer, 0, length);
// Flush the data to the output.
response.Flush();
buffer = new byte[10000];
dataToRead = dataToRead - length;
}
else
{
// Prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
catch (Exception ex)
{
throw new ApplicationException(ex.Message);
}
finally
{
response.Close();
}
}
Usually, if you want to download something i suggest you to use ContentResult
,transforming the file you want to download into a Base64 String and transforming it on the frontend using javascript with a Blob
Action
public ContentResult Download()
{
MemoryStream memoryStream = new MemoryStream();
file.SaveAs(memoryStream);
byte[] buffer = memoryStream.ToArray();
string fileAsString = Convert.ToBase64String(buffer);
return Content(file, "application/zip");
}
front end
var blob = new Blob([Base64ToBytes(response)], { type: "application/zip" });
var link = document.createElement("a");
document.body.appendChild(link);
link.setAttribute("type", "hidden");
link.href = url.createObjectURL(blob);
link.download = fileName;
link.click();
I have a below scenario.
Client send request to Server-1 for file download
Server-1 send request to Server-2 for file.
To make this work I need to create a mechanism where once client send request to the Server-1, Server-1 will request to Server-2 which will send file as response output-stream in chunks. Server-1 will send this file chunks to client browser continuously as it keep receiving from server-2.
I have done code as below, theoretically it looks fine but still it is not working.
It is not downloading entire file in client browser, it seems like last chunk is not transferred to the Server-1 or it is not downloading to client browser from Server-1
Server-1 Code (Where client request for File download)
private void ProccesBufferedResponse(HttpWebRequest webRequest, HttpContext context)
{
char[] responseChars = null;
byte[] buffer = null;
if (webRequest == null)
logger.Error("Request string is null for Perfios Docs Download at ProccesBufferedResponse()");
context.Response.Buffer = false;
context.Response.BufferOutput = false;
try
{
WebResponse webResponse = webRequest.GetResponse();
context.Response.ContentType = "application/pdf";
context.Response.AddHeader("Content-disposition", webResponse.Headers["Content-disposition"]);
StreamReader responseStream = new StreamReader(webResponse.GetResponseStream());
while (!responseStream.EndOfStream)
{
responseChars = new char[responseStream.ToString().ToCharArray().Length];
responseStream.Read(responseChars, 0, responseChars.Length);
buffer = Encoding.ASCII.GetBytes(responseChars);
context.Response.Clear();
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
context.Response.Flush();
}
}
catch (Exception ex)
{
throw;
}
finally
{
context.Response.Flush();
context.Response.End();
}
}
Server-2 Code (Where Server-1 will send request for file)
private void DownloadInstaPerfiosDoc(int CompanyID, string fileName, string Foldertype)
{
string folderPath;
string FilePath;
int chunkSize = 1024;
int startIndex = 0;
int endIndex = 0;
int length = 0;
byte[] bytes = null;
DirectoryInfo dir;
folderPath = GetDocumentDirectory(CompanyID, Foldertype);
FilePath = folderPath + "\\" + fileName;
dir = new DirectoryInfo(folderPath);
HttpContext.Current.Response.Buffer = false;
HttpContext.Current.Response.BufferOutput = false;
if (dir.Exists && dir.GetFiles().Length > 0)
{
foreach (var file in dir.GetFiles(fileName))
{
FilePath = folderPath + "\\" + file.Name;
FileStream fsReader = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
HttpContext.Current.Response.ContentType = "application/pdf";
HttpContext.Current.Response.AddHeader("Content-disposition", string.Format("attachment; filename = \"{0}\"", fileName));
int totalChunks = (int)Math.Ceiling((double)fsReader.Length / chunkSize);
for (int i = 0; i < totalChunks; i++)
{
startIndex = i * chunkSize;
if (startIndex + chunkSize > fsReader.Length)
endIndex = (int)fsReader.Length;
else
endIndex = startIndex + chunkSize;
length = (int)endIndex - startIndex;
bytes = new byte[length];
fsReader.Read(bytes, 0, bytes.Length);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.OutputStream.Write(bytes, 0, bytes.Length);
HttpContext.Current.Response.Flush();
}
}
}
}
Please help me to resolve this issue.
It is possible and feasible. I'll give a pseudo procedure for you to understand the overall idea.
Server1
download action gets hit
create a request to server2
get the response stream of your server2 request
read the response stream in desired chunk sizes until it's consumed completely
write each chunk (as soon as you read) to current response stream
Server2
download action gets hit
write your stream onto your current response stream however you like
I am trying to download a file from the server to a folder that the client chooses onto their machine. But I keep getting the error could not find part of the path
For example the DownloadLocation could be C:/myfolder
Code:
FileName = comp.DownloadLocation + "/" + "/purchase" + ".csv";
regularfilename = "purchase.csv";
byte[] buffer;
using (FileStream fileStream = new FileStream(FileName, FileMode.Open))
{
int fileSize = (int)fileStream.Length;
buffer = new byte[fileSize];
fileStream.Read(buffer, 0, (int)fileSize);
}
Response.Clear();
Response.Buffer = true;
Response.BufferOutput = true;
Response.ContentType = "application/x-download";
Response.AddHeader("Content-Disposition", "attachment; filename=" + regularfilename);
Response.CacheControl = "public";
Response.OutputStream.Write(buffer, 0, buffer.Length);
Response.Flush();
Response.Clear();
Response.End();
Possibly not the answer however this is something you should definitely check:
FileName = comp.DownloadLocation + "/" + "/purchase" + ".csv";
You probably want to remove the / before purchase or drop the + "/" + completely as that's going to build up a path in the format:
"somepath//purchase.csv"
May well be casuing your issue. See if it makes a difference.
If you need a client app to check the Web API server to see if the server's version of a file is newer than the version the client has, you can set up the server to do so by performing these steps:
Add the appropriate method to a Repository Interface, such as:
HttpResponseMessage GetCervezaBeberUpdate(string clientVersion);
Add this to the corresponding Controller class (where the Controller name is "HenryFieldingController"):
[Route("api/HenryFielding/GetUpdatedCervezaBeber")]
public HttpResponseMessage GetUpdate(string clientVersion)
{
return _tomJonesRepository.GetCervezaBeberUpdate(clientVersion);
}
Add the appropriate method to the concrete Repository class, such as:
public HttpResponseMessage GetCervezaBeberUpdate(string clientVersion)
{
var binaryFilePath = HostingEnvironment.MapPath(#"~\App_Data\CervezaBeber.exe");
FileVersionInfo currentVersion = FileVersionInfo.GetVersionInfo(binaryFilePath);
if (!ServerFileIsNewer(clientVersion, currentVersion))
{
result = new HttpResponseMessage(HttpStatusCode.NoContent);
}
else
{
var stream = new FileStream(binaryFilePath, FileMode.Open);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
}
return result;
}
Also add the method in that Repository class that GetCervezaBeberUpdate() calls:
private bool ServerFileIsNewer(string clientFileVersion, FileVersionInfo serverFile)
{
Version client = new Version(clientFileVersion);
Version server = new Version(string.Format("{0}.{1}.{2}.{3}", serverFile.FileMajorPart, serverFile.FileMinorPart, serverFile.FileBuildPart, serverFile.FilePrivatePart));
return server > client;
}
Now the client can call this by passing a URI like this to the server:
http://<servername>:<portnumber>/api/
<controllername>?clientVersion=<clientversionquad>
Or, for a more literal example, in the event your server's name is "Platypus", the port to use is 4242, the Controller is named HenryFieldingController, and the version of the file the client currently has is 3.1.4.1:
http://Platypus:4242/api/HenryFielding?clientVersion=3.1.4.1
As a free-as-in-beer (you/I wish!) premium, here's some code the client can use to save the server's response to a file (passing this a URI such as shown above):
private void DownloadTheFile(string uri)
{
var outputFileName = "Platypus.exe";
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
var webResponse = (HttpWebResponse)webRequest.GetResponse();
string statusCode = webResponse.StatusCode.ToString();
// From here on (including the CopyStream() method) derived from Jon Skeet's
// answer at http://stackoverflow.com/questions/411592/how-do-i-save-a-stream-to-a-file
if (statusCode == "NoContent")
{
MessageBox.Show("You already have the newest available version.");
}
else
{
var responseStream = webResponse.GetResponseStream();
using (Stream file = File.Create(outputFileName))
{
CopyStream(responseStream, file);
MessageBox.Show(string.Format("New version downloaded to {0}", outputFileName));
}
}
}
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[8 * 1024];
int len;
while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, len);
}
}
I have some PDFs stored in S3 and I'm trying to make a link that will download them. This is the method that I have so far:
public virtual ActionResult DownloadPDF(string filename)
{
string secretKey = this.UnitOfWork.ApplicationSettingRepository.GetOrCreateByName<string>("StorageProvider_AmazonS3_SecretKey");
string accessKey = this.UnitOfWork.ApplicationSettingRepository.GetOrCreateByName<string>("StorageProvider_AmazonS3_AccessKey");
var bucket = this.UnitOfWork.ApplicationSettingRepository.GetOrCreateByName<string>("StorageProvider_AmazonS3_BucketName");
var serviceUrl = this.UnitOfWork.ApplicationSettingRepository.GetOrCreateByName<string>("StorageProvider_AmazonS3_ServiceUrl");
AmazonS3Config config = new AmazonS3Config();
config.ServiceURL = serviceUrl;
var client = Amazon.AWSClientFactory.CreateAmazonS3Client(
accessKey,
secretKey,
config
);
GetObjectRequest request = new GetObjectRequest();
request.BucketName = bucket;
request.Key = "userfiles/MSD IMAGES/ProductDocumentation/" + filename;
GetObjectResponse response = client.GetObject(request);
response.WriteResponseStreamToFile("\\Downloads\\" + filename);
}
I got that method from this documentation here but I want to download the download to show in the browser, and go to the standard downloads folder. I created this method previously for downloading csv files:
var csv = new StringBuilder();
csv.AppendLine("col1,col2,col3");
var bytes = Encoding.UTF8.GetBytes(csv.ToString());
var response = new FileContentResult(bytes, "text/csv");
response.FileDownloadName = fileName;
return response;
I tried doing the same thing with the S3 file:
GetObjectResponse response = client.GetObject(request);
// response.WriteResponseStreamToFile("\\Downloads\\" + filename);
var bytes = Encoding.UTF8.GetBytes(response.ToString());
var download = new FileContentResult(bytes, "application/pdf");
download.FileDownloadName = filename;
return download;
it downloads a file, but the pdf doesn't work (it fails to load). How do I download the file that I got from S3?
Here's the working solution I came up with:
GetObjectResponse response = client.GetObject(request);
using (Stream responseStream = response.ResponseStream)
{
var bytes = ReadStream(responseStream);
var download = new FileContentResult(bytes, "application/pdf");
download.FileDownloadName = filename;
return download;
}
public static byte[] ReadStream(Stream responseStream)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
you would need to do something like the following
int byteCount
byte[] buffer = new byte[2048]; // read in chunks of 2KB
Stream responseStream= Response.GetResponseStream();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
while ((byteCount = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
Response.OutputStream.Write(buffer, 0, byteCount);
}
Response.Flush();
Response.Close();
Response.End();
I am quite ashamed to ask this question but somehow I am missing something.
Scenario
There is a sharepoint instance
There is a document list in sharepoint with three files
I have a asp.net MVC Portal which connects with Sharepoint instance
In a view it shows the list of files (3 in my case)
When user clicks on the item, the file is to be downloaded.
Problem
The file is downloaded but when you try to open it, word says the file downloaded is corrupt.
I have googled it and tried every variation of code. Only variation that works is to save the file on server and then download it to the client which as you know is not feasible
this is my code
As mentioned above the Sharepoint login,authentication etc all works correctly
fileref is the sharepoint path of the file
len is retrieved from Sharepoint
//int len= int.Parse(oListItemDoc.FieldValues["File_x0020_Size"].ToString());
string filePath = fileRef;
ClientContext clientContext = new ClientContext(GetSharePointUrl());
clientContext = SharepointAuthorisation(clientContext);
if (!string.IsNullOrEmpty(filePath))
{
var cd = new System.Net.Mime.ContentDisposition
{
FileName = Path.GetFileName(fileRef),
// always prompt the user for downloading, set to true if you want
// the browser to try to show the file inline
Inline = true,
};
Response.AppendHeader("Content-Disposition", cd.ToString());
byte[] fileArr=DownloadFile(title, clientContext, filePath,len,extension, "");
//FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef.ToString());
//byte[] arr = new byte[len];
//fileInfo.Stream.Read(arr, 0, arr.Length - 1);
//return arr;
Response.AppendHeader("Content-Disposition", cd.ToString());
//return new FileStreamResult(fileInfo.Stream, "application /octet-stream");// vnd.openxmlformats-officedocument.wordprocessingml.document");
return File(fileArr, "application/docx" , Path.GetFileName(fileRef));
}
else
{
return null;
}
public byte[] DownloadFile(string title, ClientContext clientContext, string fileRef, int len, string itemExtension, string folderName)// Renamed Function Name getdownload to DownloadFiles
{
if (itemExtension == ".pdf")
{
//string completePath = Path.Combine(Server.MapPath("~"), folderName);
//string PdfFile = completePath + "/" + "PDF";
////if (!Directory.Exists(PdfFile))
//{
// Directory.CreateDirectory(PdfFile);
//}
FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef.ToString());
byte[] arr = new byte[len];
fileInfo.Stream.Read(arr, 0, arr.Length);
return arr;
}
else
{
FileInformation fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef.ToString());
byte[] arr = new byte[len];
fileInfo.Stream.Read(arr, 0, arr.Length);
return arr;
}
}
What am I missing?
Probably it occurs since file size is determined incorrectly. Try to remove any dependency to file size from DownloadFile method as demonstrated below:
public static byte[] DownloadFile(ClientContext ctx,string fileUrl)
{
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(ctx, fileUrl);
using (var ms = new MemoryStream())
{
fileInfo.Stream.CopyTo(ms);
return ms.ToArray();
}
}