ASP.NET: BOM in Server.Execute() - asp.net

I'm using this to write to the Response stream:
using (var writer = new StringWriter())
{
context.Server.Execute(virtualpath, writer);
string s = writer.ToString().Replace(...);
context.Response.Write(s);
}
But I'm getting a byte order mark in the response. Am I screwing up the encoding? How do I NOT return the BOM?
EDIT: SOrry Rubens, my first example was incorrect.

Try this:
context.Server.Execute(virtualpath, context.Response.Output);
EDIT: So, try this to force your encoding:
MemoryStream ms = new MemoryStream();
StreamWriter writer = new StreamWriter(ms);
context.Server.Execute(virtualpath, writer);
context.Response.Write(Encoding.UTF8.GetString(ms.ToArray()).Replace(...));

Server.Execute() returns an encoded stream, but StringWriter() is intended to store simple .NET strings (which are 16-bit Unicode and don't have a BOM) and doesn't know how to decode the incoming bytes. So, the BOM in the response becomes literal characters in your string.
Try writing to a MemoryStream() instead, then decode that back into a string using whichever encoding (UTF-8 or whatever) that the Server.Execute() is passing back. Then you can parse it and write it back to your Response.

Related

Itextsharp open new tab ISSUE

I need to open pdf in the new tab, it works and file show perfect, but if I open File with notepadd++, after EOF there are some NULL char (see pics).
It happen only I open it in new tab and use memorystream, the string after EOF create some problem the parser of client, whats wrong?.
This is code:
Dim mswithPage As New MemoryStream()
Dim SessValue As String = Request.QueryString("s")
Dim NOrder As String = Request.QueryString("odv")
mswithPage = CType(Session(SessValue), MemoryStream)
Response.Clear()
Response.ContentType = "Application/pdf"
Response.AddHeader("content-disposition", "inline;filename=" & NOrder & ".pdf")
Response.OutputStream.Write(mswithPage.GetBuffer(), 0, mswithPage.GetBuffer().Length)
Response.OutputStream.Flush()
Response.OutputStream.Close()
Response.End()
The issue
An issue is in this line:
Response.OutputStream.Write(mswithPage.GetBuffer(), 0, mswithPage.GetBuffer().Length)
Even more precisely its final argument mswithPage.GetBuffer().Length - you should use the number of actually used bytes in the buffer but you use the size of the complete buffer.
A solution
Thus, use mswithPage.Length instead:
Response.OutputStream.Write(mswithPage.GetBuffer(), 0, mswithPage.Length)
... and if the MemoryStream already is closed
If the MemoryStream already is closed, the solution above doesn't work anymore because its Length property can only be used on open streams.
What does work on closed streams, though, is the ToArray method! Thus, you can instead use
Response.OutputStream.Write(mswithPage.ToArray())
(Actually it is funny that ToArray works on closed streams but Length does not. After all, ToArray essentially returns a copy of the first Length many bytes of the internal buffer...)

Getting a corrupted XLSX file when writing it to Response.OutputStream

In ASP.Net, I'm using NPOI to write save to an Excel doc and I've just moved to version 2+. It worked fine writing to xls but switching to xlsx is a little more challenging. My new and improved code is adding lots of NUL characters to the output file.
The result is that Excel complains that there is "a problem with some content" and do I want them to try to recover?
Here is a pic of the xlsx file that was created from my Hex editor:
BadXlsxHexImage Those 00s go on for several pages. I literally deleted those in the editor until the file opened without an error.
Why does this code add so many NULs to this file??
using (var exportData = new MemoryStream())
{
workbook.Write(exportData);
byte[] buf = exportData.GetBuffer();
string saveAsFileName = sFileName + ".xlsx";
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename={0}; size={1}", saveAsFileName, buf.Length.ToString()));
Response.Clear();
Response.OutputStream.Write(buf, 0, buf.Length);
exportData.Close();
Response.BufferOutput = true;
Response.Flush();
Response.Close();
}
(I've already tried BinaryWrite in place of OutputStream.Write, Response.End in place of Response.Close, and setting Content-Length with the length of the buffer. Also, none of this was an issue writing to xls.)
The reason you are getting a bunch of null bytes is because you are using GetBuffer on the MemoryStream. This will return the entire allocated internal buffer array, which will include unused bytes that are beyond the end of the data if the buffer is not completely full. If you want to get just the data in the buffer (which you definitely do), then you should use ToArray instead.
That being said, why are you writing to a MemoryStream at all? You already have a stream to write to: the OutputStream. Just write the workbook directly to that.
Try it like this:
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", saveAsFileName));
workbook.Write(Response.OutputStream);
Response.Flush();
Response.Close();

Xdocument.Load(XMLReader.Read()) Is giving me erros

I am trying to load a document see the code below
try
{
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
XmlReader responseReader = XmlReader.Create(response.GetResponseStream());
XDocument docs = XDocument.Load(responseReader.Read());
The above line is telling me xdocument.Load has some invalid arguments.
//XDocument docs = XDocument.Load(response.GetResponseStream());
This line is not loading anything Docs is empty
XDocument docs = XDocument.Load(responseReader);
This line is not giving any overload errors but returning nothing.
List<string> books = docs.Descendants("Test")....."Remaining QQuery"
Change
XDocument docs = XDocument.Load(responseReader.Read());
to
XDocument docs = XDocument.Load(responseReader);
The method for XDocument will accept an XmlReader which is what responseReader is, however you are calling the .Read() method on which only returns a boolean which is why you are getting that error.
Firstly, you almost had it without the XmlReader; you can't load the response straight into the XDocument, but, most of the time you can do:
XDocument docs = XDocument.Load(new StreamReader(response.GetResponseStream()));
Then check docs.Nodes.Count.
If docs is still empty, it's time to look at the response itself. Look at the response.ContentType - what is it?
Assuming the response isn't too large, look at it! You can do:
StreamReader reader = new StreamReader(response.GetResponseSteam());
string text = reader.ReadToEnd();
You can dump that string anywhere. Alternatively, if it is very big, you can save the response to disk, using either a FileStream with your Response, or, more simply WebClient.DownloadFile(url, path_to_save)
Either should be good enough to get you one step closer.

Need Help in converting Classic ASP Code to ASP.NET code

Set xml = Server.CreateObject("Microsoft.XMLHTTP")
xml.Open "GET", "http://www.indexguy.com/request_server.cfm?member_id=15893&id="+request.querystring("id")+"&"+request.querystring, False
xml.Send
How can I build the querystring parameter to a string object in C#/VB.NET
"member_id=15893&id="+request.querystring("id")+"&"+request.querystring"
If you are looking to build a querystring, String.Format("{0}", arg) might be a cleaner method to construct it.
For ASP.NET, you're going to want to replace the Server.CreateObject("Microsoft.XMLHTTP") with HttpWebRequest.
As for building the query string, that's still identical. You can still retrieve query string parameters by indexing into Request.QueryString. If you're using C# you can keep the + for string concatenation but might be more acceptable to use & in VB.
In ASP.NET the Page class exposes a Request property which provides access to a QueryString property - this is a NameValueCollection that lets you get values out in much the same way as in your existing example, by specifying keys:
var id = Page.Request.QueryString("id");
var newQuery = string.Format("?member_id=15893&id={0}&", id);
The above can easily be expanded to build more into your required query string.
As for the request you're initiating, that can be achieved using a WebRequest instance; to alter the sample from MSDN only slightly, here is an example:
WebRequest request = WebRequest.Create(yourUrl + newQuery);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Response.Write(response.StatusDescription);
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader (dataStream);
string responseFromServer = reader.ReadToEnd();
Response.Write(responseFromServer);
reader.Close();
dataStream.Close();
response.Close();

determine content-length of html string

I am exporting a HTML table to excel by sending the data as a HTML Table string and setting the content headers:
Dim html as String = "<table><tr><td>example<td></tr></table>"
context.Response.Clear()
context.Response.AddHeader("Content-Disposition", "attachment; filename=" & "exceldata-" & Now.ToString("yyyyMMddHHmmss") & ".xls")
'context.Response.AddHeader("Content-Length", ????)
context.Response.ContentType = "application/octet-stream"
context.Response.Write(response)
context.Response.End()
Is there a simple way of setting the content-length based on the size of the html string? Or should I just leave it blank anyway...would be nice to have the content-length ideally...
I am returning this using a GenericHandler in asp.net
Replace with the encoding of your choice, probably UTF8. Sorry for the C#:
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] bytes = encoding.GetBytes(html);
int length = bytes.Length;
Source: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.contentlength.aspx
This seems too easy, but is it not just equal to html.Length?
I haven't used ASP.NET, but I guess that the Length() method returns the length of the string in chars, not bytes, so it won't work if your server uses UTF-8 or Unicode for serving the pages.
As noted in another answer, just let the server fill it for you. If you think about it, you don't have to add it when you generate HTML pages from ASP since the web server would generate it based in the response from the ASP module.

Resources