Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

asynchrounous webservice method and AJAX 1

Status
Not open for further replies.

mmy1981

Programmer
Apr 2, 2007
164
BE
Hi,

I'm having problems with an asp.net application and an existing webservice (with Async methods). Generally, the code works like this:

1) the user starts a 'session' (= a connection to a PBX / call center).
2) a webservice method is called to listen for all events (call center agent loggin in, setting a pause activity, ...). This method is called GetEvents (will raise GetEventsCompleted when something is received).
3) once GetEventsCompleted is raised, the user should do a new request for new events. If not, an "are you alive" event is raised (in the GetEventsCompleted sub). If the (getEvents method) isn't launched within 60sec, the session gets disconnected automatically.

At this moment, I succeed in
1) starting the session (I call the GetEvents method)
2) I receive the first event in getEventsCompleted (agent = ready)
3) session stops because I don't launch a new GetEvents method and the "are you alive" event isn't answered.

So, now I try to call the GetEvents method again when entering the GetEventsCompleted code. This seems to work. Every time I receive an event, I tell the application to wait for new events. Like expected, the webpage keeps loading...

But...I placed a textbox in an UpdatePanel, hoping this textbox would show the last event. However, the box stays empty. (the page itself doesn't seem to keep loading, because I'm using the UpdatePanel). Debugging shows the session stays open (which is ok). The UpdatePanel has the property updateMode="always" (also tried with conditional & updating the panel by code)

Anybody know how to solve this problem? Below, the actual (relevant) code... The async methodes and events work correctly in a windows form application, but there I don't have to deal with postbacks, ...

ASP.NET code:
Code:
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
    
    <div>
    
    <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Always">
        <ContentTemplate>
            <asp:button ID="btnStartSession" runat="server" Text="start session" />    
            event: <asp:TextBox ID="txtEvent" runat="server" TextMode="MultiLine" Height="200px" Width="500px"></asp:TextBox><br />
            agent event: <asp:TextBox ID="txtAgentEvent" runat="server" TextMode="MultiLine" Height="200px" Width="500px"></asp:TextBox><br />
        </ContentTemplate>
    </asp:UpdatePanel>
    
    <asp:TextBox ID="txtInfo" runat="server"></asp:TextBox>

code behind:
Code:
    Private Sub btnStartSession_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnStartSession.Click

        NASWebServiceProxy.GetEvent01Async(Session("applicationID"), False)
    End Sub

    Private Sub NASWebServiceProxy_GetEvent01Completed(ByVal sender As Object, ByVal e As NASWebServiceProxy.GetEvent01CompletedEventArgs) Handles NASWebServiceProxy.GetEvent01Completed

        Try
'fill txtbox with event info
txtEvent.Text = Now.ToLongTimeString() & .....
        Catch ex As Exception
...
        End Try

NASWebServiceProxy.GetEvent01Async(Session("applicationID"), False)

    End Sub
 
The async methodes and events work correctly in a windows form application, but there I don't have to deal with postbacks
the desktop environment is so drastically different than the web you can't begin to compare the two. the biggest difference, statefulness. the desktop has state, the web is stateless.

I think the problem here is there is no connection between starting the async call and completing it. when asp.net receives the request it goes through the asp.net pipeline. since this is webforms it then goes through the webforms page lifecycle. btnStartSession_Click is called, the proxy is then called, btnStartSession_Click exited. the life cycle and pipeline continue on, a request is sent back to the client.

meanwhile the async completes, but the server has already returned a response to the client. there for the results are discarded.

try making the proxy call synchronously and things should work as expected.

if you are trying to improve throughput or create a responsive UI then drop the heavy webforms server controls and especially the update panel. instead opt for simple html controls and ajax/json requests this will improve the throughput and user experience.

Jason Meckley
Senior Programmer

faq855-7190
faq732-7259
My Blog
 
thanks for the quick reply. Indeed, a windows form and webapplication are completely different, but this was to indicate that I was sure the services work.

However, I'm not sure the results are discarted in the webapp because the response is already sent to the client. When debuggin, I see the variables are filled with the correct values.

If I don't launch a new GetEvent method (when receiving the 1st event), data is shown in the browser. When I use a button to launch a new request, the next received event is also showed...

A test with a synchronous call was ok, but this has to happen at least once a minute (to reply at the "are you alive" event). Maybe with a timer...but the user has to be able to keep using the webpage. The asp controls are for testing purpose at this moment. Later, I can use HTML controls if possible (and hopefully, I can learn more about ajax/json because at this moment the ajax part is automatically done using the scriptmanager & updatepanel)
 
so the GetEvent method works on page load, but not on button click? is that correct?

Jason Meckley
Senior Programmer

faq855-7190
faq732-7259
My Blog
 
try this
Code:
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" UseChildrenAsTriggers="true">
also txtInfo won't get updated, because it's not contained within the update panel. not sure if you are expecting this behavior or not.

Once you do get this working, switching over to ajax/json will mean discarding all this work. right now you are leveraging the features of webforms to most, if not all, of the html rendering for you. this won't be available if you removed the update panel.

Jason Meckley
Senior Programmer

faq855-7190
faq732-7259
My Blog
 
sorry if it's confusing. In the page load, I don't call the method.

The first time I call GetEvent (when clicking the start button), I receive the events.

In the GetEventCompleted sub I tell: display the event in the textbox. When this is done, launch the GetEvent method again. Doing this last action, I stay in a loop (give me the events & read the events).

However, when using this loop, the results aren't showed on the sreen (never, not even after the 1st click on the start button).

When I don't use this loop, the 1st event is shown on the screen. Now, when I use a 2nd test button to call the GetEvent method, the next received event is also shown on the screen...

ps. when using the loop, the events won't show on the screen, but they are read (I did a test -> writing all the events to a txt file).
 
edit, indeed...txtInfo is just for testing purposes.
 
OK, now i follow you. the subsequent calls to GetEvent from the completed event will never be sent to the client. there is no request asking for these updates.

in fact these subsequent calls are not happening within an http request at all, so there is currently no way to get this information back to the client.

to resolve this
1. add a timer to the webform
2. use the timer's change event to trigger the update panel
3. remove the GetEvent call from the GetEventCompleted method.

Jason Meckley
Senior Programmer

faq855-7190
faq732-7259
My Blog
 
hmm, sorry don't understand this.

=>"in fact these subsequent calls are not happening within an http request at all, so there is currently no way to get this information back to the client."

Ok, I'm not launching the request by clicking a button or so. But by calling the method by code, in the GetEventsCompleted sub, I tell to fill the textbox with the results (txtEvent.Text = ...)?

But no problem if I should use a timer. However, maybe I'm wrong with this... I added a timer with a 5sec interval. In the tick event I say UpdatePanel1.Update (or I use the <trigger> in the UpdatePanel)

At this moment, nothing changes (seems normal, caus I don't ask for new events). If I use
Code:
NASWebServiceProxy.GetEvent01Async(Session("applicationID"), False)
in the tick event, the same problem occurs (no txtbox updated). I think this is the same as using this line of code in thet GetEventsCompleted sub, not?
 
first there is the asp.net pipeline. then there is the webforms page lifecycle. a crude overview is

1. request comes in
2. asp.net processes request and passes it to webforms
3. webforms goes through the page life cycle
4. the start button handler is called
5. the proxy to get events is called
6. the result of get events is rendered
7. the webforms page life cycle completes
8. asp.net sends a response

all of that happens with an http context. a single request/response.
in step 6 you continue to call get events. but there is no request/response to render the results back to the client.

Now for the timmer. the timmer change/tick handler would have the same code as the start button handler. post the code and markup and we should be able to get this working.

Jason Meckley
Senior Programmer

faq855-7190
faq732-7259
My Blog
 
ok...I can understand the issue with step 6...
Can't get the timer to work correctly though (the page keeps loading, but won't update the txtboxes).

Below is my code. Hope it's not to complicated. If so, I'll delete the 'obsolete' code...
Code:
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
    <asp:Timer ID="Timer1" runat="server" Interval="5000" Enabled="false"></asp:Timer>
    
    <div>
    
    <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="true">
        <ContentTemplate>
            <asp:button ID="btnStartSession" runat="server" Text="start session" Width="150px" /><br />    
            event: <br />
            <asp:TextBox ID="txtEvent" runat="server" TextMode="MultiLine" Height="200px" Width="500px"></asp:TextBox><br />

            agent event: <br />
            <asp:TextBox ID="txtAgentEvent" runat="server" TextMode="MultiLine" Height="200px" Width="500px"></asp:TextBox><br />
        </ContentTemplate>
    </asp:UpdatePanel>

    <asp:Button ID="btnMakePrivateCall" runat="server" Text="make private call" Width="150px" /><br />        
    <asp:Button ID="btnLeesEventsAsynchroon" runat="server" Text="get events asynchroon" Width="150px" /><br />
    <asp:Button ID="btnleesEventsSynchroon" runat="server" Text="get events synchyroon" Width="150px" /><br />
    <asp:Button ID="btnStopSession" runat="server" Text="stop session" Width="150px" /><br />
    
    application id: <asp:TextBox ID="txtApplicationID" runat="server" /><br />
    foutmelding: <asp:TextBox ID="txtFoutmelding" runat="server" Width="800px"></asp:TextBox><br />
   
   
   </div>
    </form>
</body>

Code:
    Private Sub btnStartSession_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnStartSession.Click

        'NASWebServiceProxy.PreAuthenticate = True

        'credentials to connect to the webservice
        Dim myCredentials As System.Net.NetworkCredential = New System.Net.NetworkCredential
        myCredentials = System.Net.CredentialCache.DefaultCredentials
        Session("myCredentials") = myCredentials
        NASWebServiceProxy.Credentials = Session("myCredentials")

        '1st action: GetInitialUserData / wich events do we want to receive?
        Dim myUserData As UserData
        Dim requiredEvents As List(Of ClientEventType) = New List(Of ClientEventType)
        Dim requiredEvent As ClientEventType = New ClientEventType
        requiredEvents.Add(ClientEventType.AreYouAlive)
        requiredEvents.Add(ClientEventType.Agent)

        myUserData = NASWebServiceProxy.GetInitialUserData(requiredEvents.ToArray, 0)
        Session("applicationID") = myUserData.ClientApplicationId
        txtApplicationID.Text = Session("applicationID")

        'tell what phone to use
        NASWebServiceProxy.SetUserPhoneEx01(Session("applicationID"), "9910")

        'GetEvent01Async to read the events
        NASWebServiceProxy.GetEvent01Async(Session("applicationID"), False)

        Timer1.Enabled = True
    End Sub

    Private Sub NASWebServiceProxy_GetEvent01Completed(ByVal sender As Object, ByVal e As NASWebServiceProxy.GetEvent01CompletedEventArgs) Handles NASWebServiceProxy.GetEvent01Completed

        Try

            Dim ontvangen_clientevents() As ClientEvent
            ontvangen_clientevents = e.Result

            For Each ClientEvent As ClientEvent In ontvangen_clientevents
                txtEvent.Text = txtEvent.Text & Now.ToLongTimeString & " " & ClientEvent.ToString & vbCrLf

                Select Case ClientEvent.EventType

                    Case ClientEventType.Agent

                        Dim agent As Agent
                        agent = DirectCast(ClientEvent, Agent)
                        txtAgentEvent.Text = Now.ToLongTimeString & " " & vbCrLf & "CurrentActivity = " & agent.CurrentActivity.ToString & vbCrLf & _
                                            "CurrentActivityCode = " & agent.CurrentActivityCode.ToString & vbCrLf & _
                                            "CurrentStatus = " & agent.CurrentStatus.ToString & vbCrLf

                    Case ClientEventType.AreYouAlive

                        txtEvent.Text = txtEvent.Text & "are you alive" & vbCrLf

                End Select

            Next

        Catch ex As Exception
            txtFoutmelding.Text = "GetEvent: " & ex.Message.ToString
        End Try

        UpdatePanel1.Update()

        'NASWebServiceProxy.Credentials = Session("myCredentials")
        'NASWebServiceProxy.GetEvent01Async(Session("applicationID"), False)

    End Sub

    Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        UpdatePanel1.Update()
        NASWebServiceProxy.Credentials = Session("myCredentials")
        NASWebServiceProxy.GetEvent01Async(Session("applicationID"), False)
    End Sub
 
edit: appreciating the help, I'll do some extra tests if needed.

But I'm currently reading the documentation of the webservice from the manufacturer. They also say to use DHTML and Javascript to invoke the webmethods. "Resulting in smooth changes in the webpage, without flicker". Other methods (like my tests) are also possible, but there are some drawbacks (difficult to show the events on screen, ... like the problems I'm having here...)
 
1. remove UpdatePanel1.Update(). this should be be happening automatically.
2. move
Code:
Dim myCredentials As System.Net.NetworkCredential = New System.Net.NetworkCredential
myCredentials = System.Net.CredentialCache.DefaultCredentials
Session("myCredentials") = myCredentials
to the Session_Begin (or Session_Start) handler in Global.asax.
If you project doesn't contain a global file, add one.
This helps clean up the code and ensures the credentials are present whenever you need them.
3. define the async trigger for the update panel
Code:
<asp:UpdatePanel ...UpdateMode="Conditional" ChildrenAsTriggers="true">
  <Triggers>
     <asp:AsyncPostBackTrigger controlid="Timer1" eventname="Tick" />
  <Triggers>

Jason Meckley
Senior Programmer

faq855-7190
faq732-7259
My Blog
 
ok...seems to work, a star for you :)

but like you said before, it's not ideal. The timer has to check every second (to make it look like realtime). Stopping the session doesn't work very well (I think it gets interrupted by the timer)...

I guess I have to look into javascript and other techniques...
 
The timer has to check every second (to make it look like realtime)
so have it check in smaller intervals. like every 30 seconds or every x minutes. this is acceptable for a web UI, even a desktop UI really.

Stopping the session doesn't work very well
what do you mean? i don't see where the session ends in this code. and by making repeated ajax calls via the timer you will keep the user's session alive, so it won't time out.

I guess I have to look into javascript and other techniques...
you are using javascript. that's how the client is requesting updates from the server. there are no other options with web development. you have full requests and ajax requests. And an ajax request is still just a request, the only difference is the browser knows knot to refresh the entire window and instead allows you to decide what to do when the request is complete/successful/errors.

Jason Meckley
Senior Programmer

faq855-7190
faq732-7259
My Blog
 
so have it check in smaller intervals. like every 30 seconds or every x minutes. this is acceptable for a web UI, even a desktop UI really.
Eventually, this application (well, the final application - because this was for testing purposes only) will have to display changes almost immediately... So the timer interval has to be seconds or 5sec max

i don't see where the session ends in this code. and by making repeated ajax calls via the timer you will keep the user's session alive, so it won't time out.
Exactly, the session stay's alive. I'll look into the stop procedure (wasn't posted in the previous example). This is done by calling a webservice that release resources (a connection to the PBX / call center)

I guess I have to look into javascript and other techniques...
Well, I don't know what other options there are. I saw something about using Javascript and Dynamic HTML / 'Webservice behaviour' (a javascript component to act as a SOAP parser)
 
Eventually, this application (well, the final application - because this was for testing purposes only) will have to display changes almost immediately... So the timer interval has to be seconds or 5sec max
I would bet that with more knowledge and really understanding what the users need and why they need it, this window can be expanded. besides, they have the option to click "Update Now", or you can offer them that option.

the truth is, there are very few operations which require true real time processing; and for those applications that do
1. they aren't web apps
2. they aren't written in .net
Well, I don't know what other options there are. I saw something about using Javascript and Dynamic HTML / 'Webservice behaviour' (a javascript component to act as a SOAP parser)
SOAP is needlessly complex compared to ajax and json. it's like html & xml with a different protocal, but the same principles apply. Dynamc HTML is a fancy term to leverage html, js and css.

Jason Meckley
Senior Programmer

faq855-7190
faq732-7259
My Blog
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top