ASP.NET 2.0 Asynchronous User Control Not Working - asp.net

I'm trying to get a user control working asynchronously, yet no matter what I do it continues to work synchronously. I've stripped it down to its bare minimum as a test web application. This would be the user control:
<%# Control Language="C#" %>
<script runat="server">
SqlConnection m_oConnection;
SqlCommand m_oCommand;
void Page_Load(object sender, EventArgs e)
{
Trace.Warn("Page_Load");
string strDSN = ConfigurationManager.ConnectionStrings["DSN"].ConnectionString + ";async=true";
string strSQL = "waitfor delay '00:00:10'; select * from MyTable";
m_oConnection = new SqlConnection(strDSN);
m_oCommand = new SqlCommand(strSQL, m_oConnection);
m_oConnection.Open();
Page.RegisterAsyncTask(new PageAsyncTask(new BeginEventHandler(BeginHandler), new EndEventHandler(EndHandler), new EndEventHandler(TimeoutHandler), null, true));
Page.ExecuteRegisteredAsyncTasks();
}
IAsyncResult BeginHandler(object src, EventArgs e, AsyncCallback cb, object state)
{
Trace.Warn("BeginHandler");
return m_oCommand.BeginExecuteReader(cb, state);
}
void EndHandler(IAsyncResult ar)
{
Trace.Warn("EndHandler");
GridView1.DataSource = m_oCommand.EndExecuteReader(ar);
GridView1.DataBind();
m_oConnection.Close();
}
void TimeoutHandler(IAsyncResult ar)
{
Trace.Warn("TimeoutHandler");
}
</script>
<asp:gridview id="GridView1" runat="server" />
And this would be the page in which I host the control three times:
<%# page language="C#" trace="true" async="true" asynctimeout="60" %>
<%# register tagprefix="uc" tagname="mycontrol" src="~/MyControl.ascx" %>
<html>
<body>
<form id="form1" runat="server">
<uc:mycontrol id="MyControl1" runat="server" />
<uc:mycontrol id="MyControl2" runat="server" />
<uc:mycontrol id="MyControl3" runat="server" />
</form>
</body>
</html>
The page gets displayed without errors, but the trace at the bottom of the page shows each control instance is processed synchronously. What am I doing wrong? Is there a configuration setting somewhere I'm missing?

Looks like I can answer my own question. The user control should not be calling Page.ExecuteRegisteredAsyncTasks. By doing that, the control was adding the async task, running it, and waiting for it to complete.
Instead, each instance of the user control should call only Page.RegisterAsyncTask. After each control instance has done this the page automatically calls RegistereAsyncTask running all three registered async tasks simultaniously.
So here is the new user control:
<%# Control Language="C#" %>
<script runat="server">
SqlConnection m_oConnection;
SqlCommand m_oCommand;
void Page_Load(object sender, EventArgs e)
{
Trace.Warn(ID, "Page_Load - " + Thread.CurrentThread.GetHashCode().ToString());
string strDSN = ConfigurationManager.ConnectionStrings["DSN"].ConnectionString + ";async=true";
string strSQL = "waitfor delay '00:00:10'; select * from TEProcessedPerDay where Date > dateadd(day, -90, getutcdate()) order by Date asc";
m_oConnection = new SqlConnection(strDSN);
m_oCommand = new SqlCommand(strSQL, m_oConnection);
m_oConnection.Open();
Page.RegisterAsyncTask(new PageAsyncTask(new BeginEventHandler(BeginHandler), new EndEventHandler(EndHandler), new EndEventHandler(TimeoutHandler), null, true));
}
IAsyncResult BeginHandler(object src, EventArgs e, AsyncCallback cb, object state)
{
Trace.Warn(ID, "BeginHandler - " + Thread.CurrentThread.GetHashCode().ToString());
return m_oCommand.BeginExecuteReader(cb, state);
}
void EndHandler(IAsyncResult ar)
{
Trace.Warn(ID, "EndHandler - " + Thread.CurrentThread.GetHashCode().ToString());
GridView1.DataSource = m_oCommand.EndExecuteReader(ar);
GridView1.DataBind();
m_oConnection.Close();
}
void TimeoutHandler(IAsyncResult ar)
{
Trace.Warn(ID, "TimeoutHandler - " + Thread.CurrentThread.GetHashCode().ToString());
}
</script>
<asp:gridview id="GridView1" runat="server" />
And the unchanged page that creates three instances of the control:
<%# page language="C#" async="true" trace="true" %>
<%# register tagprefix="uc" tagname="mycontrol" src="~/MyControl.ascx" %>
<html>
<body>
<form id="form1" runat="server">
<uc:mycontrol id="MyControl1" runat="server" />
<uc:mycontrol id="MyControl2" runat="server" />
<uc:mycontrol id="MyControl3" runat="server" />
</form>
</body>
</html>

If I may add a little to the above post, we should not call the ExecuteRegisteredAsyncTassk explicitly unless there is a compelling reason. once you register the async task, the ASP.NET framework will execute all these tasks right after the OnPrerender event of the page lifecycle.
An example for the usage of ExecuteRegisteredAsyncTasks could be;
Sometimes you may need to ensure that several async operations are completed before calling another async task. in a situation like this it is justifiable to use ExecuteRegisteredAsyncTasks.

Related

w3wp eating up memory and not giving it back

I have a classic asp.net page in .net 4.6.1.
It loads 4 MB of data (they want it on one page) and no matter I simplify it, the IIS Worker Process w3wp.exe eats up a Gig of data, and never expires anything or gives any memory back.
Why?
<%# Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<asp:GridView ID="gvSelectionList" runat="server" AutoGenerateColumns="false" CssClass="LPSCriteriaSelection" EnableViewState="False">
<Columns>
<asp:TemplateField HeaderText="SerialNumber">
<ItemTemplate>
<asp:HyperLink ID="hlSerialNumber" Text='<%#GetSerialNumberText(Container.DataItem)%>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</asp:Content>
Here's the code
using System;
using System.Collections.Generic;
using System.Web.UI;
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
if(this.IsPostBack) return;
ExpandableSelections items = new ExpandableSelections();
if(items.Count == 0) return;
this.gvSelectionList.DataSource = items;
this.gvSelectionList.DataBind();
}
protected string GetSerialNumberText(object dataItem)
{
SerialNumberData item = (SerialNumberData)dataItem;
return item.SerialNumber;
}
}
public class SerialNumberData
{
public string SerialNumber { get; set; }
public SerialNumberData(string data) { SerialNumber = data; }
}
public class ExpandableSelections : List<SerialNumberData>
{
internal ExpandableSelections()
{ // Emulate database call
for (int i = 1; i < 72000; i++)
this.Add(new SerialNumberData("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"));
}
}
A call to Microsoft revealed calling .Dispose() on the grid itself will make it more readily available to Garbage Collection, but in this example the GC thread was often blocked (said they couldn't see by what -- antivirus?) and, because we only needed a read-only GridView,
I found it far better to simply replace the GridView with a classic <% FunctionCall(); %> and in that call write the html out directly with Reponse.Write().
This used far less RAM and would always return it on subsequent page loads.

Button not fired up inside asp user control used for umbraco macro

I'm searching solutions for my problem already since 2-3h and I decided better to ask.
I have created and empty web site and the installed umbraco, set up a new macro and it seemd ok but a button is not fired .
The code in Test.ascx:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Tests.ascx.cs" Inherits="Demo.Tests" %>
<h1>test</h1>
<form id="Form1" runat="Server">
<asp:Button ID="btnRunTest" OnClick="onClick_btnRunTest" Text="Run test" runat="server" CausesValidation = "false"/>
</form>
<div style="background-color: #de6363; padding: 10px;">
<asp:Label ID="lblMessage" runat="server" Text="" ForeColor="black" />
</div>
And code behind:
public partial class Tests : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
//btnRunTest.Click += new EventHandler(this.onClick_btnRunTest);
}
public void onClick_btnRunTest(object sender, EventArgs e)
{
lblMessage.Text = "";
Stopwatch stopwatch = Stopwatch.StartNew();
DynSLinkedList<int?> list = new DynSLinkedList<int?>();
list.Add(1);
list.Add(18);
list.Add(-1);
list.Add(-2);
list.Add(1);
list.Add(18);
list.Add(-1);
list.Add(-2);
list.Add(1);
list.Add(18);
list.Add(-1);
list.Add(-2);
list.Add(1);
list.Add(18);
list.Add(-1);
list.Add(-2);
list.Remove(18);
list.Remove(-2);
list.Remove(1);
var time = stopwatch.Elapsed.ToString();
lblMessage.Text = "Task finished in time "+time +"</br>";
}
}
When I hit the button page reloads but the onClick_btnRunTest is not hit

ViewState on programmatically loaded usercontrols (restored after Page_Load)

I'm trying to create a simple web page with a navigation bar and some usercontrols (ascx) programmatically loaded.
All controls are inside an update panel.
When I click on a link button (from the navigation bar) I do the following things:
I save the current usercontrol using viewstate.
Than I reload the current usercontrol.
My 'page_load' always reloads the current control.
Always assigning the same ID to the programmatically loaded control allows me to save the usercontrol viewstate.
So everything look good except one little thing: the usercontrol viewstate in not available during the usercontrol Page_Load!
Look below for (* HERE).
The 'txtTest.Text' value is always "0" (also during postback).
It seems that the user control viewstate is restored after the (usercontrol) Page_Load.
How is it possible?
--- "DEFAULT.ASPX": ---
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="sm" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="pnlMain" runat="server">
<ContentTemplate>
<div class="links">
<asp:LinkButton ID="lnkButton1" runat="server" OnClick="lnkButton1_Click" Text="Link 1"></asp:LinkButton>
<asp:LinkButton ID="lnkButton2" runat="server" OnClick="lnkButton2_Click" Text="Link 2"></asp:LinkButton>
</div>
<br />
<asp:Panel ID="pnlCtrl" runat="server"></asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
--- "DEFAULT.ASPX.CS": ---
private string CtrlAscx
{
get
{
if (ViewState["CtrlAscx"] == null)
{
ViewState["CtrlAscx"] = String.Empty;
}
return ViewState["CtrlAscx"].ToString();
}
set
{
ViewState["CtrlAscx"] = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
loadMyControl();
}
private void loadMyControl()
{
if (!String.IsNullOrEmpty(CtrlAscx))
{
pnlCtrl.Controls.Clear();
Control c = LoadControl(CtrlAscx);
c.ID = CtrlAscx + "ID"; // this line is mandatory in order to mantain the usercontrol viewstate
pnlCtrl.Controls.Add(c);
}
}
protected void lnkButton1_Click(Object sender, EventArgs e)
{
CtrlAscx = "Control1.ascx";
loadMyControl();
}
protected void lnkButton2_Click(Object sender, EventArgs e)
{
CtrlAscx = "Control2.ascx";
loadMyControl();
}
-- "CONTROL1.ASCX" --
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Control1.ascx.cs" Inherits="WebTest.Control1" %>
Control1: <asp:TextBox id="txtTest" runat="server" Text="0"></asp:TextBox>
<asp:Button ID="btnTest" runat="server" />
-- "CONTROL1.ASCX.CS" --
public partial class Control1 : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (txtTest.Text == "0") // * HERE
{
txtTest.Text = "1";
}
}
}
Try the EnableViewState="true" attribure on txtTest as well as on your custom user control when creating it :
.
.
c.EnableViewState = true;
pnlCtrl.Controls.Add(c);

How to update a status label while processing something on the server?

I have a requirement to process (server side) a lot of data (files) when the user clicks a button. I'd like to show a running summary of each file name as it's being processed. I've been trying to do it with the UpdatePanel control but only the very last update happens. Here's some simple code I created to simulate the issue (it should count up from 1 to 10 but instead waits the 5 seconds and outputs 10):
<%# Page Language="C#" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
ScriptManager1.RegisterAsyncPostBackControl(Button1);
}
protected void Button1_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 10; i++)
{
Label1.Text = i.ToString();
System.Threading.Thread.Sleep(500);
UpdatePanel1.Update();
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
Is there a way to make this work? Or maybe a better way to do it?
Thanks in advance,
Jason
You'll need to use an ajax call to the server. I have copied this code from one of my previous projects it's a bit long code. try it and let me know if it works.
page1.aspx
<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
<script type="text/javascript">
function BeginProcess() {
// Create an iframe.
var iframe = document.createElement("iframe");
// Point the iframe to the location of
// the long running process.
iframe.src = "Process.aspx";
// Make the iframe invisible.
iframe.style.display = "none";
// Add the iframe to the DOM. The process
// will begin execution at this point.
document.body.appendChild(iframe);
// Disable the button and blur it.
document.getElementById('trigger').blur();
}
function UpdateProgress(PercentComplete, Message) {
document.getElementById('ContentPlaceHolder2_lbDownload').setAttribute("disabled", "true");
document.getElementById('trigger').value = PercentComplete + '%: ' + Message;
}
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder2" Runat="Server">
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<input type="submit" value="Start BackUp Process!"
id="trigger" onclick="BeginProcess(); return false;"
style="width: 250px;" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdateProgress ID="UpdateProgress1"
AssociatedUpdatePanelID="UpdatePanel1" runat="server">
<ProgressTemplate>
</ProgressTemplate>
</asp:UpdateProgress>
</asp:Content>
Process.aspx.cs
public partial class Process : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
StringBuilder SB = new StringBuilder();
// Padding to circumvent IE's buffer.
Response.Write(new string('*', 256));
Response.Flush();
// Initialization
UpdateProgress(0, "Initializing task.");
try
{
foreach (yourloophere)
{
UpdateProgress(increment, db.Name + " Backup Started....");
//your process code
UpdateProgress(increment, db.Name + " Backup Completed!");
//your process code
SB.Append(db.Name + "BackUp Complted!");
//your process code
SB.Append("<br/>");
}
// All finished!
UpdateProgress(100, "All Database BackUp Completed!");
}
catch (Exception ex)
{
UpdateProgress(0, "Exception: " + ex.Message);
SB.Append("Back Up Failed!");
SB.Append("<br/>");
SB.Append("Failed DataBase: " + DBName);
SB.Append("<br/>");
SB.Append("Exception: " + ex.Message);
}
}
protected void UpdateProgress(double PercentComplete, string Message)
{
// Write out the parent script callback.
Response.Write(String.Format("<script type=\"text/javascript\">parent.UpdateProgress({0}, '{1}');</script>", PercentComplete, Message));
// To be sure the response isn't buffered on the server.
Response.Flush();
}
}

AjaxFileUpload doesn't fire OnUploadComplete Event

i am trying to get that AjaxFileUpload-Control(used in ContentPage) working. But it does not fire OnUploadComplete Event at server side
I am using version 4.1.60919.0 of the ControlToolkit. I have tried everything i found on the internet.
Here just a few steps:
Added enctype="multipart/form-data" method="post" to the form-element in my MasterPage
Nested the AjaxFileUpload into an UpdatePanel with UpdateMode=Always
Tried events UploadedComplete and OnUploadComplete, but stayed at the second one
Added a try-catch-block in the EventHandler to catch unknown exceptions and print the ExceptionMessage to a label on the site --> nothing happened
Tried it with(out) a ThrobberImage...
Many other tipps that did not work...
So, i hope we will find a solution together in this community. Heres my markup:
<%# Page Title="New Download" Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="NewDownload.aspx.cs" Inherits="Internals_NewDownload" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="Server">
<ajax:ToolkitScriptManager ID="ToolkitscriptManager" runat="server"> </ajax:ToolkitScriptManager>
<h1>Create a new Download</h1>
<ajax:AjaxFileUpload ID="FileUpload" runat="server" ThrobberID="ThrobberLabel" OnUploadComplete="FileUpload_UploadComplete" />
<asp:Label ID="ThrobberLabel" runat="server" Style="display: none;"><img alt="UploadingPicture" title="Please wait while uploading..." src='<%= Constants.DomainString + "/Data/Images/loading-small.gif" %>' /></asp:Label>
<asp:Label ID="DownloadLabel" runat="server"></asp:Label>
</asp:Content>
And this is my CodeBehind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Internals_NewDownload : System.Web.UI.Page
{
private string m_LanguageCode;
protected void Page_Load(object sender, EventArgs e)
{
if (RouteData.Values.ContainsKey("LanguageCode"))
m_LanguageCode = RouteData.Values["LanguageCode"].ToString();
//if (IsPostBack)
// return;
if (!User.IsInRole("Administrator") && !User.IsInRole("Kunde") && !User.IsInRole("Mitarbeiter"))
Response.Redirect(Constants.DomainString + "/PermissionDenied.aspx");
Session[Constants.NonGlobalizedString] = true;
Session[Constants.MenuInfoSession] = new ClsMenuInfo("NewDownload");
}
protected void FileUpload_UploadComplete(object sender, AjaxControlToolkit.AjaxFileUploadEventArgs e)
{
try
{
string filePath = "~/upload/" + e.FileName;
DownloadLabel.Text = filePath;
}
catch (Exception ex)
{
DownloadLabel.Text = ex.Message;
}
}
}
Please, if you have ANY idea, do not hesitate to let me know it. I am very confused as i think that i just did in that howtos i found on the internet...
Thanks in advance!
Take into account that AjaxFileUpload control use contextkey QueryString parameter to detect own postback. I believe the reason of you issue is that this parameter lost in result of rewriting url.
I'm not expert in applying routing but in my opinion you need to register contextkey parameter in routing tables and tweak AjaxControlToolkit sources to use RouteData instead of Request.QueryString for retrieving it value.
Check this link for more info: AjaxControlToolkit Source Code

Resources