none
Can't make WCF service calls during Application Exit?

    Question

  • I've subscribed an event to the application exit event as follows:
                Application.Current.Exit += new EventHandler(Application_Exit);

    I've then implemented that method to perform a single WCF call to my service, essentially saving the user's most recent work. However, this call is not making it to the server in either IE or FF using Silverlight 2.0 beta 2. The same call works flawlessly any time other than during exit.

    1. Is there a better point to intercept in order to make this call?
    2. Is it being blocked by browser security or something in Silverlight?
    3. Does anybody see a solution that does not involve preventing them from leaving the page using one of the various "Are you sure you want to exit?" approaches that have been posted lately?


     

    Wednesday, July 09, 2008 7:44 PM

Answers

  • Hi:

      This feature request has been logged. I'll update here if any new information is available.

    Regards

    Friday, July 11, 2008 12:06 AM

All replies

  • As the documentation states "An Exit event handler should not include long-running, re-entrant, or cyclic code, such as resetting the Silverlight plug-in control's Source property", I'd expect that async calls are out of question.

     If you need to store user's work, you might consider to use isolated storage, and when user comes back, upload it to the server. Isolated storage works in app.exit event.

    Hope it helps.

    Ilkka

     

     

    Thursday, July 10, 2008 4:36 AM
  • I appreciate the long-running issues, but I'm not looking for any sort of response, I just want to fire a dispatch. Is there some way to make the call "OneWay" or no-reply? Isolated storage wouldn't really apply in this case since there's a good chance that the user may use a different computer on the next visit.

     

    Thursday, July 10, 2008 9:35 AM
  • Hi:

      This feature request has been logged. I'll update here if any new information is available.

    Regards

    Friday, July 11, 2008 12:06 AM
  • any update with this issue?? we are now in RTW.

     

    Thanks

    Wednesday, October 22, 2008 10:48 AM
  • I too am interested in this feature.

    Wednesday, October 22, 2008 11:12 AM
  • Well I am also looking for a answer for this kind of situation, Is there any way to call the database services or web services, if any user close the browser directly in silverlight application.

     Thanks for your reply in advanced.

    Thursday, November 13, 2008 5:34 AM
  • I subscribe to this issue too. A logoff action invoking a web service on application exit is such a common scenario ... we must have a way to do this! I believe I could invoke the web service without using the proxy and use IAsyncResult for waiting for the call completion.

    Saturday, November 15, 2008 9:20 AM
  • I'm joining the club. I want to record a logout in my database when the user closes the browser.

    Tuesday, January 06, 2009 10:39 PM
  • Any update on this feature??

    Thursday, January 15, 2009 3:34 AM
  • I'm also subscribing to this.

    I need to track logged in users and thus execute web service call if user closes browser window.

    Is it possible to send some sync notification to server like HTTP GET request in Exit event ?

     http://silverlight.net/forums/p/69833/168604.aspx#168604

     

    Sunday, February 01, 2009 4:43 AM
  • Any news on this ? This message thread is quite old and I am in this exact situation.

     

    Monday, February 02, 2009 7:41 AM
  • Hi,

    i need a solution for this problem too. Writing a silverlight/wcf application for my bachelor degree, it would be nice, if someone can help me out.

    Friday, February 06, 2009 4:40 AM
  • Just an update for this issue. Bad news is it's considered as by design because there is no mechenism to prevent a page from being unloaded. Good news is we probably can use XMLHttpRequest to workaround it.

    http://www.w3schools.com/ajax/ajax_browsers.asp


     

    Friday, February 06, 2009 5:44 AM
  • Just an update for this issue. Bad news is it's considered as by design because there is no mechenism to prevent a page from being unloaded. Good news is we probably can use XMLHttpRequest to workaround it.

    http://www.w3schools.com/ajax/ajax_browsers.asp

     

     Could you give an example on how you can have a last contact with the WCF service on the silverlight application exit ?


    Sunday, February 08, 2009 2:19 AM
  • Hi,

    Instead of do that in Application_Exit we can call web service in the body's onunload event. Here's a sample:

    aspx:

    <%@ Page Language="C#" AutoEventWireup="true" %>

    <%@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls"

    TagPrefix="asp" %>

    <!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" style="height:100%;">

    <head runat="server">

    <title>SilverlightApplication2</title>

    <script type="text/javascript">

    var block = true;

    function onSuccess(result) {

    block = false;

    }

    function Call() {

    var obj = new WcfService1.IService1();

    var q = obj.DoWork(onSuccess);while (block) { alert('Log to server.. Please wait..') }

    }

     

     

    </script> </head>

    <body style="height:100%;margin:0;" onunload="Call();">

    <form id="form1" runat="server" style="height:100%;" >

     

    <asp:ScriptManager ID="ScriptManager1" runat="server">

    <Services>

    <asp:ServiceReference Path="~/Service1.svc" /></Services>

    </asp:ScriptManager>

    <div style="height:100%;">

    <asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/SilverlightApplication2.xap" MinimumVersion="2.0.31005.0" Width="100%" Height="100%" />

    </div>

     

     

    </form> </body>

    </html>

    web.config:

    <system.serviceModel>

    <bindings>

    <webHttpBinding>

    <binding name="default"/>

    </webHttpBinding>

    </bindings>

    <services>

    <service name="WcfService1.Service1" behaviorConfiguration="MyServiceTypeBehaviors">

    <endpoint address="" binding="webHttpBinding" bindingConfiguration="default" contract="WcfService1.IService1" behaviorConfiguration="webScriptEnablingBehavior"/>

    </service>

    </services>

    <behaviors>

    <endpointBehaviors>

    <behavior name="webScriptEnablingBehavior">

    <enableWebScript/>

    </behavior>

    </endpointBehaviors>

    <serviceBehaviors>

    <behavior name="MyServiceTypeBehaviors">

    <serviceMetadata httpGetEnabled="true"/>

    </behavior>

    </serviceBehaviors>

    </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>

    </system.serviceModel>

    Service1.svc.cs:

    using System.ServiceModel.Activation;

    using System.ServiceModel;

    using System.IO;

    using System;

    namespace WcfService1

    {

     

    [
    ServiceBehavior(IncludeExceptionDetailInFaults = true)] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

    public class Service1 : IService1

    {

    public void DoWork()

    {

    File.WriteAllText("C:\\1.txt", DateTime.Now.ToString() + "\r\n");

    }

     

    }

    }

    IService1.cs:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Runtime.Serialization;

    using System.ServiceModel;

    using System.Text;

    using System.ServiceModel.Web;

    namespace WcfService1

    {

    // NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in Web.config.

    [ServiceContract(Namespace = "WcfService1")]

    public interface IService1

    {

    [
    WebGet]

    [OperationContract]

    void DoWork();

    }

    }

     

    Sunday, February 08, 2009 10:02 PM
  • Waw.. thanks for the sample... I have problem with the call.

    The service i'm trying to call is required parameter. Could you kindly give me example with parameter call.

     

    Thanks :)

    Thursday, March 19, 2009 3:27 PM
  • Thanks for your workaround via the call through aspx. However my problem (as it seems many of those who contributed to this thread before) is that I need to save data which are stored within my silverlight control. So there are two question

    - Is it possible at all to get these data from outside (which means from the aspx page) in order so send the to some place?

    - And if this is possible, is it still possible in the unload event or is that too late?

    As others had the same problem, I need to write the Logout information of the currently logged in user into my database that is talked to through the WCF service. So for this I need to send to my WCF service the currently logged in user as a parameter. Additionally I would like to save the latest data changes back to the backend.

    Wednesday, May 06, 2009 8:23 AM
  • I join the others. I also have to log off my users in the WCF Service with information inside the Silverlight part. Isn't there really another way?

    Cheers.

    Thursday, August 13, 2009 9:36 AM
  • The workaround is actually quite simple, and only requires some basic browser integration:

    1. In the HTML, declare the Body tag as follows: <Body onBeforeUnload="pageUnloading();">
    2. Include the following JavaScript in your HTML: 
              var blocking = true;
      
              function pageUnloading() {
                  var control = document.getElementById("<%= Xaml1.ClientID%>"); // Needed if you use master pages 
                  control.content.Page.finalSave();
                  while (blocking)
                      alert('Saving data to server');
              }
      
              function allowClose() {
                  blocking = false;
              }
      
       
    3. Expose your Silverlight page to JavaScript by (1) decorating the class with the [ScriptableType()] attribute, and (2) in the SilverLight page's constructor or Page_Load event, register the page as follows: 
      HtmlPage.RegisterScriptableObject("Page", this); 
       
    4. Add the finalSave() method to your SilverLight page's code-behind and decorate it with the [ScriptableMember()] attribute.  Also add the completed method which will call the JavaScript allowClose() method: 
              [ScriptableMember()]
              public void finalSave()
              {
                  proxy.saveDataAsync(currentObject);
              }
      
              void proxy_saveDataCompleted(object sender, saveDataCompletedEventArgs e)
              {
                  // tells JavaScript to stop blocking
                  HtmlPage.Window.CreateInstance("allowClose");
              }
    That's pretty much it. Of course you'll need to register your proxy's saveDataCompleted event handler. I do that in the page's constructor.
     
    What happens when the user tries to close the browser, or navigate away from the page is this:
    1. The browser fires the onBeforeUnload event which calls the pageUnloading() method.
    2. pageUnloading() calls the finalSave() method in your Silverlight Application. It also keeps displaying alert messages until the global JavaScript variable blocking is no longer set (in reality, it will probably only display this once, unless the WCF call is really, really slow).
    3. The SilverLight finalSave() method saves the data to the server using WCF. When the call returns, the SilverLight application uses browser integration to call the JavaScript allowClose() method.
    4. The JavaScript allowClose() method clears the blocking variable. Now, the next time the user clicks OK in the alert popup, the page is free to close.

    Aaron

    Tuesday, August 25, 2009 5:03 PM
  • Thank you. Questions:

    1. This requires that html page is processed by asp.net since contains <%= tag. How to use it  in reqular html page, without asp net tag ?

    2. How to modify this code so it works in OOB application also?

    Andrus.

    Thursday, August 27, 2009 11:41 AM
  • Thank you Aaron,

    I was also looking for a workaround to disconnect the client on closing the browser.

    I tried your proposed solution and it does not seem to be working for me. First, I get an error while running the app at document.getElementById("<%= Xaml1.ClientID%>"); . What is supposed to be in the parameter?

    Tuesday, September 01, 2009 5:49 PM
  • The use of document.getElementById("<%= Xaml1.ClientID%>") isn't required.  If you're using ASP.NET MasterPages or UserControls, it simplifies things a lot, because ASP will generate different ID's for the DOM-level objects at runtime.  For Example, if your SIlverlight control is located within a User Control, located within a MasterPage, the actual ID of the rendered Silverlight object might be something like MyMasterPage$MyUserControl$MySilverlightClient.  And of course that's the ID that the JavaScript getElementById function would have to find.

    You can always hard code the ID directly into your JavaScript, as in document.getElementById("MyMasterPage$MyUserControl$MySilverlightClient").  Nothing wrong with that.  Just look at the source code from the rendered page and copy the ID from there.

    Aaron

    Thursday, September 03, 2009 12:37 PM
  • Thank you Aaron,

    I was using the default test.aspx page created by Silverlight project. By default the "object" tag did not had the ID attribute so I added.

    Thursday, September 03, 2009 12:48 PM
  • Silverlight shows some exceptions javascript error handler in default page.

    Can we use this method also to forward those errors to SL application which calls web method to store errors in server database for easy error tracking ?

    Andrus.

    Thursday, September 03, 2009 1:04 PM
  • Sure, why not?

    Thursday, September 03, 2009 1:12 PM
  • Hello,

     Has this been finally fixed on Silverlight 3.0?

     If not.. it would be a pain in the neck implementing an autosave functionallity. 

     Thanks

       Braulio

    Monday, September 07, 2009 8:55 AM
  • Hello,
    I have the necessity to decrease the number of connected users when the Silverlight application is closed.
    I tried Aaron's solution and it worked BUT I absolutely need to get rid of the alert message, the web service must be called and the app must be close immediately whatever the result of the call, it must be 100% transparent to the user.
    I tried everything and nothing worked, do you know how to allow the call to the web service without any "alert" message box ?

    Thursday, October 15, 2009 4:15 AM
  • If you find a way to do it without the alert box, let us know.  I tried many different things, but nothing worked consistently.

    Aaron

    Thursday, October 15, 2009 7:47 AM
  • Actually Aaron I set my last hope in that forum.
    I worked with my company Javascript most expert in order to solve the issue and we have not succeeded.
    The problem is that Javascript is mono-thread and that we have no way to hold the application from closing and to let it work at the same time.
    I really hope that something will be done for that in the next release because it's a rather serious issue IMHO.
    How should I determine the number of connected user now, that’s a good question...

    Thursday, October 15, 2009 10:55 AM
  • Aaron solution issues/questions:

    a. It works in IE only. How to make it work in all browsers ?

    b. We need to show localized exit message according to user language.
    How to pass custome message from silverlight application to alert box ?

    c. if server or connection goes down, only way to close browser is use task manager.
    How to add timeout so that if there is no response from server, alert box closes after some time?

    Of cource, best solution would be to remove alert box.

    Andrus

    Saturday, October 31, 2009 6:19 PM
  • I recall that turbotax.com is able to do this somehow.  Whenever you are in a tax return and close the browser, they pop up another browser window that says "closing connection..." or something like that.  Then after a moment, that window closes as well.  Not sure if they are using ActiveX though...

    Sunday, November 01, 2009 8:34 AM
  • I too would like this.  My async call just notifies my service that some cached items are no longer needed.  The callback is never actually used.  They end up timing out anyway, but this made testing easier.  It sometimes worked when I wrote the code (Silverlight 2) but doesn't now (Silverlight 3)? 

    Ann

    Friday, January 29, 2010 4:58 PM
  • Hello Allen,

           If I have a scenario where, I may find out the requirement for session Variable and other variable that present in asp.net.

          How *** I make use of such variable.

    With Regards,

       Gautham

    Saturday, January 30, 2010 1:35 AM
  • OK, we're almost up to SL 4.0. Has this issue been addressed ? There should't have to be a hacked-up/javascript work-around for making a final call to the server. This is a very common situation that needs to be addressed. I'm with one of the previous posters: I just need fire off a call to the server to close out the "session". I don't need or want to stop the browser from closing, I just want a supported way to communicate with the server that the user is leaving...
    Tuesday, February 09, 2010 10:41 PM
  •  Hi to all,

     I also had the need of logging out my users in the App.Exit in the database and I read through this thread and to be honest.. there is no really clean solution to this problem and I'm not a fan of any ineffectual hacks/nasty workarounds, so I thought of any other clean ways that would afford a similar behaviour.

     And here is my solution:

    I have created a DispatcherTimer in a new thread, which calls every tick a storedprocedure at my database, that refreshes a timestamp, which indicates me the "last user activity".

    On my server I have a steady service, that also runs every period through my table, and checks if the timestamp is older than the current time minus the "tick-period" of my dispatcher timer. If so, then I flag this record as "logged out".

    This is of course not exactly the wished behaviour, but it does it's job and defentitly satisfies my needs and it is a clean solution, that works every time on every browser and even in oob apps.

    Depending on the "tick-timespan" of the dispatcher timer you can be very accurtate with the loggedin/loggedout flags in your database.

     

    Hope I could help some of you!

    Saturday, February 20, 2010 7:06 AM
  • I figured with the Window.Closing event added in Silverlight 4 that at least for Out Of Browser, there would be a more elegant solution to the "save at close" issue.  Unfortunately, I've not been able to make it work.  I figured I could hook the Closing event, cancel the close while starting the async save, then execute a Window.Close when the asynchronous save completes.  The problem is that Window.Close has been made a privileged operation unless it originates from a user (mouse/keyboard) event.  As an aside, why on earth is programmatically closing an OOB Window considered a security risk?!  So anyway, at this point I'm left with something almost as bad as the alert hack, which is to ask the user to try closing the window again.Let me emphasize to the SL team that this issue of saving at close is a major problem with the platform presently.  Here is a suggested remedy:-When a close operation is pending, in or out of browser, raise an Application.Closing event with IsReady in the event args.
    -If the event args come back and not all subscribers are ready, display a progress dialog, along the same lines as the startup/loading animation.  Display a "Close Now" button so that the user can ultimately force the closure.
    -When the asynchronous task is complete, Application.ReadyToClose() is called, allowing final closure.

    Best,
    --
    Nathan Allan

    Monday, May 10, 2010 10:58 PM
  •  Is there any solutions for this problem? Thanks in advance. I've tried to adopt an othe solution. Check this thread.

     http://forums.silverlight.net/forums/t/181674.aspx

    The problem is that firefox doesn't work. IE does. Why?

    Wednesday, May 12, 2010 11:41 AM
  • I think you guys have been looking into the work around. However i still dont understand why the on application exit event the call would not work. One reason that i can think of looking at the original thread is that maybe you are using the WCF service for operation type request-response. I think in this case what happens is that a thread is used from thread pool for the request and it waits for the response. However with applicaiton exit i think the thread does not live long enough to be there for the request. I would like to try the other type of WCF service which is one-way, fire and forget, operation type and see if that works on the application exit event.  

    Wednesday, August 04, 2010 1:34 PM
  • raoayya,

    I suspect you may be right that the IO operation is queued, but the queue is not serviced after the Exit point.  In fact, any successful strategy would require blocking until the IO operation is sent, otherwise the process may terminate during transmission.  The problem becomes more difficult given the fact that Silverlight only supports asynchronous WCF contracts. 

    In the end, even if there was a way to fire-and-forget, this would be an inferior option.  When you go to close an editor, for instance, and you've made some changes; you are given the opportunity to save, ignore, or cancel.  I think this modality needs to be incorporated into Silverlight.  If done by Silverlight itself, it would prevent applications from arbitrarily preventing closure, but would give a mechanism for proper shut-down.

    Best,

    --

    Nathan Allan

    Database Consulting Group / Alphora

    Wednesday, August 04, 2010 2:19 PM
  • I just want to tell the server that I'm logging out/exiting.  Those above browser options won't work for out of browser which I use the most.  Is there a way to override the X button on the window maybe?

    Tuesday, September 28, 2010 7:45 PM
  • managed to hack it using Javascript using In Browser mode. But still can't get anything to work in OOB mode :( I've also tried the WebBrowser control in 4.0 but still no success.


    I do not know why the HTML DOM Bridge is disabled in OOB mode.

    By investigating the index.html file in C:\Users\<user>\AppData\Local\Microsoft\Silverlight\OutOfBrowser\<randomnumber>.localhost, it still looks like that the silverlight app is hosted in a browser anyway. To prove it is still running in a browser, I put onunload="alert('out')" on the body tag within this file and it actually executed when I closed my OOB application.

    If we could either use the DOM bridge or define our own OOB index.html file then we could execute the same JS as in In Browser mode and we'd all be happy chaps!!


    FYI "In Browser Mode" that worked for me:

    All I am doing in "In Browser Mode" is running some JS when "onbeforeunload" of the body tag fires:

    <body onbeforeunload="OnClose()">


    The OnClose() function just redirects a hidden IFRAME on the page to a logout REST url (make sure the url is in the same domain as your app:

    function OnClose() {
                window.frames['logout'].location.href = '/Placemaker.Host/Geography.svc/xml/LogoutUser';
                eraseCookie(".ASPXAUTH");
            }

           function OnClose() {

                window.frames['logout'].location.href = '/yourdomain.com/yourservice.svc/xml/LogoutUser';

            }


    all the RESTful service does is log out the user at the server side, I really dont give a $hht what the service returns because the app would be long gone.


    Sunday, October 10, 2010 4:53 PM
  • How to create LogoutUser URL handler?

    Multiple users may have same IP addresses. How to custom session id from application to this handler ?

    Andrus.

    Monday, October 11, 2010 3:53 AM
  • It is not a Handler, the LogoutUser url is a WCF service operation with the WebGet() attribute which runs outside of the actual application scope. I do not use server side Sessions. Technically, session is on the client app.


    I am using System.Web.ApplicationServices.AuthenticationService to authenticate the user at login. Once the user is logged in, I can make calls to a WCF endpoint which validates the user based on the .ASPXAUTH ticket obtained from the login. As you can see, it requires cookies. But I can easily change the WCF endpoint to authenticateMode="UserNameOverTransport" and pass credentials to WCF instead of the cookie.


    When the user decides to log out, I call the LogoutUser WCF operation.

    Monday, October 11, 2010 7:28 PM
  • I also think it is essential feature

    Tuesday, April 17, 2012 5:15 AM