OpenXML file download without temporary file - c#

Is there a way of providing a download in an ASP.Net Page for a freshly generated OpenXML (docx) file without saving it in a temporary folder?
On MSDN I only found a tutorial for using a temp file but I thought about using the WordprocessingDocument.MainDocumentPart.GetStream() and directly writing the stream out.

When you create the document use a MemoryStream as the backing store. Then create and close the document normally and serve the contents of the memory stream to the client.
using(var stream = new MemoryStream())
{
using(var doc = WordprocessingDocument.Create(stream, WordprocessingDocumentType.Document, true)
{
...
}
stream.Position = 0;
stream.CopyTo(Response.OutputStream);
}
Do not just grab the MainDocumentPart because, as the name implies, this is just one part of the document package, not everything.
You'll also need to set response headers for content type and disposition.

Stream.CopyTo() in .NET 4.0 might help you out here.
WordprocessingDocument.MainDocumentPart.GetStream().CopyTo(Response.OutputStream);
You'll still need to set the headers for MIME type, content-disposition and so on.

Related

Content-type of Word file from Amazon S3

I need to get a content of the Microsoft Word (.docx) file from Amazon S3. I am able to get the object, but the result is not exactly what I want, because it looks like Word file opened in Notepad. I tried to read .txt file and it works perfectly. I think the problem is a content-type.
I would like to ask two question:
Is it possible to get the content of the document as is in file #Amazon and how to modify my code do achive that?
Is it possible to get the content with formatting (colors, bold text etc.)? If it is, I would aprreciate some clues.
My Code:
public static string ReadObjectData(string keyName)
{
string responseBody = "";
//using (IAmazonS3 client = new AmazonS3Client(RegionEndpoint.USEast1))
using (IAmazonS3 client = new Amazon.S3.AmazonS3Client("key", "secretKey", Amazon.RegionEndpoint.EUCentral1))
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = "bucketName",
Key = keyName
};
using (GetObjectResponse response = client.GetObject(request))
using (Stream responseStream = response.ResponseStream)
using (StreamReader reader = new StreamReader(responseStream))
{
responseBody = reader.ReadToEnd();
}
}
return responseBody;
}
The correct Content-Type for a .docx file is application/vnd.openxmlformats-officedocument.wordprocessingml.document.
The Content-type being set incorrectly may cause a web browser to render the document incorrectly, but that isn't likely the problem, here. Setting it correctly will have no impact on the bytes that are actually contained in responseBody if you are trying to read it from code.
You need a library that understands the internals of files in the .docx format.
I understand your question regarding getting the object with content type. I think Michael's answer has some information to resolve the problem.
I just like to add some additional information while storing the objects in S3 bucket. The content type can be set in the meta data field when the objects are added to bucket.
If you are storing the objects and retrieving it later, please add the content type (Content-Type) in meta data. So that you can get the content type of the object when you read it.
This is the better approach if you adding and retrieving the object later.
doc application/msword
docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
If you are reading the object added by someone else, you can request then to add the content type information (or) you need to derive it as mentioned in Michael's answer.

How to create Excel file using OpenXML without creating a local file?

Is it possible to create and edit an excel document using OpenXML SDK without creating a local file?
As per the documentation the Create method demands for a filepath, which creates a local copy of the file.
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook);
I'm referring the MSDN article here:
https://msdn.microsoft.com/en-us/library/office/ff478153.aspx
My requirement is to create the file, and it should be downloaded by the browser on clicking a button.
Any suggestion?
You could use the overload of SpreadsheetDocument.Create that takes a Stream and pass it a MemoryStream:
MemoryStream memoryStream = new MemoryStream();
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(memoryStream, SpreadsheetDocumentType.Workbook);
//add the excel contents...
//reset the position to the start of the stream
memoryStream.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
Note that as per this StackOverflow question you don't need to dispose the Stream as it will be done for you by the FileStreamResult class.
Adding another answer as I spent way too much time searching for this: Another way to save a SpreadsheetDocument to a stream is by calling SpreadsheetDocument.Clone(Stream s)
It has the benefit of letting you save to a stream even if you created the document from a file or a stream you don't want to save to.

How could I make WebBrowser.Navigate analog for bytes array, instead of URL?

I planning to load PDF files into it, but I can't save those to disk. PDFs exist only as byte arrays in my program.
For text data I can use something like this:
webBrowser1.DocumentText = "<html>page content</html>";
But PDF is not text, so I need some other way, but can't find any.
I tried this:
byte[] file_content = File.ReadAllBytes("C:\\Users\\Metafalica\\Documents\\DatabaseSQLLanguageRzheutskaya.pdf");
MemoryStream ms = new MemoryStream(file_content);
ms.Flush();
ms.Position = 0;
webBrowser1.DocumentStream = ms;
But getting this:
It's not possible to load and render a PDF via webBrowser.DocumentStream. What happens behind the scene is that an instance of MSHTML Document Object gets created and initialized with the supplied stream. You could possibly load an image (which MIME type is recognized by MSHTML), but not a PDF. On the other hand, when webBrowser.Navigate is used, an instance of Adobe Acrobat Reader PDF Document gets created, rather than MSHTML.

Add zipping capability to existing StreamWriter code

The program I am working on is currently using a StreamWriter to create one or many text files in a target folder. Off StreamWriter class, I am using WriteLine and its IDisposable interface via Using directive (for implicit .Close).
I need to add an option to create one or many text files in a zip archive inside a target folder. I was going to change existing code to use streams, so it's possible to use a ZIP file as an output (planning to use DotNetZip).
I was thinking to create some GetOutputStream function and feed that into the currently existing method. This function would determine whether archive option is set, and either create plain files, or archive them. Problem is that MemoryStream, which looks like a good buffer class to use with DotNetZip, does not intersect with StreamWriter in the inheritance hierarchy.
Looks like my only option is to create some IWriteLine interface, which would implement WriteLine and IDisposable. Then branch two new child classes from StreamWriter and MemoryStream, and implement IWriteLine in them.
Is there a better solution?
The current code conceptually looks like this:
Using sw As StreamWriter = File.CreateText(fullPath)
sw.WriteLine(header)
sw.WriteLine(signature)
While dr.Read 'dr=DataReader
Dim record As String = GetDataRecord(dr)
sw.WriteLine(record)
End While
End Using
For code samples, either VB.NET or C# is fine, although this is more of a conceptual question.
EDIT: Cannot use .NET 4.5's System.IO.Compression.ZipArchive, have to stick with .NET 4.0. We still need to support clients running on Windows 2003.
Use the StreamWriter(Stream) constructor to have it write to a MemoryStream. Set the Position back to 0 so you can then save the written text to the archive with ZipFile.Save(Stream). Check the ZipIntoMemory helper method in the project's sample code for guidance.
First of all, with .NET 4.5 System.IO.Compression.ZipArchive class (see http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive.aspx) you no longer need DotNetZip at least for common zipping tasks.
It could look like this:
string filePath = "...";
//Create file.
using (FileStream fileStream = File.Create(filePath))
{
//Create archive infrastructure.
using (ZipArchive archive = new ZipArchive(fileStream, ZipArchiveMode.Create, true, Encoding.UTF8))
{
SqlDataReader sqlReader = null;
//Reading each row into a separate text file in the archive.
while(sqlReader.Read())
{
string record = sqlReader.GetString(0);
//Archive entry is a file inside archive.
ZipArchiveEntry entry = archive.CreateEntry("...", CompressionLevel.Optimal);
//Get stream to write the archive item body.
using (Stream entryStream = entry.Open())
{
//All you need here is to write data into archive item stream.
byte[] recordData = Encoding.Unicode.GetBytes(record);
MemoryStream recordStream = new MemoryStream(recordData);
recordStream.CopyTo(entryStream);
//Flush the archive item to avoid data loss on dispose.
entryStream.Flush();
}
}
}
}

Creating report with Aspose.Word without losing formatting

I am using Aspose.Words to create reports from a template file (.docx filetype).
After using Aspose.Words to modify the template file and saving it into a new file, the formatting of the template file were lost (such as bold text, comments, etc).
I have tried:
Aspose.Words.Document doc = new Document(inputStream);
var outputStream = new MemoryStream();
doc.Save(outputStream, SaveFormat.docx);
What I did not expect is that outputStream is much less bytes than inputStream although I have yet to make any modification on doc. It may the reason why the report file lose their formatting.
What should I try now?
Ok, the problem is because the current version of Aspose.Words I'm using does not support docx filetype. But it still can read text of a .docx file, and only text(without any associated formatting).

Categories