How to display asynchronous results that are primarily included in an asp.netweb application?

I need to send three asynchronous requests in three class files, 3 times the response time of the requests, the first 2 seconds, the second 7 seconds, and the third 4 seconds, now I need to display the first response in the browser for 2 seconds and after 2 seconds display the third answer and finally display the second answer , but now my results all the answers are displayed simultaneously after the completion of the three answers, please give me some suggestion, it is very urgent, please .....

my code

public delegate string AsyncMethodCaller(string name); public delegate string AsyncMethodCallertest(string name); public delegate string NatilusAsyn(string name); 

button click event

  AsyncMethodCaller caller = new AsyncMethodCaller(ps.PennStarService); IAsyncResult result = caller.BeginInvoke(txtFirst.Text, null, null); NatilusAsyn caller123 = new NatilusAsyn(cs.PennStarService); IAsyncResult result123 = caller123 .BeginInvoke(txtthird.Text, null, null); AsyncMethodCallertest cltest = new AsyncMethodCallertest(ps.testHi); IAsyncResult tetsresult = cltest.BeginInvoke(txtSecond.Text, null, null); lblFirst.Text = caller.EndInvoke(result); lblSecond.Text = cltest.EndInvoke(tetsresult); lblthird.Text = caller123.EndInvoke(result123); 

thank u Hemanth

+8
asynchronous
source share
1 answer

I think the root of the problem is to understand what is happening with the ASP.Net request.

Each page has a life cycle that includes an event pipeline, for more information check this answer . Each request is processed by the workflow from the AppDomain of the current application. A response will not be sent to the user until the page pipeline is complete.

About streams:

The number of simultaneous threads available can be configured in machine.config . The key point to understand is that this number of threads is fixed, which means that when the maximum number of simultaneous threads is reached, subsequent requests will be queued, the number of requests that can be queued, limited by server memory.

When a worker thread causes a long labor-intensive operation, you block this thread until the operation is completed, which means again, if there are several simultaneous users, potentially all available threads can be blocked, which forces new requests to be queued and, in the worst case, causing an error 503 - Service Unavailable.

A way to prevent this is to call such methods in the background thread. Like your code , but the behavior is not what you expect in this case, your code is waiting for the threads to finish to complete the page request , which is the reason you get the result at the same time (at the end of the request).

For more information on asynchronously executing asp.net pages, see this great article.

Now, to get the desired results:

(This is a complete working example, in this example I use Rx - Reactive Programming to use lengthy laborious methods in a new thread, you can change this to use a different structure if you want, I prefer to use Rx because I feel more comfortable with API)

Using PageMethods

Code for

  [WebMethod] public static string Execute1() { JavaScriptSerializer j = new JavaScriptSerializer(); string r = string.Empty; var o = Observable.Start(() => { Thread.Sleep(2000); r = "My Name1: " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); }, Scheduler.NewThread); o.First(); r += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); r = j.Serialize(new { res = r }); return r; } [WebMethod] public static string Execute2() { JavaScriptSerializer j = new JavaScriptSerializer(); string r = string.Empty; var o = Observable.Start(() => { Thread.Sleep(7000); r = "My Name2: " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); }, Scheduler.NewThread); o.First(); r += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); r = j.Serialize(new { res = r }); return r; } [WebMethod] public static string Execute3() { JavaScriptSerializer j = new JavaScriptSerializer(); string r = string.Empty; var o = Observable.Start(() => { Thread.Sleep(4000); r = "My Name3: " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); }, Scheduler.NewThread); o.First(); r += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); r = j.Serialize(new { res = r }); return r; } 

Aspx

 .... <script type="text/javascript" src="Scripts/jquery-1.7.2.min.js"></script> .... <asp:ScriptManager runat="server" /> <input type="button" id="callAsync" name="callAsync" value="Call Async" /> <div id="first"></div> <script type="text/javascript"> function onsuccess1(msg) { var result = Sys.Serialization.JavaScriptSerializer.deserialize(msg.d); var h = $("#first").html(); $("#first").html( h + "<br/>&nbsp;&nbsp;&nbsp;&nbsp;Result: " + result.res); } function onerror1(xhr) { alert(xhr.responseText); } function callMyMethod(url, mydata, onsuccess, onerror) { var h = $("#first").html(); $("#first").html(h + "<br/>&nbsp;&nbsp;Calling Method: " + new Date()); return $.ajax({ cache: false, type: "POST", async: true, url: url, data: mydata, contentType: "application/json", dataType: "json", success: function (msg) { onsuccess(msg); }, error: function (xhr) { onerror(xhr); } }); } $(document).ready(function () { $("#callAsync").click(function () { var h = $("#first").html(); $("#first").html(h + "<br/>New call: " + new Date()); callMyMethod("DynamicControls.aspx/Execute1", "{}", function (data) { onsuccess1(data); }, function (data) { onerror1(data); }); callMyMethod("DynamicControls.aspx/Execute2", "{}", function (data) { onsuccess1(data); }, function (data) { onerror1(data); }); callMyMethod("DynamicControls.aspx/Execute3", "{}", function (data) { onsuccess1(data); }, function (data) { onerror1(data); }); }); }); </script> 

Exit

This code generates the following:

 New call: Fri Jun 22 02:11:17 CDT 2012 Calling Method: Fri Jun 22 02:11:17 CDT 2012 Calling Method: Fri Jun 22 02:11:17 CDT 2012 Calling Method: Fri Jun 22 02:11:17 CDT 2012 Result: My Name1: 6/22/2012 2:11:19 AM Background thread: 38 Main thread: 48 Result: My Name2: 6/22/2012 2:11:26 AM Background thread: 50 Main thread: 48 Result: My Name3: 6/22/2012 2:11:30 AM Background thread: 52 Main thread: 48 

As you can see, the code is not optimized, the main thread is blocked, the maximum number of seconds that we set is 7, but in this case, from the moment the server code is called (02:11:17) until the last answer is received (2:11: 30) 13 seconds. This is because by default, ASP.Net blocks the current Session object, which blocks the main thread. Since we are not using a session in this example, we can configure the page as follows:

 <%@ Page EnableSessionState="False" 

And a new conclusion:

 New call: Fri Jun 22 02:13:43 CDT 2012 Calling Method: Fri Jun 22 02:13:43 CDT 2012 Calling Method: Fri Jun 22 02:13:43 CDT 2012 Calling Method: Fri Jun 22 02:13:43 CDT 2012 Result: My Name1: 6/22/2012 2:13:45 AM Background thread: 52 Main thread: 26 Result: My Name3: 6/22/2012 2:13:47 AM Background thread: 38 Main thread: 49 Result: My Name2: 6/22/2012 2:13:50 AM Background thread: 50 Main thread: 51 

Now only 7 seconds have passed from the first method of the server method to the last received response without blocking the main thread =)

Change 1

If my understanding is correct, you need to pass some parameters to the methods and return data sets to fill labels and text fields.

To pass parameters to PageMethods, this is the way to do this:

Install the Nuget package:

Team class. This class will represent the parameters you want to send to the server method in post action

 public class ProcessXmlFilesCommand { public string XmlFilePath { get; set; } public ProcessXmlFilesCommand() { } } 

Instead of returning a DataSet , I think it would be easier and more convenient to return an IEnumerable , something like this:

  [WebMethod] public static IEnumerable<MyResult> ProcessXmlFiles(ProcessXmlFilesCommand command) { List<MyResult> results = new List<MyResult>(); var o = Observable.Start(() => { // here do something useful, process your xml files for example // use the properties of the parameter command results.Add(new MyResult { SomethingInteresting = DateTime.Now.ToString(), FilePath = command.XmlFilePath + "Processed" }); results.Add(new MyResult { SomethingInteresting = DateTime.Now.ToString(), FilePath = command.XmlFilePath + "Processed" }); results.Add(new MyResult { SomethingInteresting = DateTime.Now.ToString(), FilePath = command.XmlFilePath + "Processed" }); Thread.Sleep(2000); }, Scheduler.NewThread); o.First(); return results.AsEnumerable(); } 

The MyResult class represents the data you want to send back to the user.

 public class MyResult { public string SomethingInteresting { get; set; } public string FilePath { get; set; } } 

On the aspx page

 <script type="text/javascript" src="Scripts/jquery-1.7.2.min.js"></script> <script type="text/javascript" src="Scripts/json2.min.js"></script> <script type="text/javascript"> function processFiles() { var filePath = $("#filePath").val(); var command = new processFilesCommand(filePath); var jsonCommand = JSON.stringify(command); $.ajax({ cache: false, type: "POST", async: true, url: "CustomThreads.aspx/ProcessXmlFiles", data: "{'command':" + jsonCommand + "}", contentType: "application/json; charset=utf-8", dataType: "json", success: function (msg) { onFileProcessedSuccess(msg); }, error: function (exc) { onFileProcessedError(exc); } }); } function onFileProcessedSuccess(msg) { var response = msg.d; $.each(response, function (index, myResponse) { $("#<%:this.myLabel.ClientID %>").append(myResponse.SomethingInteresting + "<br/>"); }); } function onFileProcessedError(exc) { alert("Error: " + exc.responseText); } function processFilesCommand(filePath) { this.XmlFilePath = filePath; } $(document).ready(function () { $("#processFile").click(processFiles); }); </script> <input type="text" name="filePath" id="filePath" /> <input type="button" name="processFile" id="processFile" value="Process File" /> <br /><asp:Label ID="myLabel" runat="server" /> 

Edit 2

This is a simplified way.

 <%@ Page EnableSessionState="False" Language="C#" AutoEventWireup="true" CodeBehind="CustomThreadsSimple.aspx.cs" Inherits="WebApplication1.CustomThreadsSimple" %> .... <script type="text/javascript" src="Scripts/jquery-1.7.2.min.js"></script> .... <script type="text/javascript"> function makeCall(url, data) { $("#<%:this.lblMessage.ClientID %>").append("<br/>Initializing call: " + new Date()); $.ajax({ url: url, type: "POST", dataType: "json", contentType: "application/json; charset=utf-8;", async: true, cache: false, data: "{name:'" + data + "'}", success: function (msg) { $("#<%:this.lblMessage.ClientID %>").append("<br/>&nbsp;&nbsp;&nbsp;&nbsp;" + msg.d); }, error: function (exc) { alert(exc.responseText); } }); } $(function () { $("#startProcess").click(function () { makeCall("CustomThreadsSimple.aspx/Execute1", $("#<%: this.txtData1.ClientID %>").val()); makeCall("CustomThreadsSimple.aspx/Execute2", $("#<%: this.txtData2.ClientID %>").val()); makeCall("CustomThreadsSimple.aspx/Execute3", $("#<%: this.txtData3.ClientID %>").val()); }); }); </script> <asp:TextBox runat="server" ID="txtData1" /> <asp:TextBox runat="server" ID="txtData2" /> <asp:TextBox runat="server" ID="txtData3" /> <input type="button" name="startProcess" id="startProcess" value="Start execution" /> <asp:Label ID="lblMessage" runat="server" /> 

Code for

 public partial class CustomThreadsSimple : System.Web.UI.Page { [WebMethod] public static string Execute1(string name) { string res = string.Empty; Func<string, string> asyncMethod = x => { Thread.Sleep(2000); return "Res1: " + x +" " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); }; IAsyncResult asyncRes = asyncMethod.BeginInvoke(name, null, null); res = asyncMethod.EndInvoke(asyncRes); res += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); return res; } [WebMethod] public static string Execute2(string name) { string res = string.Empty; Func<string, string> asyncMethod = x => { Thread.Sleep(7000); return "Res2: " + x + " " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); }; IAsyncResult asyncRes = asyncMethod.BeginInvoke(name, null, null); res = asyncMethod.EndInvoke(asyncRes); res += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); return res; } [WebMethod] public static string Execute3(string name) { string res = string.Empty; Func<string, string> asyncMethod = x => { Thread.Sleep(4000); return "Res3: " + x + " " + DateTime.Now.ToString() + " Background thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); }; IAsyncResult asyncRes = asyncMethod.BeginInvoke(name, null, null); res = asyncMethod.EndInvoke(asyncRes); res += " Main thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); return res; } } 

Exit

enter image description here

+5
source share

All Articles