Click here to Skip to main content
Click here to Skip to main content
Go to top

Calling Web Services from Silverlight after the Browser has closed

, 19 Oct 2009
Rate this:
Please Sign up or sign in to vote.
There are two things I wanted to look at. Firstly, I wanted to allow a web service to be called after the Silverlight application’s Exit event is raised. Secondly, I wanted to provide the Silverlight application with the opportunity to cancel, or at least interrupt the close window process.

Introduction

Today I was reading an excellent post by my fellow Disciple Laurent Bugnion, which led on to a short discussion about performing actions after a user attempts to close a browser window. It got me thinking about the capability to dispatch a web service call in Silverlight just after a user attempts to close the browser window or navigate elsewhere. I have been asked the question before, yet before now, have not attempted to answer it. So today I decided to do some experimenting.

There are two things I wanted to look at. Firstly, I wanted to allow a web service to be called after the Silverlight application’s Exit event is raised. Secondly, I wanted to provide the Silverlight application with the opportunity to cancel, or at least interrupt the close window process.

In the first scenario, I found the way I could achieve the call after the Silverlight applications Exit event was raised, was to call a JavaScript method from Silverlight, and then finally a PageMethod; to perform the housekeeping.

Figure: A web service is called after the user closes the browser.

We see that in our App.xaml.cs the Exit event handler is called, which then calls a JavaScript function, as demonstrated in the following excerpt:

void Application_Exit(object sender, EventArgs e)
{
    HtmlPage.Window.Invoke("NotifyWebserviceOnClose", 
          new[] { guid.ToString() });
}

We then call a PageMethod on the page hosting the application like so:

function NotifyWebserviceOnClose(identifier) {
    PageMethods.SignOff(identifier, OnSignOffComplete);            
}

The PageMethod is where we are able to update a list of connected clients, or do whatever takes our fancy.

[WebMethod]
[System.Web.Script.Services.ScriptMethod] 
public static void SignOff(string identifier)
{
    /* Update your list of signed in users here etc. */
    System.Diagnostics.Debug.WriteLine("*** Signing Off: " + identifier);
}

Caveat lector- According to Laurent, this is not reliable. So, you will need to test it for yourself. I've tested it locally in Firefox 3.5 and IE8. But, your results may differ.

Now the second thing I wanted to look at was the ability to provide some interaction with the user, either cancelling or calling a web service, when the user attempts to close the browser; but before the browser is actually closed.

The way I did this was to place an onbeforeunload handler in the body tag of the page, as shown:

<body onbeforeunload="OnClose()">

I then created the OnClose handler in a JavaScript script block as shown in the following excerpt:

function OnClose() {           
    var plugin = document.getElementById("silverlightControl");
    var shutdownManager = plugin.content.ShutdownManager;
    var shutdownResult = shutdownManager.Shutdown();
    if (shutdownResult) {
        event.returnValue = shutdownResult;
    }
}

Here we see that we retrieve the Silverlight application and resolve an instance of the ShutdownManager class present in the Silverlight App class. The ShutdownManager is a class that is able to perform some arbitrary duty when the application is closing. It is made accessible to the host webpage by registering it with a call to RegisterScriptableObject.

void Application_Startup(object sender, StartupEventArgs e)
{
    HtmlPage.RegisterScriptableObject("ShutdownManager", shutdownManager);
    this.RootVisual = new MainPage();
}

ShutdownManager

The ShutdownManager is decorated with two attributes that allow it to be consumed by an external source. They are SciptableType and ScriptableMember. As we see below, they are used to allow the ShutdownManager class to be called via Ajax.

[ScriptableType]
public class ShutdownManager
{
    [ScriptableMember]
    public string Shutdown()
    {
        string result = null;
        var page = (MainPage)Application.Current.RootVisual;

        if (page.Dirty)
        {
            var messageBoxResult = MessageBox.Show(
                "Save changes you have made?", 
		"Save changes?", MessageBoxButton.OKCancel);
            if (messageBoxResult == MessageBoxResult.OK)
            {
                var waitingWindow = new WaitingWindow();
                waitingWindow.Show();

                waitingWindow.NoticeText = "Saving work on server. Please wait...";
                page.SetNotice("Saving work on server. Please wait...");

                var client = new ShutdownServiceClient();
                client.SaveWorkCompleted += ((sender, e) =>
                    {
                        waitingWindow.NoticeText = 
			"It is now safe to close this window.";
                        page.SetNotice("It is now safe to close this window.");
                        page.Dirty = false;
                        waitingWindow.Close();
                    });
                client.SaveWorkAsync("Test id");
                result = "Saving changes.";
            }
            else
            {
                result = "If you close this window you will lose any unsaved work.";
            }
        }

        return result;
    }
}

Here we see that once the Shutdown method is called, we test if the main (Silverlight) page is dirty. If so, we prompt the user to save changes. If changes are to be saved, we dispatch our async web service call using a service client. The key thing to note here is that we are returning a string value if the page is deemed dirty. This string value then indicates to the consuming JavaScript code that the window should not be closed immediately. Once the call makes it back to our JavaScript onbeforeload handler, we assign the event.returnValue the value of this string. If this value is not an empty string, it will cause the web browser to display a dialog; asking users whether they really wish to leave the page.

Figure: Browser prompts with ‘Are you sure ...’ message.

In the demo application accompanying this post, you will notice that we simulate a user modification. This is done by ticking the Page dirty checkbox.

Figure: The demonstration application simulates a modification to the data model.

Unticked, closing the browser will result in the window closing immediately. However, ticked will cause the presentation of a Save Changes dialog, as shown below:

Figure: Save changes dialog prompts user.

What happens if the user cancels the operation? Remember our event.returnValue string in the JavaScript OnClose function. If the user cancels, then this value is assigned a string value of “If you close this window, you will lose any unsaved work.” We can see how the browser chooses to display the string shown below:

Figure: User is prompted with browser initiated dialog.

Obviously we must deal with when the user selects the nominal Ok button in the save dialog. To provide a somewhat more agreeable user experience, I have dropped in a Silverlight ChildWindow control, with a ProgressBar control for good measure.

Figure: A progress bar is presented to the user while saving.

Once the user hits Ok on the Save Changes dialog, that web service call is dispatched almost immediately. In order for the web service call to occur though, we must perform interrupt the thread so that our Silverlight App has a chance to dispatch the call. We can do that with a JavaScript alert call, or as we see here, we assign the event.returnValue, which causes a dialog to be displayed in much the same manner.

Conclusion

In this post, we have seen how it is possible to call a web service after a Silverlight App’s Exit event has been raised. While this may not be reliable, I'd be interested to know your experience with this approach, and certainly of any alternate approaches. Finally we looked at interacting with the user, to allow cancellation of a close window event or to perform last minute web service calls. This was achieved using the onbeforeunload event and a JavaScript handler.

Thank you for reading.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author

Daniel Vaughan
President Outcoder
Switzerland Switzerland
Daniel Vaughan is a Microsoft MVP and co-founder of Outcoder, a Swiss software and consulting company dedicated to creating best-of-breed user experiences and leading-edge back-end solutions, using the Microsoft stack of technologies--in particular WPF, WinRT, Windows Phone, and also Xamarin.Forms.
 
Daniel is the author of Windows Phone 8 Unleashed and Windows Phone 7.5 Unleashed, both published by SAMS.
 
Daniel is the developer behind several acclaimed Windows Phone apps including Surfy, Intellicam, and Splashbox; and is the creator of a number of popular open-source projects including Calcium SDK, and Clog.
 
Would you like Daniel to bring value to your organisation? Daniel's Blog | MVP profile | Follow on Twitter
 
Windows Phone Experts
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
QuestionRock solid solution gr8 for IE -> Can it be run on FF/Chrom PinmemberKennyPatel12-Dec-12 23:06 
Questiondoes'nt work on Firfox PinmemberMember 91942225-Sep-12 18:11 
QuestionWithout IE interfering PinmemberAlex16067820-Oct-11 8:06 
AnswerRe: Without IE interfering PinmvpDaniel Vaughan20-Oct-11 11:41 
Questioncan we do the same without using javascript onbeforeunload event Pinmemberchhari22-Sep-11 8:38 
urs solutions is wonderful,
but i dont want to use onbeforeunload function of javascrpt,
can we do the same without using javascript onbeforeunload event???
 
pls let me know if any sol.
 

Thank you
 
Regards,
Hari
AnswerRe: can we do the same without using javascript onbeforeunload event PinmvpDaniel Vaughan22-Sep-11 8:58 
GeneralExcellent Post PinmemberKunalChowdhury28-Feb-10 23:02 
GeneralRe: Excellent Post PinmvpDaniel Vaughan1-Mar-10 3:03 
GeneralOut of Browser Pinmemberremcoschrijvers17-Feb-10 5:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140922.1 | Last Updated 19 Oct 2009
Article Copyright 2009 by Daniel Vaughan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid