Here I'm using WebApi I want an image for sending Email For that I wrote the code as:
var files = HttpContext.Current.Request.Files;
if (files.Count > 0) {
for (int i = 0; i < files.Count; i++) {
HttpPostedFile file = files[i];
mailModel.filename = file.FileName;
mailModel.filecontent = file.InputStream;
}
}
Here How can i Bind mailModel.Filecontent
My Class File as
public class SendMailRequest
{
public string filecontent { get; set; }
public string filename { get; set; }
}
My Mail Sending Code is:
if (mailModel.filename != null) {
string tempPath = WebConfigurationManager.AppSettings["TempFile"];
string filePath = Path.Combine(tempPath, mailModel.filename);
using(System.IO.FileStream reader = System.IO.File.Create(filePath)) {
byte[] buffer = Convert.FromBase64String(mailModel.filecontent);
reader.Write(buffer, 0, buffer.Length);
reader.Dispose();
}
msg.Attachments.Add(new Attachment(filePath));
How can I Bind my File to the FileContent?
I think you probably want to learn about using Streams in .Net? First use Stream not string here:
public class SendMailRequest
{
public Stream FileContent { get; set; }
public string FileName { get; set; }
}
Then, because it's utterly confusing, rename your reader to writer.
Then, don't do anything stringy with your Stream, just do:
await mailModel.filecontent.CopyToAsync(writer);
There is a complication here. This code assumes that the original uploaded filestream is still present and working, in memory, at the time that you try to send your email. Whether that is true depends on what happens in between.
Especially, if the Http request processing has finished and a response been returned before the email gets sent, the filecontent stream has probably already gone away. has A safer course is to do the copy straight away in the controller:
file.InputStream.CopyToASync(mailModel.filecontent)
but at this point I have to say, I would rather either (1) copy straight to a file or (2) copy into a MemoryStream. i.e.
mailModel.filecontent= new MemoryStream();
file.InputStream.CopyToASync(mailModel.filecontent)
(If you use MemoryStream, you must calculate what is the largest file you are willing to handle, and make sure bigger files are rejected before you create the memory stream).
Finally, if this populates your file with Base64 instead of the binary, look at the answers to this question: HttpRequest files is empty when posting through HttpClient
Related
I have been messing with this for hours to no avail. I am trying to copy an excel file, add a new sheet to it, put the file in a MemoryStream and then return the stream.
Here is the code:
public Stream ProcessDocument()
{
var resultStream = new MemoryStream();
string sourcePath = "path\\to\\file";
string destinationPath = "path\\to\\file";
CopyFile(destinationPath, sourcePath);
var copiedFile = SpreadsheetDocument.Open(destinationPath, true);
var fileWithSheets = SpreadsheetDocument.Open("path\\to\\file", false);
AddCopyOfSheet(fileWithSheets.WorkbookPart, copiedFile.WorkbookPart, "foo");
using(var stream = new MemoryStream()){
copiedFile.WorkbookPart.Workbook.Save(stream);
stream.Position = 0;
stream.CopyTo(resultsStream);
}
return resultsStream;
}
public void CopyFile(string outputFullFilePath, string inputFileFullPath)
{
int bufferSize = 1024 * 1024;
using (var fileStream = new FileStream(outputFullFilePath, FileMode.OpenOrCreate))
{
var fs = new FileStream(inputFileFullPath, FileMode.Open, FileAccess.ReadWrite);
fileStream.SetLength(fs.Length);
int bytesRead = -1;
byte[] bytes = new byte[bufferSize];
while ((bytesRead = fs.Read(bytes, 0, bufferSize)) > 0)
{
fileStream.Write(bytes, 0, bytesRead);
}
fs.Close();
fileStream.Close();
}
}
public static void AddCopyOfSheet(WorkbookPart sourceDocument, WorkbookPart destinationDocument, string sheetName)
{
WorksheetPart sourceSheetPart = GetWorkSheetPart(sourceDocument, sheetName);
destinationDocument.AddPart(sourceSheetPart);
}
public static WorksheetPart GetWorksheetPart(WorkbookPart workbookPart, string sheetName)
{
string id = workbookPart.Workbook.Descendants<Sheet>().First(x => x.Name.Value.Contains(sheetName)).Id
return (WorksheetPart)workbookPart.GetPartById(id);
}
The issue seems to arise from copiedFile.WorkbookPart.Workbook.Save(stream).
After this is ran, I get an error saying that there was an exception of type 'System.ObjectDisposedException'. The file copies fine and adding the sheet seems to also be working.
Here's what I've tried:
Using .Save() without stream as a parameter. It does nothing.
Using two different streams (hence the resultStream jank left in this code)
Going pure OpenXML and copying the WorkbookParts to a stream directly. Tested with a plain text excel and was fine, but it breaks the desired file because it has some advanced formatting that does not seem to work well with OpenXML. I am open to refactoring if someone knows how I could work around this, though.
What I haven't tried:
Creating ANOTHER copy of the copy and using the SpreadsheetDocument.Create(stream, type) method. I have a feeling this would work but it seems like an awful and slow solution.
Updating OpenXML. I am currently on 2.5.
Any feedback or ideas are hugely appreciated. Thank you!
PS: My dev box is airgapped so I had to hand write this code over. Sorry if there are any errors.
Turns out that copiedFile.WorkbookPart.Workbook.Save(stream); disposes of the stream by default. The workaround to this was to make a MemoryStream class that overloads its ability to be disposed, like so:
public class DisposeLockableMemoryStream : MemoryStream
{
public DisposeLockableMemoryStream(bool allowDispose)
{
AllowDispose = allowDispose;
}
public bool AllowDispose { get; set; }
protected override void Dispose(bool disposing)
{
if (!AllowDispose)
return;
base.Dispose(disposing);
}
}
All you need to do is make sure you stream.AllowDispose = true and then dispose of it once you're done.
Now, this didn't really fix my code because it turns out that .Save() only tracks changes made to the document, not the entire thing!!!. Basically, this library is hot garbage and I regret signing up for this story to begin with.
For more information, see a post I made on r/csharp.
My class inherits from FluentFTP and I have created a class like this. I need to create a function called Read in this class. The purpose of the read function is to return a string to me by reading the contents of the files I have read from the FTP line by line. I'll process the rotating string later. Is there a method for this in FluentFTP? Ff there is none, how should I create the function?
using FluentFTP;
public class CustomFtpClient : FtpClient
{
public CustomFtpClient(
string host, int port, string username, string password) :
base(host, port, username, password)
{
Client = new FtpClient(host, port, username, password);
Client.AutoConnect();
}
private FtpClient Client { get; }
public string ReadFile(string remoteFileName)
{
Client.BufferSize = 4 * 1024;
return Client.ReadAllText(remoteFileName);
}
}
I can't write like this because the Client I'm writing comes from FTP. Since I derived it from SFTP in my previous codes, I wanted to use a similar code snippet to it, but there is no such code snippet in FluentFTP. How should I perform an operation in the Read function?
In another file, I want to call it like this.
CustomFtpClient = new CustomFtpClient(ftpurl, 21, ftpusername, ftppwd);
var listedfiles = CustomFtpClient.GetListing("inbound");
var onlyedifiles = listedfiles.Where(z =>
z.FullName.ToLower().Contains(".txt") || z.FullName.ToLower().Contains("940"))
.ToList();
foreach (var item in onlyedifiles)
{
//var filestr = CustomFtpClient.ReadFile(item.FullName);
}
To read file to a string using FluentFTP, you can use FtpClient.Download (FtpClient.DownloadStream or FtpClient.DownloadBytes in upcoming versions) that either writes the file contents to Stream or byte[] array. The following examples uses the latter.
if (!client.Download(out byte[] bytes, "/remote/path/file.txt"))
{
throw new Exception("Cannot read file");
}
string contents = Encoding.UTF8.GetString(bytes);
I now have this scenario:
I have a table in SQL Server, and a handful of webpage-user-defined queries that generates a results page showing the results. The controller functions are all ready to use.
Now I would like to be able to download the results to local computers accessing the website. I'm not sure yet what to put the results into. I've searched for it and both xls and csv files seem pretty straight-forward enough. But they only create a file and then save it onto the server side.
So my questions are:
Does the task must be accomplished by creating a temporary file ==> download the temporary file to client ==> delete the temporary file on the server?
If it must be so, how do I create a button for downloading that temporary file? And what will happen if it is serving multiple users at the same time?
Not sure what to do now and any help would be appreciated.
You should create a MemoryStream from the data received from Sql Server. Create a new class with the code below.
public abstract class FileActionResult : IHttpActionResult
{
private string MediaType { get; }
private string FileName { get; }
private Stream Data { get; }
protected FileActionResult(Stream data, string fileName, string mediaType)
{
Data = data;
FileName = fileName;
MediaType = mediaType;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
Data.Position = 0;
var response = new HttpResponseMessage
{
Content = new StreamContent(Data)
};
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentType = new MediaTypeHeaderValue(MediaType);
response.Content.Headers.ContentDisposition.FileName = FileName;
response.Content.Headers.ContentLength = Data.Length;
return Task.FromResult(response);
}
}
public class ExcelFileActionResult : FileActionResult
{
public ExcelFileActionResult(Stream data) : base(data, "Exported.xls", "application/vnd.ms-excel")
{
}
}
Calling code from Controller.
return new ExcelFileActionResult(stream);
stream is the memorystream.
Following the documentation, I'm having an extremely difficult time getting this to work. Using ZipFile I want to create a zip in memory and then be able to update it. On each successive call to update the, the zip reports that it has 0 entries.
What am I doing wrong?
public void AddFile(MemoryStream zipStream, Stream file, string fileName)
{
//First call to this zipStream is just an empty stream
var zip = ZipFile.Create(zipStream);
zip.BeginUpdate();
zip.Add(new ZipDataSource(file), fileName);
zip.CommitUpdate();
zip.IsStreamOwner = false;
zip.Close();
zipStream.Position = 0;
}
public Stream GetFile(Stream zipStream, string pathAndName)
{
var zip = ZipFile.Create(zipStream);
zip.IsStreamOwner = false;
foreach (ZipEntry hi in zip) //count is 0
{
}
var entry = zip.GetEntry(pathAndName);
return entry == null ? null : zip.GetInputStream(entry);
}
The custom data source
public class ZipDataSource : IStaticDataSource
{
private Stream _stream;
public ZipDataSource(Stream stream)
{
_stream = stream;
}
public Stream GetSource()
{
_stream.Position = 0;
return _stream;
}
ZipFile.Create(zipStream) is not just a convenient static accessor like anyone would think. If you're going to use that only use it for the very first time you're creating a zip. When opening up an existing zip you need to use var zip = new ZipFile(zipStream).
I've personally had many issues in the past with this library and would suggest that anyone looking for a good zip library to choose something other than icsharpziplib... The API just plain sucks.
I want to create a WCF service (working like windows service). This service will read a PDF file from a specific path, extract pages, create a new PDF file and return it to the caller.
How can I do this ? I use QuickPDF to process on PDF files, I can extract and create new PDF file. How can use this in a WCF service ?
Waiting your helps...
This is only sample code :
public Stream ExtractPdf(string PathOfOriginalPdfFile, int StartPage,int PageCount)
{
PDFLibrary qp = new PDFLibrary();
Stream Stream_ = null;
if (qp.UnlockKey(".................") == 0)
{
string fileName = #"..\..\Test Files\sample1.pdf";
string OutputFile = #"..\..\Test Files\sample1_extracted.pdf";
if (qp.Unlocked() == 1)
{
int docID = qp.LoadFromFile(fileName, "");
int extractPageSuccess = qp.ExtractPages(StartPage, PageCount);
if (extractPageSuccess == 0)
{
// error
}
else
{
qp.SaveToFile(OutputFile);
}
}
}
//
// Codes here
//
return Stream_;
}
I edited it :
public byte[] ExtractPdf(string PathOfOriginalPdfFile, int StartPage,int PageCount)
{
QuickPDFDLL0815.PDFLibrary qp = new QuickPDFDLL0815.PDFLibrary(#"C:\Program Files (x86)\Quick PDF Library\DLL\QuickPDFDLL0815.dll");
string fileName = #"..\..\Test Files\sample1.pdf";
byte[] binFile = null;
if (qp.UnlockKey("...................") == 0)
{
if (qp.Unlocked() == 1)
{
int docID = qp.LoadFromFile(fileName, "");
int extractPageSuccess = qp.ExtractPages(StartPage, PageCount);
if (extractPageSuccess == 0)
{
// error
}
else
{
binFile = qp.SaveToString();
}
}
}
return binFile;
}
You could send the file as a Stream, see How to: Enable Streaming, then on the client save off the file and have the shell execute it. The MSDN article includes a sample GetStream method as well as a whole section on Writing a custom stream.
If you would like fuller sample code the forum post Streamed file transfer using WCF starts with some, however, note that the author posted it there because they were encountering issues running it.
As to byte[] or stream see Uploading Image Blobs–Stream vs Byte Array and Stream vs Raw Bytes. The second states
Streams will perform better for large files since not all of it needs to be read into memory at one time