Reputation: 11393
I have the following code :
protected void gv_inbox_RowCommand(object sender, GridViewCommandEventArgs e)
{
int index = Convert.ToInt32(e.CommandArgument);
if (e.CommandName == "sign")
{
Session["TransYear"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_TransYear")).Value);
Session["MailNumber"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_MailNumber")).Value);
Response.Redirect("Signature.aspx", false);
//Response.Write("<script>");
//Response.Write("window.open('Signature.aspx','_blank')");
//Response.Write("</script>");
}
}
I want to open the page in a new tab or window . The commented code do that but when refresh
the original page cause errors .how to open Signature.aspx
in a new window or tab in the correct way in the row command event of my gridview .
Upvotes: 4
Views: 9480
Reputation: 648
Why are we using post backs for opening a link in a different window for the URL.
While creating the control link we can embed the values required by signature.aspx on the link control as Querystring and it will be just a simple browser click.
I hope this is simple and clean.
Upvotes: 1
Reputation: 5319
First of all, the exercise here is how to pass simple values from one page to another.
In your case those are only Keys/Values so you can pass them via GET.
You need to render this every row, instead of the command button.
<a href="Signature.aspx?TransYear=value1&MailNumber=value2" target="_blank">
Sign
</a>
In this example, value1 and value2 are the values that you were writing into HDN_TransYear and HDN_MailNumber respectively.
In Signature.aspx you had to do something like this if you wanted to use the session variables:
Session["TransYear"]
Session["MailNumber"]
Now it should be changed to this:
Request.QueryString["TransYear"]
Request.QueryString["MailNumber"]
That will normally make what you asked for. But...
If you say that this method is insecure, that anyone could play with the querystring variables by changing the parameter values, then...
Compute a signature for each row, put this signature as a third param in your querystring and validate the values and the signature in the other side.
How to compute the signature, well, it is up to you. That's your secret sauce. There are lots of hashing functions and salting algorithms.
As a very simple example:
string signature = CRC32(HDN_TransYear + "stuff that you only know" + HDN_MailNumber)
Then your link should look something like this:
<a href="Signature.aspx?TransYear=2012&MailNumber=1&sig=8d708768" target="_blank">
Sign
</a>
In Signature.aspx you use the values from the querystring and the "stuff you only know" to calculate the CRC32 signature again and validate against the signature passed as parameter in the querystring.
No dramas.
Upvotes: 4
Reputation: 1021
Why do you want to set the session before opening the new window?
If setting the session after opening the new window is okay, I think you can do it in the code behind of Signature.aspx
, considering you have the required parameters passed as query strings as @David pointed out.
Upvotes: 2
Reputation: 4971
We've used the following code successfully for some number of years now. These several methods are extracted out of a larger general-purpose module but I think I've included everything...
public class Utilities
{
/// <summary>
/// This will return the first parent of the control that is an update panel
/// </summary>
/// <param name="source">The source control</param>
/// <returns>The first parent found for the control. Null otherwise</returns>
public static UpdatePanel GetFirstParentUpdatePanel(Control source)
{
Page currentPage = source.Page;
UpdatePanel updatePanel = null;
Type updatePanelType = typeof(UpdatePanel);
object test = source.Parent;
while (test != null && test != currentPage)
{
// is this an update panel
if (test.GetType().FullName == updatePanelType.FullName)
{
// we've found the containing UpdatePanel
updatePanel = (UpdatePanel)test;
}
// check the next parent
test = ((Control)test).Parent;
} // next test
return updatePanel;
}
/// <summary>
/// This will open the specified url in a new window by injecting a small script in
/// the current page that is run when the page is sent to the client's browser.
/// This method accounts for the presence of update panels and script managers on the
/// page that the control resides in.
/// </summary>
/// <param name="source">The control that the call is being made from</param>
/// <param name="url">The URL to bring up in a new window</param>
public static void RedirectToNewWindow(Control source, string url)
{
// create the script to register
string scriptKey = "_NewWindow";
string script = "window.open('" + url + "');";
RegisterControlScript(source, scriptKey, script);
}
/// <summary>
/// This will register a script for a specific control accounting for the control's UpdatePanel
/// and whether or not there is a script manager on the page
/// </summary>
/// <param name="source">The control that will be affected by the script</param>
/// <param name="scriptKey">A unique key for the script</param>
/// <param name="script">The script that will affect the control</param>
public static void RegisterControlScript(Control source, string scriptKey, string script)
{
// get the control's page
Page currentPage = source.Page;
// does the control reside in an UpdatePanel
UpdatePanel updatePanel = GetFirstParentUpdatePanel(source);
// did we find the UpdatePanel
if (updatePanel == null)
{
// register the script on the page (works outside the control being in an update panel)
currentPage.ClientScript.RegisterStartupScript(currentPage.GetType(), scriptKey,
script, true /*addScriptTags*/);
}
else
{
// register the script with the UpdatePanel and ScriptManger
ScriptManager.RegisterClientScriptBlock(source, source.GetType(), scriptKey,
script, true /*addScriptTags*/);
} // did we find the UpdatePanel
}
}
Then, for you're usage, you'd call
protected void gv_inbox_RowCommand(object sender, GridViewCommandEventArgs e)
{
int index = Convert.ToInt32(e.CommandArgument);
if (e.CommandName == "sign")
{
Session["TransYear"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_TransYear")).Value);
Session["MailNumber"] = int.Parse(((HiddenField)gv_inbox.Rows[index].Cells[1].FindControl("HDN_MailNumber")).Value);
Utilities.RedirectToNewWindow(gv_inbox, "Signature.aspx");
}
}
Not the most concise code as I've extracted these helper methods but you get the idea. The code above will work on c#2.0 and up and will work regardless of UpdatePanel
nesting or even if no UpdatePanel
s are used at all
Upvotes: 2
Reputation: 8759
What you want to do is use the ScriptManager
to make the JavaScript call.
The JavaScript snippet you had defined works, however, you need the ScriptManager
to take care of executing it for you.
String js = "window.open('Signature.aspx', '_blank');";
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "Open Signature.aspx", js, true);
The issue with using Response.Write
is that during PostBack
, the browser will not execute script tags. On the other hand, when using ScriptManager.RegisterClientScriptBlock
, the ASP.NET ScriptManager
will execute the code automatically.
UPDATE - 2013/02/14
As suggested in Vladislav's answer, use ClientScript
vs. ScriptManager
; the difference is ClientScript
is for synchronous postbacks only (no asp:UpdatePanel
), and ScriptManager
is for asynchronous postbacks (using asp:UpdatePanel
).
Additionally, per the author's comment below - enclosing the asp:GridView
in an asp:UpdatePanel
will eliminate the browser message confirming a refresh. When refreshing a page after a synchronous postback (no asp:UpdatePanel
), the browser will resend the last command, causing the server to execute the same process once more.
Finally, when using an asp:UpdatePanel
in conjunction with ScriptManager.RegisterClientScriptBlock
, make sure you update the first and second parameters to be the asp:UpdatePanel
object.
ScriptManager.RegisterClientScriptBlock(updatePanel1, updatePanel1.GetType(), "Open Signature.aspx", js, true);
Upvotes: 5
Reputation: 2982
I would rather use
ClientScript.RegisterStartupScript(this.GetType(), "Open Signature.aspx", js, true);
and you don't need to refresh your page.
The script block will fire after the page has recovered from the postback.
And just a suggestion: - is it possible in your case to use DataKeys to retrieve values for TransYear and MailNumber instead of using HiddenFields
Upvotes: 2