response.redirect to a new browser tab - response.redirect

There are several discussions on this topic (the closest one might be at Redirecting new tab on button click.(Response.Redirect) in asp.net C#), but none fit my need. Here is my situation:
The code
<asp:ImageButton ID="SearchButton"
runat="server"
OnClick="SearchButton_Click" OnClientClick="target='_blank';"/>
allows me to handle the event in the "code behind" (to process the URL for this redirection) and if this markup is in a "regular" .aspx page and the event handler SearchButton_Click in the code behind all is fine.
My situation differs from this in that this code resides in an .ascx (User Control) element, which is dynamically loaded on the "top level" page. This same code results with the current page being replaced with this "search page" and cannot even use the browser's Back button to return to the original context.
Please note that I would prefer to handle this in C# as
protected void SearchButton_Click(object sender, EventArgs e)
{
string what = queryText.Text;
Response.Redirect(baseUrl + what);
}
Every advice appreciated.

Your question is a bit involved, I'll explain some backstory:
Tabs and Windows, and why you shouldn't make any assumptions or demands of the browser
Traditionally hyperlinks (e.g. <a href="foo">) opened links in the same window viewport as the originating document. This is convention and is what users expect when they click on a link. Unless you know exactly what the user expects you should never cause a link to open up in a new window, tab, or in-document iframe popup or Ajax dialog.
Prior to the advent of tabbed browsers, hyperlinks with target="_blank" would cause them to open in new windows. In recent years, tabbed browsers prevent taskbar spam by opening them in new tabs - but this is a user preference. Browser tabs are not exposed to the browser through any public API, so your application will never know if a target="_blank" opens in a new window, a new tab, or even the same window viewport (unless you monitor window events in client-script).
I'm of the opinion that applications should never surprise the user, and that the user will always expect a link to open something in the same window.
When XHTML1.x was released, they removed the target attribute entirely because it was originally intended for frames (which were also removed in XHTML), because the committee felt that the _blank feature was being abused, and because XHTML can be rendered on a variety of devices that might not support multiple windows (think: 2005-era featurephones with terrible web browsers).
...unfortunately they brought it back in HTML5, oh well. I guess it does have some legitimate uses, but anyway.
ASP.NET Web Forms Events (e.g. _Click)
(This is why I ditched Web Forms for MVC, I strongly suggest you do the same).
ASP.NET Web Forms emulates WinForms by wrapping the entire page in a <form> element, then adding client-script to all of the control elements, such as <asp:Hyperlink> and <asp:Button> which causes the entire <form> to submit a POST back to the server, which re-creates the form and, during processing, raises these events. This is a particularly ingenious, if misguided, design. Fortunately it has been made obsolete by MVC, but I digress.
...it means that when you have <asp:Hyperlink> with a _Click handler in the server code it means that you're getting <a onclick="__doPostback()"> instead of <a href="URL to redirect to" />, so it provides a very poor user-experience, makes things brittle (as data not within the <form> element is not saved), and means you can run into problems like these where it's unclear (from a client-side perspective) where logic is being carried out: logically a link should be executed by the client, not the server.
Response.Redirect
Response.Redirect is a shortcut of sending a HTTP 3xx redirect to the client and ending further processing of the page. It sends this redirection back instead of the complete page response. A HTTP redirection can only tell the browser to follow it to the new location, there are no other options it can specify.
Conclusion
Piece these things together and you see that there is no way <asp:Hyperlink onclick="delegate() { Response.Redirect("someUrl") }" /> can cause someUrl to be loaded in a new browser tab.
I suggest that instead you use straightforward <a href="someUrl" /> without using any server-side logic. I can't see why you even need to at all in this case.

If you think out of the box, there is always a way to solve this.
Look at this SO post. response-redirect-to-new-window. I went with the Extention Method way it it works. Yes, if they disable javascript, it does not, but who does that? Not your normal person and they are likely used to issues with not enabling javascript.

Or, you could do this:
Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim url As String = "Page2.aspx"
Dim sb As New StringBuilder()
sb.Append("<script type = 'text/javascript'>")
sb.Append("window.open('")
sb.Append(url)
sb.Append("');")
sb.Append("</script>")
ClientScript.RegisterStartupScript(Me.GetType(), _
"script", sb.ToString())
End Sub

Related

SP2010 - httpcontext.response.write() not working for LinkButton's onClick event

probably a simple oversight I've missed (though I vaguely recall some obscure blogpost about the inner workings of Response.Write not working as expected in some situations but I don't remember if this is one of them):
The situation is, I have a Link Button on a control running in SP2010, and if I don't use HttpContext.Response.Write(), everything works as expected (ie I can change the .Text value for a Label). However, if I call Context.Response.Write(), while I can debug and step through the code, nothing seems to happen any more (nothing is written back and changes to other controls do not appear). It's being run on an application page in _layouts, appearing in a modal dialog.
(basically, I'm trying to do this - http://acveer.wordpress.com/2011/01/25/using-the-sharepoint-2010-modal-dialog/ but it doesn't work. EDIT: If I change it to a asp:Button, it still doesn't work)
Here's some code if you're interested:
.aspx:
# Page Language="C#" AutoEventWireup="true" ...
<asp:LinkButton CssClass="button remove" runat="server" OnClick="remove_Click" Text="Remove" ID="remove"></asp:LinkButton>
.aspx.cs:
public void remove_Click(object sender, EventArgs e)
{
....
//if successful
HttpContext context = HttpContext.Current;
if (HttpContext.Current.Request.QueryString["IsDlg"] != null)
{
testControl.Text = "test code";
//doesn't work, and prevents line above from working
Context.Response.Write("<script type='text/javascript'>alert('hi!');</script>");
Context.Response.Flush();
Context.Response.End();
// context.Response.Write("<script type='text/javascript'>window.frameElement.commitPopup()</script>");
// context.Response.Flush();
// context.Response.End();
}
}
Anyone come across something similar?
EDIT: some more interesting pieces that may help,
The button itself lies within an UpdatePanel
I do have a AsyncPostbackTrigger assigned
Using Response.Write from Web Forms code behind is problematic at best. As a rule of the thumb: never ever use Response.Write from a Web Forms page or user control.
The reason Response.Write is problematic, is because it is not part of the page's control tree, and rendering infrastructure. This means that when used within events in it will output the text outside of the normal page flow, and usually outside of the proper HTML page structure.
This is also why things go awry when you're using them in combination with UpdatePanels. As UpdatePanels are specifically designed to replace parts from a page, the infrastructure needs to know which parts. A Response.Write happens completely outside of this, and there's no real way of knowing where to render it. At best, the ScriptManager will perform a Response.Clear to wipe out your Response.Writes, at worst you'll break the UpdatePanel protocol body and you'll get a JavaScript error.
To top things off, any literal <script> tag will be ignored when you're performing a partial page update, as the browser's innerHTML feature used to fill in the HTML fragments sent by the server does not execute <script> tags.
Now, with all this theory out of the way -- is there no way to execute a piece of JavaScript code through an UpdatePanel? It turns out there is, and it's a lot cleaner than just executing a Response.Write: ScriptManager.RegisterClientScriptBlock and ScriptManager.RegisterStartupScript. For example:
ScriptManager.RegisterClientScriptBlock(
theButton, // control or UpdatePanel that will be rendered
typeof(YourPage), "UniqueKey", // makes your script uniquely identifiable
"alert('Testing!');", true);
The important part is the first argument: now the ScriptManager will know when to execute your script. If you register it on a control that is not updated on a partial page refresh, your script will not execute. But if the UpdatePanel containing the control is refreshed, your script that is hooked up to it will also execute. And that's usually exactly what you want.
If you always want to execute your script, regardless of which panel updates, you'd call
ScriptManager.RegisterClientScriptBlock(Page, ... );
#Ruben provided a very good answer, but I felt I could add useful content that doesn't fit in a comment.
There are a few occasions in SharePoint where you use a Response.Write - namely when dealing with webparts that are displayed within a SharePoint Modal popup and you want to do something cute with the callback when using window.frameElement.commitPopup().
The fact that you are using Response.Write within an update panel is actually part of your issue. When a postback that was generated with an update panel returns, the response is formatted with UpdatePanelId|Response Content where UpdatePanelId is the div associated with the update panel and Response Content is the new inner HTML of the div. When you use response.write, that format is lost, therefore the ScriptManager has no idea what to do with the response and should ignore it as erroneous. #Ruben provided you a method of registering scripts within an UpdatePanel.
Context.Response... should have a lower case context
ie:
context.Response.Flush()
etc
or am I missing the point?

ASP.NET browser shows "web page has expired" for back button (after a post back)

I'm having trouble with a simple ASP.NET application and the back button after a post back.
The page in question has a simple form on it, some text fields etc, and a dropdown that does a postback (autopostback).
The "normal" flow is the user fills out the form and perhaps changes the dropdown. Based on the dropdown value the page content might change.
The problem I'm having is that after the user has changed the dropdown and the postback has completed then the user clicks the back button. They see a "webpage has expired" message from IE.
I've set the following:
Response.Cache.SetExpires(DateTime.Now.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.Private);
But that doesn't seem to have nailed the problem.
The actual Cache-Control response header reads as: private, no-cache:"Set-Cookie"
In a classic ASP application the with a Cache-Control response header of just "private" the back button behaves as expected after a "post back".
Is there anyway to force ASP.NET to set the cache-control explicitly to exactly "private"? Or any other solution that results in the back button and postbacks working well together?
Thanks!
Depending on a situation you might get away with this hack/workaround:
private void Page_PreRender(object sender, System.EventArgs e)
{
if (IsPostBack && !IsCallback)
{
Response.Write("<html><head><script>location.replace('" + Request.Path + "');\n" + "</script></head><body></body></html>\n");
Response.End();
}
}
What you're dealing with is actually an old problem. In essence, the reason that you're seeing the "web page has expired" message is that one of the techniques for disabling the "back" button has been employed. The technique sets the cache to a date in the past, therefore causing the browser to show this error if the user clicks the "back" button.
That would be this line of code:
Response.Cache.SetExpires(DateTime.Now.AddMinutes(-1));
This has been an issue, particularly with WebForms ASP.NET because of how the postback works, compared to other frameworks.
For a thorough explanation of all the issues involved, I strongly recommend reading the article linked to below. It does not answer your question directly, but I think you will get more information out of it than a simple answer and will help you think through your options, armed with a better understanding of the issue at hand. Be sure to read parts 1 AND 2.
https://web.archive.org/web/20210927201700/http://www.4guysfromrolla.com/webtech/111500-1.shtml
I do have an idea on how to make the "back" button behave like a "back" button again, so that postbacks aren't treated as a page navigation:
Personally, I've adopted a (arguably hackish/sloppy) approach of just putting things in an UpdatePanel when I don't want the postbacl/back button conflict, since I use Ajax in most of my apps anyway. This forces the "back" button to actually go back to the previous page, rather than staing on the same page, but reverting to the control values as they were before the postback.

How do i render a control to a string

I've seen it time and time again the typical answer being something like this:
public string RenderControlToHtml(Control ControlToRender)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
System.IO.StringWriter stWriter = new System.IO.StringWriter(sb);
System.Web.UI.HtmlTextWriter htmlWriter = new System.Web.UI.HtmlTextWriter(stWriter);
ControlToRender.RenderControl(htmlWriter);
return sb.ToString();
}
... This is fine if you have simple html tags but when I have a textbox or some other asp control in my control it throws a wobbly about the control not being on a form (which in fact it is because im trying to render a portion of the page to a string that i can then send as an email)
So ...
I'm pretty sure this has been asked and answered before but i'm at a loss for finding a real answer that actually works ...
How do i render the html output of both server and client side controls to a html string in .Net 4.0 because seemingly the above is not good enough?
Note:
I have found examples that talk about doing this at page level ...
public override void VerifyRenderingInServerForm(Control control)
{
//Do nothing (we dont care if theres a form or not)
}
... and disabling event validation but apparently that's not working for me either.
Is there a way to do this without a "hack" thats clean?
Also:
I even tried creating a new page, adding a form to it, added my control to that then calling renderControl on that page to which i got more errors.
EDIT:
I've been digging around and I think the problem might be related to postbacks or something because i found this:
http://forums.asp.net/t/1325559.aspx
Another thing that might be putting a bit of a spanner in the works is my use of the ajax toolkit, I essentially need only the visible portion of the control which seems to give a bit of a headache for updatepanels for some reason.
I'm guessing the above sample works only on basic .net controls that are not ajax toolkit related.
What further complicates the issue is that I would like to get the control in its current state when a button is clicked at the bottom of it ...
Essentially the control represents a form for booking an MOT and I would like to render the form filled in to an email that is then sent to the garage if that makes sense.
I'm thinking i may have to admit defeat here and simply get the markup from the client and manually build an email pulling out the control values as this seems to be a compatability issue between ajax controls and the renderControl method from what i can tell (maybe you cant render a partial postback compatible control in this fashion).
Unless someone smarter than me can prove it can be done ???
Create an ajax control extender and get the html markup on the client side then post that back to the server for processing, it's a bit of hack but it seems that anything involving ajax controls will cause the default recommended mechanism to break.

How to wait three seconds then turn to another webpage

I'm new to web development, and I'm currently using ASP.net. I wonder what would I need to do to let the browser wait for 3 seconds so my users can read the text "Customer Successfully Added" before turning to another page? I have attached my code as follows.
Protected Sub btnAdd_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnAdd.Click
Dim db As New DatabaseClass
db.addProfile(txtLN.Text, txtFN.Text, txtUsername.Text, txtPassword.Text, txtAddress.Text, txtZip.Text, txtPhone.Text, txtEmail.Text)
lblMessage.Text = "Customer Successfully Added"
End Sub
In addition, I'm not sure how to utilize MSDN. For me, its information overload, I'm wondering how to go about finding the solution on MSDN so i would be able to solve my problems in the future. Thank you!
You can't do it in the code behind of the page because of how asp.net works - the label text would not update until after the timeout occurred if you did it in the code-behind.
The server-side processing spits all the html back to the browser only after it has completely processed any server-side code unless you're using Ajax. Since you're new, I won't even bother going into how to do it with Ajax as there is a MUCH simpler option for accomplishing what you want.
A simple method to accomplish what you're looking for would be to have a simple HTML page that just has a message that says "Customer successfully added" and use javascript (client-side code) to pause and then redirect using the Javascript "SetTimeout" function.
There's an example here: http://www.bloggingdeveloper.com/post/JavaScript-Url-Redirect-with-Delay.aspx
The logic flow wshould work like this:
The original page should add the record (in code-behind) then redirect to this simple html page (in code-behind). The html page should have the "Customer Added" message and use the SetTimeout and Redirect to go to whatever page you want the user to see after viewing the message.
For stuff like this you need the code to run client side rather than on the server. The easiest way to do this is to return some javascript with your page (in the .aspx part rather than the code behind)
Take a look here for an idea of what to do :)
The page is displayed for a few seconds and then the javascript triggers a redirect to a url of your choosing. Just add something like this into your html.
You can emit javascript to redirect to the other page, using the setTimeout function.
This is best accomplished using the ScriptManager to register any javascript on the page.

How do I persist the value of a label through a response.redirect?

Here's the situation: I have a label's text set, immediately followed by a response.redirect() call as follows (this is just an example, but I believe it describes my situation accurately):
aspx:
<asp:Label runat="server" Text="default text" />
Code-behind (code called on an onclick event):
Label.Text = "foo";
Response.Redirect("Default.aspx");
When the page renders, the label says "default text". What do I need to do differently? My understanding was that such changes would be done automatically behind the scenes, but apparently, not in this case. Thanks.
For a little extra background, the code-behind snippet is called inside a method that's invoked upon an onclick event. There is more to it, but I only included that which is of interest to this issue.
A Response.Redirect call will ask the user's browser to load the page specified in the URL you give it. Because this is a new request for your page the page utilises the text which is contained in your markup (as I assume that the label text is being set inside a button handler or similar).
If you remove the Response.Redirect call your page should work as advertised.
After a redirect you will loose any state information associated to your controls. If you simply want the page to refresh, remove the redirect. After the code has finished executing, the page will refresh and any state will be kept.
Behind the scenes, this works because ASP.NET writes the state information to a hidden input field on the page. When you click a button, the form is posted and ASP.NET deciphers the viewstate. Your code runs, modifying the state, and after that the state is again written to the hidden field and the cycle continues, until you change the page without a POST. This can happen when clicking an hyperlink to another page, or via Response.Redirect(), which instructs the browser to follow the specified url.
ASP and ASP.Net are inherently stateless unless state is explicitly specified. Normally between PostBacks information like the value of a label is contained in the viewstate, but if you change pages that viewstate is lost because it is was being stored in a hidden field on the page.
If you want to maintain the value of the label between calls you need to use one of the state mechanisms (e.g. Session, Preferences) or communication systems (Request (GET, POST)).
Additionally you may be looking for Server.Transfer which will change who is processing the page behind the scenes. Response.Redirect is designed to ditch your current context in most cases.
To persist state, use Server.Transfer instead of Response.Redirect.
So, if I may answer my own question (according to the FAQ, that's encouraged), the short answer is, you don't persist view state through redirects. View state is for postbacks, not redirects.
Bonus: Everything you ever wanted to know about View State in ASP.NET, with pictures!
For what it's worth (and hopefully it's worth something), Chapter 6 of Pro ASP.NET 3.5 in C# 2008, Second Edition is a terrific resource on the subject. The whole book has been great so far.

Resources