Retrieving HTML from ASP.NET page on postback - asp.net

I've found a few posts about retrieving HTML from an ASPX page, mostly by overriding the render method, using a WebClient, or creating an HttpWebRequest. All these methods return the HTML of the page as it's loaded, but I was hoping to actually retrieve the HTML after the user has entered information.
The purpose behind this is that I work in IT, and I'm attempting to build a logging library that has an overload that essentially does a "screen-scrape" on the page just as the user encounters an exception, that way I can log the exception, and create an HTML file in a sub-directory of the logging directory that shows the page exactly as the user had it before clicking "submit" or having some other random error, and add an "ID" to the error that's logged telling whoever is fixing the issue which page to look at.
I hope I've provided enough information, because I really have no idea where to start.
Also, We'd like to do this through our own library, because our logging library is included in our common library, and many of our common library functions use our logging class.

Hmmm...
If you want to see what the user sees after they've been using the page, you're most likely going to have to do some fancy client-side scripting.
A naive approach:
When the clicks the submit button, fire a JavaScript event that encodes the DOM and either passes it as a form variable to the server, or executes a separate AJAX request with the encoded data as a parameter. ("Encode" in this case may be as simple as grabbing document.innerHtml, but I haven't checked.)
This potentially introduces a lot of overhead to every form submission, so I'd keep it out of production code.
I'm not sure why you need the rendered HTML as part of your exception log - I've never found it necessary for server-side debugging.

You getting HTML code from a website. You can use code like this.
string urlAddress = "http://www.jobdoor.in";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlAddress);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream receiveStream = response.GetResponseStream();
StreamReader readStream = null;
if (response.CharacterSet == null)
readStream = new StreamReader(receiveStream);
else
readStream = new StreamReader(receiveStream, Encoding.GetEncoding(response.CharacterSet));
string data = readStream.ReadToEnd();
response.Close();
readStream.Close();
}

Related

Session and XMLHTTP

I have two asp pages on the same server. The first one generates XML dynamically using querystring informations and session information. The second one reads the first one using an XMLHTTP object and do things using the XML datas.
However, my problem is that the XMLHTTP request is done server-side. Thus, the session variables of the client are not accessible when the xml should be generated.
How can I do so that the page that generates the XML receives the session variables ?
Thanks.
There are many problems with what you are trying to do, not least is that it can lead a busy server to lock up entirely.
Here is the another approach.
Add a third page to your solution. This page contains simply a function which returns an XML DOMDocument. This function contains all the logic from your original xml generating page but builds the XML into the DOM (which you were probably doing all ready right?).
Now your original page simply includes this new function page, calls the function and sends the DOM to the response:
<!-- #include file="xmlFunction.asp" -->
<%
Response.ContentType = "text/xml"
Response.CharSet = "UTF-8"
GenerateXml().Save Response
%>
Your client page can now look this
<!-- #include file="xmlFunction.asp" -->
<%
. . .
Dim dom: Set dom = GenerateXml()
''# Code that uses the XML in the dom.
%>
No additional "Request to self" is needed hence no potential lock up. Since code in the xmlFunction.asp is running as part of the original request the appropriate Session object is accessible.

How do I return multiple "documents" from a web forms application?

We have a webforms application that generates parametric documents. The user supplies some information, clicks a button, and our web service generates Word documents.
The service works for one document at a time but not batches. We want to add the ability to process more than one document. We now have the code below, where contactIdsForLetters is a List<int>.
foreach (int contactId in contactIdsForLetters)
{
string parameters = string.Format("ContactID~{0}", contactId);
string defaultFilename = Reporting.Utilities.CreateDefaultFileName(outputformat);
byte[] bytes = Reporting.Reports.CreateReport(selectedReportId, parameters, outputformat, out serviceCallWasSuccessful);
if (!serviceCallWasSuccessful || bytes == null)
{
Reporting.Reports.LogReportActivity(selectedReportId, string.Empty, parameters, userLogin, false);
return;
}
Reporting.Reports.LogReportActivity(selectedReportId, string.Empty, parameters, userLogin, true);
Reporting.Utilities.SendResponse(defaultFilename, bytes);
}
When running the above code, only one document is ever returned. One document is processed (the For-Each never gets to the second item in contactIdsForLetters), a dialog pops up asking to open or save the file, and after clicking open, Word opens with the document. Everything is happening like it should but we can't get the For-Each to process the second and subsequent documents.
The users want a seperate Word session for each document returned. Subsequent documents will need to open in their own Word session.
How do I loop through a List<int>, send each int to a service one-at-a-time, and open a Word session for each returned document?
Here is SendResponse() ...
public static void SendResponse(string defaultFilename, byte[] bytes)
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.Buffer = false;
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.AppendHeader("Content-Disposition", string.Format("attachment; filename={0}", defaultFilename));
HttpContext.Current.Response.AppendHeader("Content-Length", bytes.Length.ToString());
HttpContext.Current.Response.BinaryWrite(bytes);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}
There should be no problem sending a List<int> to the service and having the service return List<byte[]>.
I don't know what you mean by "open a Word session". I hope you're not trying to call Word from an ASP.NET application. That's not supported, is unreliable, and doesn't work very well.
ASP.NET runs on top HTTP.
HTTP is based on a per request basis.
Each request returns a response if the browser is able to reach the server.
This response contains a stream (we can call it File in your case).
After the server flushes that stream (1st file) the request connection to the server is closed and the request life cycle ends, closing any threads related to that request.
This is why you never get to the second document.
You are going to have to deliver the documents in a compressed container like a zip file so all the documents go in a single stream. First get all the documents, package them and send the response to the client.
Hope this helps.
UPDATE: Also you might want to look at using AJAX to generate a javascript call to the server returning different links to pull the different documents. It would be like clicking on different invisible links that open different documents after the user clicks a single button or link. Using this approach is really easy to achieve what you want. You can trigger the click event for all the invisible links with javascript.

asp.net dynamic HTML form

I want to create an html page inside a asp.net page using c# and then request that html page. The flow is, I'll be creating a request that will give me a response with some values. Those values will be stored in hidden fields in the html page I'm creating on the fly and then requesting. I figure it would be something like below but I'm not sure if it would work, I've also received some "Thread Aborting" errors. So, does anyone know the proper way to do this or at least direct me to a nice article or something?
StringBuilder builder = new StringBuilder();
builder.Append("<html><head></head>");
builder.Append("<body onload=\"document.aButton.submit();\">");
builder.Append("<input type=\"hidden\" name=\"something\" value=\"" + aValue + "\">");
HttpContext.Current...Response.Write(builder.ToString());
... end response
This is a very common request and is almost never a good idea. What are you trying to do?
That said: you write out a file with a temporary name and redirect to that file. Later you have to figure out when it's safe to delete the file.
Edit That method points out one of the problems: you have to do your own garbage collection, deciding how long files must be kept around and deleting them appropriately.

Server.Transferrequest() and getting the current URL

Say in my 'Page_init()' of "a.aspx" i just have 'server.transferrequest("b.aspx").
This works great, displays the content for "b.aspx" and the browserurl still stays at "a.aspx".
Happy days.
However does anyone know how to see this url from my "b.aspx" (the resulting page)?.
The usual request.rawurl and request.url.absoluteuri both return the current page as "b.aspx".
Server.TransferRequest performs an asynchronous execution of the specified URL. This means that your client has no clue of was is going on at the server so from your client perspective it's the same page.
If you need to change the actual page (which is the most common) then use Response.Redirect.
Maybe before you do the transfer you could save the information you need somewhere, then retrieve it when it's needed again.
You can use PreviousPage to get source page that makes server transfer :
string previousPagesUrl = PreviousPage.Request.RawUrl;
EDIT : #maxp, as an answer to your comment, PreviousPage only works for Server.Transfer and cross page postback.
You'll get null for PreviousPage if :
the source page redirects to the destination page.
a link at source page forwards the page to destination page.
NameValueCollection headers = new NameValueCollection();
headers["RawUrl"] = HttpContext.Current.Request.RawUrl;
Server.TransferRequest("b.aspx", true, null, headers);
And then use Headers["RawUrl"] in b.aspx.
Have you tried this method:
public void Transfer(string path, bool preserveForm )
http://msdn.microsoft.com/en-us/library/caxa892w.aspx
I currently got in the same problem, and I found out that Server object has this parameter on transfer method that gives you the posibility to preserve the original request form or not.

Process raw HTTP request content

I am doing an e-commerce solution in ASP.NET which uses PayPal's Website Payments Standard service. Together with that I use a service they offer (Payment Data Transfer) that sends you back order information after a user has completed a payment. The final thing I need to do is to parse the POST request from them and persist the info in it. The HTTP request's content is in this form :
SUCCESS
first_name=Jane+Doe
last_name=Smith
payment_status=Completed
payer_email=janedoesmith%40hotmail.com
payment_gross=3.99
mc_currency=USD
custom=For+the+purchase+of+the+rare+book+Green+Eggs+%26+Ham
Basically I want to parse this information and do something meaningful, like send it through e-mail or save it in DB. My question is what is the right approach to do parsing raw HTTP data in ASP.NET, not how the parsing itself is done.
Something like this placed in your onload event.
if (Request.RequestType == "POST")
{
using (StreamReader sr = new StreamReader(Request.InputStream))
{
if (sr.ReadLine() == "SUCCESS")
{
/* Do your parsing here */
}
}
}
Mind you that they might want some special sort of response to (ie; not your full webpage), so you might do something like this after you're done parsing.
Response.Clear();
Response.ContentType = "text/plain";
Response.Write("Thanks!");
Response.End();
Update: this should be done in a Generic Handler (.ashx) file in order to avoid a great deal of overhead from the page model. Check out this article for more information about .ashx files
Use an IHttpHandler and avoid the Page model overhead (which you don't need), but use Request.Form to get the values so you don't have to parse name value pairs yourself. Just pretend you're in PHP or Classic ASP (or ASP.NET MVC, for that matter). ;)
I'd strongly recommend saving each request to some file.
This way, you can always go back to the actual contents of it later. You can thank me later, when you find that hostile-endian, koi-8 encoded, [...], whatever it was that stumped your parser...
Well if the incoming data is in a standard form encoded POST format, then using the Request.Form array will give you all the data in a nice to handle manner.
If not then I can't see any way other than using Request.InputStream.
If I'm reading your question right, I think you're looking for the InputStream property on the Request object. Keep in mind that this is a firehose stream, so you can't reset it.

Resources