ASP.Net: IHttpAsyncHandler and IRequiresSessionState not working - asynchronous

I have implemented an IHttpAsyncHandler. I am making about 5 different AJAX calls from a webpage that has widgets to that handler.
One of those widgets takes about 15 seconds to load(because of a large database query) the others should all load in under a second. The handler is responding in a synchronous manner.
I am getting very inconsistent results. The ProcessRequest method is using Session and other class level variables. Could that be causing different requests to use the same thread instead each there own?
I'm getting this...
Request1 ---> response 1 sec
Request2 ---> response 14 sec
Request3 ---> response 14.5 sec
Request4 ---> response 15 sec
Request5 ---> response 15.5 sec
but I'm looking for something more like this...
Request1 ---> response 1 sec
Request2 ---> response 14 sec
Request3 ---> response 1.5 sec
Request4 ---> response 2 sec
Request5 ---> response 1.5 sec
Without posting too much code my implementation of the IHttpAsyncHandler methods are pretty standard.
private AsyncProcessorDelegate _Delegate;
protected delegate void AsyncProcessorDelegate(HttpContext context);
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context,
AsyncCallback cb, object extraData)
{
_Delegate = new AsyncProcessorDelegate(ProcessRequest);
return _Delegate.BeginInvoke(context, cb, extraData);
}
void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
{
_Delegate.EndInvoke(result);
}
Putting a debug break point in my IHttpAsyncHandler.BeginProcessRequest method I can see that the method isn't being fired until the last Process is complete.
Also my machine.config has this entry...
processModel autoConfig="true" with no other properties set.
I'm calling the handler like this...
$.ajax(
{
type: "GET",
url: "../HTML/HtmlHandler.ashx",
cache: true,
dataType: "text",
data: { html: name },
success: function(html) {
//$(function() {
//console.log(tabname);
//console.log("msg:" + msg);
$("#" + name + "holder").html(html);
//checkAllLoaded();
ClientHome_init('');
//});
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
$("#" + name + "holder").html("<span>Error retrieving widget.</span>");
//console.log("error:" + tabname);
//checkAllLoaded();
}
}
What else do I need to check for?

Just incase someone else has this problem changing IRequiresSessionState to IReadOnlySessionState fixed the problem for me.

Your problem here is probably not with your server code. The nature of javascript is that it is synchronous. Even when you are using asynchronous AJAX requests, I find that javascript will rarely allow you to make two HTTP requests at the same time.

Related

Push Data To Client Using SignalR

I'm sorry for potentially creating a duplicate thread here, but I simply cannot get my web application to do what I need by following the other examples I've found.
My goal is to do one of the following:
OPTION 1 - IDEAL SOLUTION
Fetch data from a database and update the UI on a web page ONLY when changes are made to the data being displayed on the web page. For example, if a user is viewing a service ticket, I don't want to update the UI on that page unless that ticket is changed.
OPTION 2 - ACCEPTABLE SOLUTION
Fetch data from a database every x seconds and use that data to update the UI on a web page.
My current implementation of Option 2 is below. It involves sending an asynchronous HTTP request every 60 seconds to fetch the data:
// start checking for new messages every 60 seconds
setInterval(function () {
$.ajax({
async: true,
type: "POST",
contentType: "application/json; charset=utf-8;",
url: "/AJAX_Handlers/CheckForNewMessages.ashx",
dataType: "json",
success: function (Result) {
var new_message_received = Result[0]["NewMessageReceived"];
if (new_message_received) {
$("#DIVMessageReminder").html("<strong>You have " + num_new_messages + " new message(s).</strong>");
$("#DIVMessageReminder").show();
}
else {
$("#DIVMessageReminder").hide();
}
}
});
}, 60000);
Rather than sending an HTTP request every 60 seconds, I would like to use SignalR to push that data to the client every 60 seconds.
As a simple example, I have created the following Hub with a method to get the current time on the server:
Imports Microsoft.AspNet.SignalR
Public Class ServerTimeHub
Inherits Hub
Public Sub GetServerTime()
Dim current_time As String = Now.ToString()
Clients.All.updateTime(current_time)
End Sub
End Class
And a basic textbox:
<input id="TXTLongPollingTest" type="text" class="form-control" />
And my client-side code:
var hub = $.connection.serverTimeHub;
hub.client.updateTime = function (new_time) {
$("#TXTLongPollingTest").val(new_time);
}
$.connection.hub.start().done(function () {
alert("connected to the SignalR hub");
hub.getServerTime();
}).fail(function (err) {
alert("failed to connect to SignalR hub: " + err);
});
At first I tried getting it to fetch the server time just once. My code will successfully connect to the hub, but then it throws an error saying "Uncaught TypeError: hub.getServerTime is not a function". That's the first problem I haven't been able to overcome.
The second problem is: How can I get the hub to send the current time to the client on a regular interval such as every 1 second?
Here is what I have done to achieve something similar. Essentially fetching data from the database and broadcasting to clients every 30 seconds.
In my global.asax.cs I have this to ensure whenever my website is has started/restarted it will kick off my repeater:
protected void Application_Start(object sender, EventArgs e)
{
GetTeamData.TeamDataRepeater();
}
In my GetTeamData.cs I have a timer that is set to run every 30 seconds
public class GetTeamData
{
static Timer TeamDataTimer = new Timer();
public static void TeamDataRepeater()
{
TeamDataTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimedEvent_TeamDataBroadcaster);
TeamDataTimer.Interval = 30000; //30 Seconds
TeamDataTimer.Start();
}
public static void OnTimedEvent_TeamDataBroadcaster(Object sender, ElapsedEventArgs e)
{
updateFirstRow();
}
public static void updateFirstRow()
{
IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MsgHub>();
hubContext.Clients.All.pushMyData(mydata1, mydata2, mydata3);
}
}
My java script for the client has:
//I have already started my connection
$(function () {
var chat = $.connection.msgHub;
chat.client.pushMyData = function (mydata1, mydata2, mydata3)
{
//Do something with the returned data now
}
});
Note that I have removed some things such as use of try/catch just to give you an example.
Hope that helps.

Changing my code to use async methods instead of sync methods will force my WebClient to never timeout (20 minute++)

I have 2 asp.net MVC web applications , as follow:-
ApplicationA . which is an Asp.net mvc-4 deployed under iis-8.
ApplicationB. which is an Asp.net mvc-5 deployed under iis-8.
now inside my ApplicationA i have the following method,which will call an action method (home/sync) on applicationB , as follow:-
public List<Technology> GetTechnology(int? currentfiltertype)
{
try
{
using (WebClient wc = new WebClient())
{
string url = currentURL + "home/sync?filtertype=" + currentfiltertype;
wc.Headers.Add("Authorization", token);
string json = wc.DownloadString(url);
List<Technology> result = JsonConvert.DeserializeObject<List<Technology>>(json);
return result;
}
}
catch (Exception e){}
}
now i have noted that when the WebClient calls the action method, and the method did not receive a response within around 2 minutes it will raise a timeout exception. But since the home/sync action method on web application B needs around 30 minutes to complete.. so i was searching for a solution to extend the web-client timeout period. so i tried changing my code to use async methods as follow,mainly by replacing wc.DownloadString with wc.DownloadStringTaskAsync as follow:-
public async Task<List<Technology>> GetTechnology(int? currentfiltertype)
{
try
{
using (WebClient wc = new WebClient())
{
string url = currentURL + "home/sync?filtertype=" + currentfiltertype;
wc.Headers.Add("Authorization", token);
string json = await wc.DownloadStringTaskAsync(url);
List<Technology> result = JsonConvert.DeserializeObject<List<Technology>>(json);
return result;
}
}
catch (Exception e) {}
}
and now seems the WebClient will never expired ... i tried calling the action method and the web client keep waiting for a response for more than 20 minutes without raising any timeout exception, then it received the response from web applicationB and everything worked well..
so can anyone advice why changing my code to use async methods as shown in the above code, caused the WebClient to not timeout ?? i can not understand the relation between using async logic and extending the timeout period for the web-client (not sure if the WebClient will ever timeout inside async methods!!)?
can anyone advice why changing my code to use async methods as shown in the above code, caused the WebClient to not timeout ??
The answer is a bit convoluted: WebClient is based on WebRequest, and HttpWebRequest's Timeout property is only honored for synchronous requests.
(noy sure if the WebClient will ever timeout inside async methods!!)?
It does not directly support asynchronous timeouts, but it does support (its own kind of) cancellation, which you can trigger after a timer.

SignalR Long Running Process

I have setup a SignalR hub which has the following method:
public void SomeFunction(int SomeID)
{
try
{
Thread.Sleep(600000);
Clients.Caller.sendComplete("Complete");
}
catch (Exception ex)
{
// Exception Handling
}
finally
{
// Some Actions
}
m_Logger.Trace("*****Trying To Exit*****");
}
The issue I am having is that SignalR initiates and defaults to Server Sent Events and then hangs. Even though the function/method exits minutes later (10 minutes) the method is initiated again ( > 3 minutes) even when the sendComplete and hub.stop() methods are initiated/called on the client prior. Should the user stay on the page the initial "/send?" request stays open indefinitely. Any assistance is greatly appreciated.
To avoid blocking the method for so long, you could use a Taskand call the client method asynchronously.
public void SomeFunction(Int32 id)
{
var connectionId = this.Context.ConnectionId;
Task.Delay(600000).ContinueWith(t =>
{
var message = String.Format("The operation has completed. The ID was: {0}.", id);
var context = GlobalHost.ConnectionManager.GetHubContext<SomeHub>();
context.Clients.Client(connectionId).SendComplete(message);
});
}
Hubs are created when request arrives and destroyed after response is sent down the wire, so in the continuation task, you need to create a new context for yourself to be able to work with a client by their connection identifier, since the original hub instance will no longer be around to provide you with the Clients method.
Also note that you can leverage the nicer syntax that uses async and await keywords for describing asynchronous program flow. See examples at The ASP.NET Site's SignalR Hubs API Guide.

How to lazily stream using HttpServletRequest#getPart(name)

I'm using Jetty 9's implementation of HttpServletRequest#getPart(name), and it appears to eagerly processes the entire request (or at least the Part in question) before continuing, even though the resulting Part exposes a getInputStream() method.
Is there a way for getPart to return immediately, and leave request streaming to the resulting Part's InputStream?
For reference, here's the relevant snippet from my Servlet implementation:
override def doPost(req: HttpServletRequest, res: HttpServletResponse) {
println("ABOUT TO GET PART") // this happens immediately
val file = req.getPart("file")
println("GOT PART") // it takes a long time to get here if the upload is large
It's wicked tedious, but this can be done using MultipartStream from commons-fileupload:
try {
MultipartStream multipartStream = new MultipartStream(input, boundary);
boolean nextPart = multipartStream.skipPreamble();
OutputStream output;
while(nextPart) {
String header = multipartStream.readHeaders();
// process headers
// create some output stream
multipartStream.readBodyData(output);
nextPart = multipartStream.readBoundary();
}
} catch(MultipartStream.MalformedStreamException e) {
// the stream failed to follow required syntax
} catch(IOException e) {
// a read or write error occurred
}
This requires the use of the InputStream from HttpServletRequest#getInputStream(), and the boundary delimiter encoded in the HTTP request's content type:
Content-Type: multipart/form-data; boundary=------------------------bd019839518ca918

Response.Write() in WebService

I want to return JSON data back to the client, in my web service method. One way is to create SoapExtension and use it as attribute on my web method, etc. Another way is to simply add [ScriptService] attribute to the web service, and let .NET framework return the result as {"d": "something"} JSON, back to the user (d here being something out of my control). However, I want to return something like:
{"message": "action was successful!"}
The simplest approach could be writing a web method like:
[WebMethod]
public static void StopSite(int siteId)
{
HttpResponse response = HttpContext.Current.Response;
try
{
// Doing something here
response.Write("{{\"message\": \"action was successful!\"}}");
}
catch (Exception ex)
{
response.StatusCode = 500;
response.Write("{{\"message\": \"action failed!\"}}");
}
}
This way, what I'll get at client is:
{ "message": "action was successful!"} { "d": null}
Which means that ASP.NET is appending its success result to my JSON result. If on the other hand I flush the response after writing the success message, (like response.Flush();), the exception happens that says:
Server cannot clear headers after HTTP headers have been sent.
So, what to do to just get my JSON result, without changing the approach?
This works for me:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void ReturnExactValueFromWebMethod(string AuthCode)
{
string r = "return my exact response without ASP.NET added junk";
HttpContext.Current.Response.BufferOutput = true;
HttpContext.Current.Response.Write(r);
HttpContext.Current.Response.Flush();
}
Why don't you return an object and then in your client you can call as response.d?
I don't know how you are calling your Web Service but I made an example making some assumptions:
I made this example using jquery ajax
function Test(a) {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "TestRW.asmx/HelloWorld",
data: "{'id':" + a + "}",
dataType: "json",
success: function (response) {
alert(JSON.stringify(response.d));
}
});
}
And your code could be like this (you need to allow the web service to be called from script first: '[System.Web.Script.Services.ScriptService]'):
[WebMethod]
public object HelloWorld(int id)
{
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.Add("message","success");
return dic;
}
In this example I used dictionary but you could use any object with a field "message" for example.
I'm sorry if I missunderstood what you meant but I don't really understand why you want to do a 'response.write' thing.
Hope I've helped at least. :)

Resources