Approach to targetting HTTP Handler from Button Click - asp.net

Main purpose here is to target the handler to download a file that is being previewed.
There are two different conditions of the file, one where it is already saved in the database, then the following parameters to the handler through a query string
COIHandler.axd?Action=preview_saved&letterId=xxxx
or
one that hasn't been saved yet, in which i store it in the session and target the handler in the following way
COIHandler.axd?Action=preview_unsaved
then the handler will handle clearing the session after I'm done.
Any thoughts on how to make this occur. Still new to http handlers.
CLARIFICATION
I have a OnClientClick property in my sub classed version of the Button class which allows me to append javascript to it that will be executed client-side. That is where I want the targeting to occur.
I want the user stay on the same page when they click the download button as well.
I dont want to simply do a redirect in javascript that will target the handler and I would like to avoid a pop-up window if possible. Not really sure if that leaves any options

In Response to Yads comment, you can use a button click handler on your page to download the file without a need for a popup or separate HTTP Handler.
protected void btnDownload_OnClick(object sender, EventArgs args)
{
PDFContentData data = GeneratePDFData(); //parses strings from some source (as mentioned in comments)
WebFileUtil.InvokePDFDownload(Page.Context, data);
}
public static class WebFileUtil
{
public static void InvokePDFDownload(HttpContext context, PDFContentData data)
{
context.Response.Clear();
context.Response.ClearContent();
context.Response.ClearHeaders();
FileStore.generateDocument(data, context.Response.OutputStream);
context.Response.ContentType = "application/pdf";
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.AddHeader("Content-Disposition", String.Format("attachment;filename={0}_Documenth.pdf", DateTime.Now.ToShortDateString()));
context.Response.End();
}
}

Your handler would actually be .ashx. Other than that your approach seems fine. You can examine the context that is passed into the PrcoessRequest method.
public void ProcessRequest(HttpContext context)
{
switch(context.Request.QueryString["Action"].ToLower())
{
case "preview_saved":
//do stuff for saved
case "preview_unsaved":
//do stuff for unsaved
}
}
UPDATE If you want a central handler, then you'll either want to redirect the user at the end of the call in which case you'll also want to pass a returnUrl parameter in the query string. Then you can just do a context.Response.Redirect(context.Request.QueryString["returnUrl"]). Or if you want the page to retain its state, you're going to have to make an Ajax call to your handler.

First off thank you very much for all the possible solutions they were helpful in getting outside the box.
I figured out a unique solution that I thought I would share.
I place an invisible iframe in the html markup of my page.
then I set a property called OnClientClick in my server control Download Button (this allows me to render a parameter string to the onclick attribute of the html)
I set the property to a javascript method which embodies a recursive algorithm to navigate to the top parent frame of the page, once it reaches that point, I use a simply JQuery selector to look for the iframe I spoke of in step 1. (The reason for the recursion is to maintain support with Master Pages where you will have frames inside of frames).
Set the src attribute of the iframe to the target HTTP Handler. The applied behavior causes the iframe to load the requested source ... but in this case it is a handler, and since it was made all originally from direct user input (via the Download button click), you won't even have the issue of getting the Yellow Bar with IE7+
The handler serves the request and the file is served to the browser
Yay!

Related

Winform browser control "attachment" button

We have a winform app that has a browser control on it. Previously these files (always very small 10kb etc.) were stored at a unc location. We would generate some html and load the html into the browser. If we wanted to make one of these small files available we would include in the HTML an anchor tag () WHen the html was displayed in the browser control so would be the link. The user could click on the link and the file save as dialog would appear.
We are now storing these files in the db as varbinary and thus there is no longer a physical location for the anchor tag to point to. I have several thoughts but would like the members of SO who are way smarter than me to chime in.
Option 1 in my mind would be to have an image button, anchor tag, something in the html to click on. I would handle the "onclick" either in javascript or as a postback. This seems doable for my level of knowledge EXCEPT I do not know how to get the byte[] to translate into the save as dialog for the user....do I render it to disk first?
The other idea I had was to have a button that is NOT in the browser control. This button would be hidden / visible if the biz rules said to show a file. Clicking on the button would then generate the byte[] which is easily turned into a file and the save as shown dialog shown in the winform app.
So any thought or all together different suggestions welcome
TIA
JB
I understand that you are in control of the ASP.NET web page shown in the windows forms web browser control so you can edit that page and build it the way you want.
if that is true, behavior in hosted web browser or in normal IE session is the same and I would suggest to create a bunch of hyper links or buttons in the asp.net web form page each one which a specific ID, like the ID of the file to download. then you can create an handler or a button_click event handler where you get the byte[] of the file by the clicked button/link associated file Id, or from query string if you initiated an handler call, and then you start streaming down to the browser the file content, the browser will do all what is required for you.
for example, just as a starting point, a bit of code taken from here: http://social.msdn.microsoft.com/Forums/en-US/silverlightnet/thread/d6a5087f-43b1-4782-95f1-d1376130d2c8
shows you a possible way to do this from a page load, the trick is that the call to GetDocument gets the proper file content for you (in this case from the query string, imagine like if we are inside an handler processing method) and returns a class DocumentInfo which contains the bytes. you do nor need this DocumentInfo, you can just have a method which returns byte[] by File Id for example...
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
string queryString = this.Request.QueryString.ToString();
if (string.IsNullOrEmpty(queryString)) return;
DocumentInfo documentInfo = GetDocument(queryString);
if (!documentInfo.HasValue) return;
Response.ClearHeaders();
Response.ClearContent();
Response.AppendHeader("Content-Length", documentInfo.Value.Content.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment; filename=Test.doc");
Response.BinaryWrite(documentInfo.Value.Content);
Response.End();
}
}

ASP.NET How to raise load event on previous page with cross page postbacks

I'm working on a wizard-like set of page, and I'm relying on cross page postbacks to navigate between them.
I need to be able to trigger the Load event on the previous page in order to save the form data for the page.
I've been told that for situations of this sort all I had to do is access the PreviousPage property in the destination page and this would trigger the load event of the previous page but for some reason this doesn't seem to be working.
Is there anything else I can do to explicitly trigger the load event on the previouspage if the PreviousPage property is not null?
Thanks for your help,
Yong
Have you considered moving whatever persistence logic you're doing in the load of the Previous Page into a method on the page?
That way you can just hit:
if(PreviousPage != null)
PreviousPage.DoThatSavingThing();
Obviously you'd need to type it to get the specific methods you add unless you added those to all pages.
This sounds a little confusing to me, but if you are wanting access to data, it's best to save that data into something that you can easily get to, like the ASP.NET session cache. So instead of going back to a previously navigated page in order to get data, you will cache the data the first time you reach the first page, and then when the user navigates to the 2nd page, it will have access to that information.
To add - I tested using two methods of getting a "strongly-typed" previouspage.
Added a reference to the destination:
Added the PreviousPage directive on the destination:
When accessing the PreviousPage property in the destination, the Load event was fired on the
PreviousPageName page (source).
Example (assuming there is a public property named Test on the PreviousPageName (Source page)):
protected void Page_Load(object sender, EventArgs e)
{
if (PreviousPage != null)
{
//Using a reference, you have to cast:
PreviousPageName x = (PreviousPageName)PreviousPage;
string test = x.Test;
//Using the PreviousPage directive, you do not need to cast:
string test2 = PreviousPage.Test
}
}

Losing backward navigation in ASP.NET

I have an ASP.NET2.0 web page with a Submit button.
When the user clicks, I generate an XML file on the fly and return that as a result.
Here is the code:
protected void submitBtn_Click(object sender, EventArgs e)
{
string result = this.ProduceMyXmlResult();
this.Response.Clear();
this.Response.StatusCode = 200;
this.Response.ContentType = "application/xml";
this.Response.ContentEncoding = System.Text.Encoding.UTF8;
this.Response.Write(result);
this.Response.End();
}
The piece of code does exactly what I want. However, the browser does not recognize the XML file as a new page, so the BACK button does not take me back to my original page. Why and how can I overcome that?
The simplest way to do so, I think, would be to create a separate page that executes this code on Page_Load(), and redirect to it when the button is pressed.
The reason you have no backward navigation is because the browser is unaware the page has changed. Since the Submit button is preforming a postback, and you are returning XML data as the response to that postback, it appears to the browser as though this is just some transformation of the current page (just as though you'd, say, changed the text of a Label control).
The "correct" way to accomplish this would be with some type of HTTP handler, but I haven't the experience to suggest the proper way to do so and you already have working C# code-behind for this method.

ASP.NET Save HTML Sent to Browser

I need to save the full and exact HTML sent to the browser for some transactions (for legal tracking purposes.) I suspect I am not sure if there is a suitable hook to do this. Does anyone know? (BTW, I am aware of the need to also save associated pages like style sheets and images.)
You can create an http module and have the output stream saved somewhere.
You should hook to PreSendRequestContent event...:
This event is raised just before ASP.NET sends the response contents to the client. This event allows us to change the contents before it gets delivered to the client. We can use this event to add the contents, which are common in all pages, to the page output. For example, a common menu, header or footer.
You could attach to the PreSendRequestContent. This event is raised right before the content is sent and gives you a chance to modify it, or in your case, save it.
P&P article on interception pattern
You could implement a response filter. Here is a nice sample that processes the HTML produced by ASP.NET. In addition to the HTML being sent to the client you should be able to also write the HTML to a database or other suitable storage.
Here is an alternate and IMO much easier way to hook the filter into your application:
in Global.asax, place the following code in the Application_BeginRequest handler:
void Application_BeginRequest(object sender, EventArgs e)
{
Response.Filter = new HtmlSavingFilter(Response.Filter);
}
I suppose you only want to save the rendered html for certain pages. If so, I have been using the following approach in one of my applications that stores the rendered html for caching purpose somewhere on the disk. This method simply overrides the render event of the page.
protected override void Render(HtmlTextWriter writer)
{
using (HtmlTextWriter htmlwriter = new HtmlTextWriter(new System.IO.StringWriter()))
{
base.Render(htmlwriter);
string html = htmlwriter.InnerWriter.ToString();
using (FileStream outputStream = new FileStream(#"C:\\temp.html", FileMode.OpenOrCreate))
{
outputStream.Write(html, 0, html.Length);
outputStream.Close();
}
writer.Write(html);
}
}
Really works well for me.
There are also hardware devices made specifically for this purpose. We've used one called "PageVault".

Modifying the HTML of a page before it is sent to the client

I need to catch the HTML of a ASP.NET just before it is being sent to the client in order to do last minute string manipulations on it, and then send the modified version to the client.
e.g.
The Page is loaded
Every control has been rendered correctly
The Full html of the page is ready to be transferred back to the client
Is there a way to that in ASP.NET?
You can override the Render method of your page. Then call the base implementation and supply your HtmlTextWriter object. Here is an example
protected override void Render(HtmlTextWriter writer)
{
StringWriter output = new StringWriter();
base.Render(new HtmlTextWriter(output));
//This is the rendered HTML of your page. Feel free to manipulate it.
string outputAsString = output.ToString();
writer.Write(outputAsString);
}
You can use a HTTPModule to change the html. Here is a sample.
Using the answer of Atanas Korchev for some days, I discovered that I get JavaScript errors similar to:
"The message received from the server could not be parsed"
When using this in conjunction with an ASP.NET Ajax UpdatePanel control. The reason is described in this blog post.
Basically the UpdatePanel seems to be critical about the exact length of the rendered string being constant. I.e. if you change the string and keep the length, it succeeds, if you change the text so that the string length changes, the above JavaScript error occurs.
My not-perfect-but-working solution was to assume the UpdatePanel always does a POST and filter that away:
protected override void Render(HtmlTextWriter writer)
{
if (IsPostBack || IsCallback)
{
base.Render(writer);
}
else
{
using (var output = new StringWriter())
{
base.Render(new HtmlTextWriter(output));
var outputAsString = output.ToString();
outputAsString = doSomeManipulation(outputAsString);
writer.Write(outputAsString);
}
}
}
This works in my scenario but has some drawbacks that may not work for your scenario:
Upon postbacks, no strings are changed.
The string that the user sees therefore is the unmanipulated one
The UpdatePanel may fire for NON-postbacks, too.
Still, I hope this helps others who discover a similar issue. Also, see this article discussing UpdatePanel and Page.Render in more details.
Take a look at the sequence of events in the ASP.NET page's lifecycle. Here's one page that lists the events. It's possible you could find an event to handle that's late enough in the page's lifecycle to make your changes, but still get those changes rendered.
If not, you could always write an HttpModule that processes the HTTP response after the page itself has finished rendering.
Obviously it will be much more efficient if you can coax the desired markup out of ASP.Net in the first place.
With that in mind, have you considered using Control Adapters? They will allow you to over-ride how each of your controls render in the first place, rather than having to modify the string later.
I don't think there is a specific event from the page that you can hook into; here is the ASP.Net lifecycle: http://msdn.microsoft.com/en-us/library/ms178472.aspx
You may want to consider hooking into the prerender event to 'adjust' the values of the controls, or perform some client side edits/callbacks.

Resources