views:

105

answers:

2

In classic ASP.NET I’d persist data extracted from a web service in base class property as follows:

   private string m_stringData;
   public string _stringData
    {  get {
            if (m_stringData==null)
                {
                    //fetch data from my web service
                    m_stringData = ws.FetchData()
                }
            return m_stringData;
       }
   }

This way I could simply make reference to _stringData and know that I’d always get the data I was after (maybe sometimes I’d use Session state as a store instead of a private member variable).

In Silverlight with a WCF I might choose to use Isolated Storage as my persistance mechanism, but the service call can't be done like this, because a WCF service has to be called asynchronously.

How can I both invoke the service call and retrieve the response in one method?

Thanks, Mark

A: 

In your method, invoke the service call asynchronously and register a callback that sets a flag. After you have invoked the method, enter a busy/wait loop checking the flag periodically until the flag is set indicating that the data has been returned. The callback should set the backing field for your method and you should be able to return it as soon as you detect the flag has been set indicating success. You'll also need to be concerned about failure. If it's possible to get multiple calls to your method from different threads, you'll also need to use some locking to make your code thread-safe.

EDIT

Actually, the busy/wait loop is probably not the way to go if the web service supports BeginGetData/EndGetData semantics. I had a look at some of my code where I do something similar and I use WaitOne to simply wait on the async result and then retrieve it. If your web service doesn't support this then throw a Thread.Sleep -- say for 50-100ms -- in your wait loop to give time for other processes to execute.

Example from my code:

IAsyncResult asyncResult = null;
try
{
    asyncResult = _webService.BeginGetData( searchCriteria, null, null );
    if (asyncResult.AsyncWaitHandle.WaitOne( _timeOut, false ))
    {
        result = _webService.EndGetData( asyncResult );
    }
}
catch (WebException e)
{
    ...log the error, clean up...
}
tvanfosson
Thanks for taking the time to answer, but I tried this previously and found that my wait loop (do{// stuff}while(blnWaiting==true)} was locking the thread, so the flag was never getting set. I'm limited to 300 chars in this 'comment', so can't show full code, can you provide an example? Thanks, Mark
Mark Cooper
I added an example from the way I actually do it -- which is different than what I described. It may or may not be applicable depending on your web service.
tvanfosson
Yes, this looks like what I need. I'll implement that and see how I go. Thanks for your assistance.
Mark Cooper
I'm implementing my methods via the Add Service Reference feature, so I don't have the Begin... and End... methods. Can I get an IAsyncResult from any other auto-generated properties?
Mark Cooper
In VS2008, at least, you can right click on the service reference and choose Configure Service Reference. Check the Generate asynchronous operations box under the client section and click ok.
tvanfosson
A: 

Thanks for your help tvanfosson. I followed your code and have also found a pseudo similar solution that meets my needs exactly using a lambda expression:

private string m_stringData;
public string _stringData{    
get
    {
   //if we don't have a list of departments, fetch from WCF
        if (m_stringData == null)
        {
            StringServiceClient client = new StringServiceClient();
            client.GetStringCompleted +=
                (sender, e) =>
                {
                    m_stringData = e.Result;
                };
            client.GetStringAsync();
        }
        return m_stringData;
    }
}

EDIT

Oops... actually this doesn't work either :-( I ended up making the calls Asynchronously and altering my programming logic to use MVVM pattern and more binding.

Mark Cooper