GetCallbackEventReference doesn't work synchronously - asp.net

I have an ASP.NET 3.5 WebForm that leverages the frameworks Page.ClientScript.GetCallbackEventReference() method and I'd like some of the calls to be synchronous.
Now, the documentation says that the 5th parameter (see below) controls this. Specifically, when you pass 'false' it's supposed to be a non-asynchronous call. However, regardless if it's true or false, it still processes the call asynchronously.
Page.ClientScript.GetCallbackEventReference(this, "arg", "ReceiveServerData", "context",false);
Is there a work-around for this or perhaps I'm doing something wrong?

ASPX Page
<%# Page Language="VB" AutoEventWireup="false" CodeFile="How-to-use-GetCallbackEventReference.aspx.vb" Inherits="How_to_use_Callback" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>How to use GetCallbackEventReference</title>
<script type="text/javascript">
function GetNumber() {
UseCallback();
}
function GetRandomNumberFromServer(txtGetNumber, context) {
document.forms[0].txtGetNumber.value = txtGetNumber
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<input id="Button1" type="button" value="Get Random Number" onclick="GetNumber()" /><br /><br />
<asp:TextBox ID="txtGetNumber" runat="server"></asp:TextBox> </div>
</form>
</body>
</html>
Code Behind
Partial Class How_to_use_Callback
Inherits System.Web.UI.Page
Implements System.Web.UI.ICallbackEventHandler
Dim CallbackResult As String = Nothing
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim cbReference As String = Page.ClientScript.GetCallbackEventReference(Me, "arg", "GetRandomNumberFromServer", "context")
Dim cbScript As String = "function UseCallback(arg,context)" & "{" & cbReference & " ; " & "}"
Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "UseCallback", cbScript, True)
End Sub
Public Function GetCallbackResult() As String Implements System.Web.UI.ICallbackEventHandler.GetCallbackResult
Return CallbackResult
End Function
Public Sub RaiseCallbackEvent(ByVal eventArgument As String) Implements System.Web.UI.ICallbackEventHandler.RaiseCallbackEvent
CallbackResult = Rnd().ToString()
End Sub
End Class

For any other poor souls still using the MS AJAX library I found the following post:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/f4134c2e-ca04-423a-9da3-c613713a7b52/synchronous-callbacks-with-the-net-20-framework?forum=netfxjscript
The last comment from an MS source says:
This is actually by design. In order not to block the UI of the browser, this parameter doesn't actually do the request synchronously but makes sure the requests are queued and only one is going on at any given time. The effect is pretty much the same, except that the end-user can still use the browser UI while the request is going on and he won't have to kill the process if the server fails to respond or the network connection falls.
The MSDN page confirms this:
When sending data synchronously in a callback scenario, synchronous callbacks return immediately and do not block the browser. No two synchronous callbacks callback can execute at the same time in the browser. If a second synchronous callback is fired while one is currently pending, the second synchronous callback cancels the first and only the second callback will return.

Related

What's the difference between script function and code behind function?

<script runat="server">
Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
' The first time the page loads,
' render the DefaultView.
If Not IsPostBack Then
' Set DefaultView as the active view.
MultiView1.SetActiveView(DefaultView)
End If
End Sub
Sub LinkButton_Command(sender As Object, e As System.Web.UI.WebControls.CommandEventArgs)
' Determine which link button was clicked
' and set the active view to
' the view selected by the user.
Select Case (e.CommandArgument)
Case "DefaultView"
MultiView1.SetActiveView(DefaultView)
Case "News"
MultiView1.SetActiveView(NewsView)
Case "Shopping"
MultiView1.SetActiveView(ShoppingView)
Case Else
Throw New Exception("You did not select a valid list item.")
End Select
End Sub
</script>
what is difference between above code in(aspx) And if the same code in code behind(aspx.cs). Difference between function defined in tag with runat="server" attribute and function defined in code behind...?
How to execute JavaScript Function From ASP.NET Code:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="How_calljavascript_aspx_page.aspx.cs" Inherits="How_calljavascript_aspx_page" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Call JavaScript in asp.net page by C# on page load </title>
<script type="text/javascript">
function MyFunction() {
alert('this is javascript function run by C# code.');
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
execute JavaScript from code behind in asp.net:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class How_calljavascript_aspx_page : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!ClientScript.IsStartupScriptRegistered("alert"))
{
Page.ClientScript.RegisterStartupScript(this.GetType(),
"alert", "MyFunction();", true);
}
}
}
Functionally there is no difference between these two approaches, both will work the same for you.
Page script is useful if you have a small server side code, so that you can embed that code in the page itself.
But this will make things messier if the code is large.
The page designers will have access to the page code here.
The code behind approach provides you a clear separation of HTML and asp or VB code. Thats all...no functional difference between two approaches.

Passing any value to FileUpload.FileName using a button click

Despite the firing of the method associated with a form and button click, my fileupload will not pass a value to a string, am I doing something obviously wrong (or just wrong in general)?
Do I need to attach a handler to the fileupload
Here is some sample source, note, it is the only code in the project, I have not made any definitions to the button or fileupload anywhere else:
Public Class WebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Protected Sub Button_Click()
Dim FileUpload1 As New FileUpload()
Dim X As String = FileUpload1.FileName
Response.Write(X)
End Sub
End Class
and the form:
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm1.aspx.vb" Inherits="Test.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:Button ID="Button1" runat="server" OnClick="Button_Click" text="Submit"/>
<%-- <input type="file" />--%>
</form>
</body>
</html>
After trying FileUpload.HasFile, it appears as though not only can I not get the file name (described to me in the answer below), but the FileUpload.HasFile is nothing when a file is associated with it as well, is there any reason for this?
Protected Sub Button_Click()
Dim FileUpload1 As New FileUpload()
'Dim X As String = FileUpload1.FileName
'Response.Write(X)
If (FileUpload1.HasFile) Then
' Do Something
' SaveFile(FileUpload1.PostedFile)
Else
End If
End Sub
If you are looking for the path of the uploaded file in the client's machine, that is not allowed for security reasons.
However you should be able to get just the file name using the FileName property.
I check the file name in my applications when i want to test the to see the filetype that is uploaded.
I do not think the following line is required in your Protected Sub Button_Click() function:
Dim FileUpload1 As New FileUpload()
That must be creating a new instance causing it to show you an empty File Name.
If you just need the file name and not the entire path you could try the above.
Edit: Just saw the edit to your questions. The line I asked you to remove may be causing HasFile property to be empty as well.
You can not pass/assign name asp:FileUpload, as it is converted to input type file it is not allowed due to security reason. As it could breach the security of client machine that is browsing the website. The only possibility to assign it a value is through user selection that is browsing and assigning the file by user from client (browser)
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.fileupload.saveas.aspx
You can use FileUpload.SaveAs method to save the selected file.
FileUpload1.SaveAs(savePath);

using ClientScriptIncludeRegister to get a hidden field value

I am implementing a web application using ASP.NET/VB. The front-end (.aspx) executes an external .js file as:
<script type =" text/javascript" src="External.js"></script>
where it contains some functions. One of these functions called populateHidden() is used to assign a value to the hiddenField I defined on the front-end (.aspx) as follows:
In External.js
document.getElementByID('Hidden2').value = "dsadsadas";
In .aspx
<input id="Hidden2" type ="hidden" runat="server" />
what I have been trying to do is to get the value assigned to Hidden2 and pass it to the server-side (.aspx.vb) using:
Dim str = Hidden2.value
However, since server-side code executes first,str would be empty and unless a postback is done somehow whether using a Button or a Timer to reload the front-end, then str will have dsadsadas. I do not intend to reload the page or initialize a postback. I tried window.onload = populateHidden() with no luck. This situation made me desperate since I tried to many things making sure I do not use postbacks or reloads until I came across ClientScriptManager.RegisterClientScriptInclude Method . I couldn't not get around onto how I can use such an example to solve my situation.
The idea in mind is to call or execute External.js from the server side (since it executes first), then populate Hidden2 on the front-end, go back to the server side and retrieve Hidden2.value.
However the example in the link mentioned earlier, the server-side code is written in the front-end but I want to write it on the server-side (.aspx.vb).
The reason why I need Hidden2.value in the server-side is to store it in my sql_database. Any suggestions, advice or solutions to get Hidden2.value from the front-end would be really appreciated.
The following solution uses only ASP.Net Ajax Engine. In PageLoad event, a call to populateHidden() function is being registered. In the codebehind, a method marked with the WebMethod attribute was added, allowing it to be called by an Ajax request (without postback). So, when the button is clicked, the javascript function sendHiddenValueToServer() is called, making an Ajax request to the Page Method, passing the Hidden Field Value as Parameter.
First, you will need a ScriptManager declared with the EnablePageMethods property set to true:
<asp:ScriptManager runat="server" EnablePageMethods="true" />
I tested using the following markup:
<html>
<head runat="server">
<title></title>
<script src="External.js" type="text/javascript"></script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server" EnablePageMethods="true" />
<div>
<asp:HiddenField ID="Hidden2" runat="server" ClientIDMode="Static" />
<button id="button1" onclick="sendHiddenValueToServer();">
Send Value to Server</button>
</div>
</form>
</body>
</html>
In the Javascript file:
function populateHidden() {
document.getElementById('Hidden2').value = "dsadsadas";
}
function sendHiddenValueToServer() {
PageMethods.ReceiveHiddenValue(
document.getElementById('Hidden2').value,
function () { alert("success!") },
function () { alert("error!") });
}
And in the codebehind:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
ScriptManager.RegisterStartupScript(Me, Me.GetType(), "register", "populateHidden();", True)
End If
End Sub
<System.Web.Services.WebMethod()>
Public Shared Sub ReceiveHiddenValue(ByVal value As String)
Dim str As String = value
' Save Value to database
End Sub

Show Image/HTML before Page_Load is completed

I have following code in aspx
<%# Page Language="VB" AutoEventWireup="false" CodeFile="test.aspx.vb" nherits="test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server"></head>
<body>
<img src="images/loading_anim.gif" />Please wait...
</body>
</html>
In test.aspx.vb
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
......Do some processing here .
Response.redirect("Next.aspx")
End Sub
Code Behind I do some processing in Page_load method and redirect to other page but it might take some time so I want to show user loading image.But it shows that after page_load is completed.How to handle this ?
I will suggest that you use a generic handler (ashx) and use un-buffered response. For example:
public class Handler : IHttpHandler
{
public void ProcessRequest (HttpContext context)
{
context.Response.BufferOutput = false;
context.Response.Write("<html><head></head><body><img src=\"images/loading_anim.gif\" />Please wait...</body></html>"
context.Response.Flush();
// do your processing
...
// redirect
}
...
}
Yet another way to first show image on the client side (using java-script) and then do redirection (or post) from client side.
I don't think it will work because always the server side code works first, then only HTML rendering starts. Better option will be using Ajax.
More details here : ASP.NET Integration with IIS 7

asp.net FindControl Recursively

This is a really weird one - I will do my best to explain.
I have a basic master page:
<%# Master Language="VB" CodeFile="MasterPage.master.vb" Inherits="master_MasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
<asp:PlaceHolder ID="PH1" runat="server" />
<asp:PlaceHolder ID="PH2" runat="server" />
</div>
</form>
</body>
</html>
And a standard child page:
<%# Page Title="" Language="VB" MasterPageFile="~/master/MasterPage.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="master_Default" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
</asp:Content>
I have the following extension methods for finding controls recursively:
Option Strict On
Option Explicit On
Imports System.Runtime.CompilerServices
Imports System.Web.UI
Public Module ExtensionMethods
<Extension()> _
Public Function FindControlRecursively(ByVal parentControl As System.Web.UI.Control, ByVal controlID As String) As System.Web.UI.Control
If parentControl.ID = controlID Then
Return parentControl
End If
For Each c As System.Web.UI.Control In parentControl.Controls
Dim child As System.Web.UI.Control = FindControlRecursively(c, controlID)
If child IsNot Nothing Then
Return child
End If
Next
Return Nothing
End Function
<Extension()> _
Public Function FindControlIterative(ByVal rootControl As Control, ByVal controlId As String) As Control
Dim rc As Control = rootControl
Dim ll As LinkedList(Of Control) = New LinkedList(Of Control)
Do While (rc IsNot Nothing)
If rc.ID = controlId Then
Return rc
End If
For Each child As Control In rc.Controls
If child.ID = controlId Then
Return child
End If
If child.HasControls() Then
ll.AddLast(child)
End If
Next
rc = ll.First.Value
ll.Remove(rc)
Loop
Return Nothing
End Function
End Module
I have a control with a listview:
<%# Control Language="VB" AutoEventWireup="false" CodeFile="control-1.ascx.vb" Inherits="controls_control_1" %>
<p>
Control 1</p>
<asp:ListView ID="lv" runat="server">
<ItemTemplate>
<div>
<asp:Literal ID="Name" runat="server" Text='<%#Eval("Name") %>' />
<asp:LinkButton ID="TestButton" runat="server">Test</asp:LinkButton>
</div>
</ItemTemplate>
</asp:ListView>
That is databound:
Partial Class controls_control_1
Inherits System.Web.UI.UserControl
Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Dim l As New List(Of Person)
Dim j As New Person
j.Name = "John"
l.Add(j)
lv.DataSource = l
lv.DataBind()
End If
End Sub
End Class
Public Class Person
Public Property Name As String
End Class
I have a second control that is very basic:
<%# Control Language="VB" AutoEventWireup="false" CodeFile="control-2.ascx.vb" Inherits="controls_control_2" %>
<p>Control 2</p>
In my child page, I have the following code to load the controls:
Option Strict On
Option Explicit On
Partial Class master_Default
Inherits System.Web.UI.Page
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
Dim controlInstance1 As System.Web.UI.Control = LoadControl("~/controls/control-1.ascx")
controlInstance1.ID = "control_1"
Dim zone As System.Web.UI.Control = Me.Master.FindControlRecursively("PH1")
zone.Controls.Add(controlInstance1)
Dim controlInstance2 As System.Web.UI.Control = LoadControl("~/controls/control-2.ascx")
controlInstance2.ID = "control_2"
Dim zone2 As System.Web.UI.Control = Me.Master.FindControlRecursively("PH2")
zone2.Controls.Add(controlInstance2)
End Sub
End Class
This loads the controls, but if I click the Test button in the listview, the page loses the data in the listview after postback.
If I change the FindControlRecursively calls to FindControlIterative, when I click the test button, the data in the listview is retained after the postback.
Anybody have any idea what the FindControlRecursively call might be doing to cause the listview to lose it's data? This only happens if control-2 is added to the page - if it is not, and control-1 is loaded using FindControlRecursively, data is retained correctly after postback.
Thanks in advance...this one is driving me nuts, and it took me a while to figure out where exactly it was breaking down.
Why don't you simply expose properties that return PH1 and PH2, because the master has the reference of them and you don't need to iterate all child controls of master:
Public ReadOnly Property Container1 As PlaceHolder
Get
Return Me.PH1
End Get
End Property
Public ReadOnly Property Container2 As PlaceHolder
Get
Return Me.PH2
End Get
End Property
You can access them:
Dim ph1 As PlaceHolder = DirectCast(Me.Master, myMaster).Container1
Dim ph2 As PlaceHolder = DirectCast(Me.Master, myMaster).Container2
Another problem is this line:
controlInstance1.ID = "control_2"
You are setting only controlInstance1's ID twice, but that doesn't cause your issue.
Your main problem is that you are adding the controls to the placeholders in Page_Init instead of Page_Load. Therefore the UserControls can't load their ViewState and the ListView is empty. Recreate them in Page_Load and it will work.
Edit: But i must admit that i don't know why your iterate extension wins over the recursive. The reference on the placeholders are the same, they shouldn't work both, weird.
summary:
it works with my properties,
putting all in page's load event handler instead init
with your iterate-extension(for whatever reasons)
It also works if you add both UserControls at last, after you've found the placeholders via FindControlRecursively.
zone.Controls.Add(controlInstance1)
zone2.Controls.Add(controlInstance2)
I'm losing motivation on this, but i'm sure you'll find the answer here. Controls.Add loads it's parent's ViewState into all childs and therefore it depends on when you add the controls, also the index of the controls in their parent controls must be the same on postback to reload the ViewState.
Your recursive extension method touches control1's ID after you've added it to PH1(while searching PH2), the iterative extension does not. I assume that this corrupts it's ViewState in Page_Init.
Conclusion Use properties instead
I figured out why I was seeing the behavior I described above. I changed the recursive function to the following:
<Extension()> _
Public Function FindControlRecursively(ByVal parentControl As System.Web.UI.Control, ByVal controlId As String) As System.Web.UI.Control
If String.IsNullOrEmpty(controlId) = True OrElse controlId = String.Empty Then
Return Nothing
End If
If parentControl.ID = controlId Then
Return parentControl
End If
If parentControl.HasControls Then
For Each c As System.Web.UI.Control In parentControl.Controls
Dim child As System.Web.UI.Control = FindControlRecursively(c, controlId)
If child IsNot Nothing Then
Return child
End If
Next
End If
Return Nothing
End Function
By adding the parentControl.HasControls check, I am preventing the function from searching the listview for child controls, and this allows the listview to load its viewstate later on in the page/control lifecycle.
Also, I tweaked my iterative function to make it more efficient and prevent it from bugging out if a control was not returned:
<Extension()> _
Public Function FindControlIteratively(ByVal parentControl As Web.UI.Control, ByVal controlId As String) As Web.UI.Control
Dim ll As New LinkedList(Of Web.UI.Control)
While parentControl IsNot Nothing
If parentControl.ID = controlId Then
Return parentControl
End If
For Each child As Web.UI.Control In parentControl.Controls
If child.ID = controlId Then
Return child
End If
If child.HasControls() Then
ll.AddLast(child)
End If
Next
If (ll.Count > 0) Then
parentControl = ll.First.Value
ll.Remove(parentControl)
Else
parentControl = Nothing
End If
End While
Return Nothing
End Function
Also, to follow up on my earlier description of the problem - I was able to reproduce the recursive function's intially weird behavior using the iterative function if I removed the If child.HasControls() Then check from the iterative function. Hope that makes sense.
In the end I am sticking with the iterative function because looping should be less expensive than recursion, though in real world scenarios the difference probably will not be noticeable.
The following links were extremely helpful to me in working this out:
http://msdn.microsoft.com/en-us/library/ms972976.aspx#viewstate_topic4
https://web.archive.org/web/20210330142645/http://www.4guysfromrolla.com/articles/092904-1.aspx
http://scottonwriting.net/sowblog/archive/2004/10/06/162995.aspx
http://scottonwriting.net/sowblog/archive/2004/10/08/162998.aspx
Extra thanks to Tim for pointing me in the right direction.

Resources