tags:

views:

160

answers:

2

My Silverlight 4 application keeps in contact with a server side through a wcf service. Whenever the user refreshes, navigates away or terminates the browser I should do some cleanup towards the server side.

I can not use the Application Exit event; my wcf client is dead before it eventually gets called. I can not use the (new in SL4) FrameworkElement Unloaded event; it ain't called when the Silverlight app shuts down.

So, how do I detect the browser refresh, newpage or shutdown in time to do my cleanup?

A: 

I dont think you can do anything on server side after user has decided to navigate away or browser is terminated, however you can write a javascript to prevent unload of current page there you can warn the user for not to close it.

Second, use a small session timer, like every 2 minutes, your session should timeout, but when your silverlight application is open and running in the browser, you should ping your server by writing some ping method that will keep your session alive every 1 minute.

So in case if your session is expiring, (it didnt receive ping in last 60 seconds), your session will be destroyed and you can write some cleanup code at server's session end.

Akash Kava
Akash, Thank you for your reply. I do indeed have a session timer like you describe, but the user may be evil and refresh the browser and re-logon *before* it kicks in. Anyway, it would be nice to do the cleanup in an orderly fashion when these things happen rather than depend on the session timer (keepalive) to tidy up.
BaBu
+1  A: 

BaBu,

I do this exact thing when a user navigates away from my Silverlight app (or does a refresh). Follow the steps below to catch this event.

1.) Start by listening for the HTML page's "onbeforeunload" event, like so...

public void Application_Startup(object sender, StartupEventArgs e)
{
    bool ok = HtmlPage.Window.AttachEvent("onbeforeunload", Application_BeforeExit);
    ok = HtmlPage.Document.AttachEvent("onbeforeunload", Application_BeforeExit);
    MainPage mainPage = new MainPage();
    base.RootVisual = mainPage;
}

2.) Implement Application_BeforeExit() to setup and call an ASP.NET "PageMethod", like so...

private void Application_BeforeExit(object sender, HtmlEventArgs args)
{
    string methodName = "ModelShutdown";
    params object[] args = new Guid().ToString());;

    try
    {
        ScriptObject pageMethods = (ScriptObject)HtmlPage.Window.GetProperty("PageMethods");
        if (pageMethods == null)
            throw new ArgumentException("Web page does not support PageMethods");
        object[] pageMethodArgs = { new PageMethodEventHandler(Success), new PageMethodEventHandler(Failure), null/*userContext*/};
        object[] combinedArgs = new object[args.Length + pageMethodArgs.Length];
        args.CopyTo(combinedArgs, 0);
        pageMethodArgs.CopyTo(combinedArgs, args.Length);
        pageMethods.Invoke(methodName, combinedArgs);
    }
    catch (Exception ex)
    {
        //ex.Alert();
    }
}

3.) Add the PageMethod to your page code behind (Index.aspx.cs), like so,

public partial class Index : Page
{
    [WebMethod] // a PageMethod called from Silverlight
    public static void ModelShutdown(string identifier)
    {
        System.Diagnostics.Debug.WriteLine("*** Signing Off: " + identifier);
    }
}

4.) Allow PageMethods on your page (Indx.aspx), like so,

<asp:ScriptManager runat="server" EnablePageMethods="true" />
<div id="silverlightControlHost">
    <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">

Good luck,
Jim McCurdy, YinYangMoney.com

Jim McCurdy
Many thanks Jim! I admit I was hoping for a cleaner solution, i.e. without aspx/javascript stuff. I find that it's best to stay away from browser-near things like that. But I am reluctantly starting to realize there may be no other way. By the way; does your solution work in Firefox and Chrome, as well as IE?
BaBu
I just realized that you could call your WCF service instead of doing the PageMethod approach; that would work just as well. The only thing you won't be able to do is get a completed event from an async call, since once you leave the Application_BeforeExit() method, the Silverlight app is gone. And it should work in any browser; thats why I listed 2 diferent AttachEvent() calls.
Jim McCurdy
Thanks again Jim. Sorry to report that a call to the wcf service from Application_BeforeExit() never reaches the server either. I've done some research and it seems your original solution, or similar approaches, are the only way to handle this. See e.g. http://forums.silverlight.net/forums/t/20279.aspx. My guess is that some future Silverlight version will offer a solution to this though. After all 'save on exit' is a much wanted feature.
BaBu