Focus On Delivering Value to Your Patients.

Simplifying Asynchronous Calls in Silverlight using Action

Contact Us Today

This post explores a way to encapsulate web service calls from Silverlight in a way that is easy to use and understand.

As anyone who works with Silverlight knows, Silverlight forces web service calls to be asynchronous. There is a good reason for this, which I won’t get into with this post. What I would like to do is demonstrate an approach that advocates a clean separation of the internals of the service from the application that is consuming it.

First, I am assuming you understand web services and WCF. I assume you’ve called services from Silverlight, and are aware of the nuances of configuring the endpoint, etc. I am also going to assume you are familiar with some frameworks such as Prism, MEF, Caliburn, etc that advocate clean separation of concerns and modular design.

Let’s assume I have a service on my web page that is a calculator (oh, where did I get that idea?) It looks something like this:

[ServiceContract(Namespace = "https://training.atmosera.com/sample")]    
public interface ICalculatorService
{
    [OperationContract]
    long Multiply(int x, int y);
}

Simple, correct? The first thing I’m going to do is to create a similar interface on my Silverlight client. This interface will hide the details of how the service is connected and wired. I also want to make it easier to deal with the asynchronous nature of the calls. I’ve seen some pretty exotic implementations to try to make an asynchronous call look synchronous, and don’t quite understand why we’d want to do it. Instead, let’s just define a contract like this somewhere in the Silverlight application that is “seen” globally:

public interface ICalculator 
{
   void Multiply(int x, int y, Action<long> result); 
}

As you can see, it’s a simple void method … in fact, all methods we use to abstract the asynchronous calls will most likely be void. But the key is last parameter. This delegate allows me to specify how I want to deal with the result.

Now I create a project that is solely used to implement ICalculator and connect with the web service. First, if you haven’t read my post about abstracting WCF service calls, be sure to read it: Abstracting WCF Service Calls in Silverlight. It explains how I use a base class to avoid having to change the ServiceReferences.ClientConfig file everytime I deploy an application, and also will give you the concept for the BaseService class you see below.

public class CalculatorService : BaseService<CalculatorServiceClient,ICalculatorService>, ICalculator
{
    public CalculatorService()
    {
        _GetClientChannel().MultiplyCompleted += new EventHandler<MultiplyCompletedEventArgs>(CalculatorService_MultiplyCompleted);
    }        

    #region Event handlers

    void CalculatorService_MultiplyCompleted(object sender, MultiplyCompletedEventArgs e)
    {
        Action<long> result = e.UserState as Action<long>;
        if (result != null)
        {
            result(e.Result); 
        }
    }

    #endregion 

    #region ICalculator Members

    public void Multiply(int x, int y, Action<long> result)
    {
        _GetClientChannel().MultiplyAsync(x, y, result);
    }

    #endregion
}

The base class preps the channel and credentials, etc for me. In the constructor of the implementation, I simply register for the completion event for the call. When a consumer of the service makes a call, the consumer provides a delegate to call back to when the service is done. This is passed in the user state, then cast back to an action and called once the service returns. If you wanted to have error handling, you’d just extend the action delegate to have an error-related parameter and check the e.Error when the call completed.

Now we can put it into use. In my bootstrapper, I’ll bind the service to the contract like this:

Container.RegisterType<ICalculator,CalculatorService>(new ContainerControlledLifetimeManager());
            

Now I can throw a view model together that looks something like this:

public class CalculatorViewModel : INotifyPropertyChanged
{

    private bool _busy = false;

    public bool BusyState
    {
        get { return _busy; }
        set
        {
            if (!value.Equals(_busy))
            {
                _busy = value;
                OnPropertyChanged("BusyState");
                CalculateCommand.RaiseCanExecuteChanged();
            }
        }
    }

   public DelegateCommand<object> CalculateCommand { get; set; } 

    public CalculatorViewModel(ICalculator calculator)
    {
        Calculator = calculator;
        CalculateCommand = new DelegateCommand<object>(o => CommandCalculate(),
            o => !BusyState);
    }

    public ICalulator Calculator { get; set; }

    private int _x;

    public int X
    {
        get { return _x; }
        set
        {
            if (!value.Equals(_x))
            {
                _x = value;
                OnPropertyChanged("X"); 
            }
        }
    }

     private int _y;

    public int Y
    {
        get { return _y; }
        set
        {
            if (!value.Equals(_y))
            {
                _y = value;
                OnPropertyChanged("Y"); 
            }
        }
    }

    private long _answer;

    public long Answer
    {
        get { return _answer; }
        set
        {
            if (!value.Equals(_answer))
            {
                _answer = value;
                OnPropertyChanged("Answer"); 
            }
        }
    }

    public void CommandCalculate()
    {
        BusyState = true;
        Calculator.Multiply(_x, _y, answer => {
              BusyState = false;
              Answer = answer;
         }); 
    }

    private void OnPropertyChanged(string property)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(property));
        }
    }

    #endregion 

    #region INotifyPropertyChanged Members

   public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

Now I can simply data bind my XAML to the X, Y, and Answer properties, and bind a button to the Click command. The button will even disable itself while the client is waiting on the server to return the answer. As you can see, the implementation is very straightforward and I don’t have to worry about how the call happens. In fact, using this type of abstraction, I could easily wire in a mock class to satisfy the service for testing like this… or maybe decide that a web service for multiplication is overkill and just satisy the contract locally:

public class MockCalculator : ICalculator 
{
   public void Multiply(int x, int y, Action<long> result) 
   {
      result(x*y);
   }
}

While the Action command is really a different way of expressing a delegate, it also makes the intent of the code clear and allows for a clean separation of mechanism from result when dealing with asynchronous calls.

Jeremy Likness

Take advantage of our free assessment and Azure credits.

We understand that evolving your IT can be costly.
We are offering you a unique opportunity to save you money and get you started faster.

Get $2,500 Azure Credits and a Free Architecture Roadmap

Assess and Migrate Your Existing Environment

Improve Your Information Security and Compliance

Get up to 5 hours of architecture work and $2,500 worth of Azure credits, free of charge.

We right-size your systems and move them into an optimized environment.

We work closely with your team to develop the right roadmap.

Atmosera cited by Gartner as a Representative Vendor in the Market Guide for Cloud Service Providers to Healthcare Delivery Organizations

Read Press Release

We help healthcare solution providers make the most of the cloud.

We are a Gold certified Microsoft Azure service provider offering a comprehensive set of managed services.
We excel at working with care providers and their ecosystem of solution providers.

Collaborate with Experts

Migrate Environments

Maintain Confidence

We take on your infrastructure concerns as an extension of your team and tackle compliance including HIPAA/HITECH and HITRUST.

Our methodology encompasses design through deployment and focuses on delivering solutions which are realistically implementable.

Rely on our deep knowledge of critical security frameworks and 24x7x365 monitoring by a team of experts.

We Know Healthcare:

We are fortunate to count a number of leading care providers and healthcare vendors as our customers. We continue to grow this segment as companies turn to secure and compliant cloud solutions.

Our Customers Include:

All Care Services, CarePayment Technologies, Consonus Healthcare, Digital Visions, Fanno Creek Clinic, First Insight, Health Share of Oregon, Marquis Companies, MediPro Direct, Metropolitan Pediatrics, Navos, OCHIN, Oregon State Hospital, Planned Parenthood, ProtoCall Services, Salem Health, Seasons Management, The Portland Clinic, Touchmark, Vistalogic, WVP Health Authority.

Download Data Sheet View Case Study

Collaborate with Experts

  • Plan out your cloud strategy without having to commit all your applications to the public cloud
  • Microsoft has the only viable hybrid strategy and expected to surpass AWS in market share by 2019.
  • We specialize in engineering, deploying and operating the right solution for your business by combining public and private Azure.
  • As one of the world’s five largest Microsoft cloud solution providers (CSP), we help you identify the optimal environment to run each application including your database and storage.
  • Meet HIPAA/HITECH, HITRUST and PCI DSS compliance

Migrate Environments

  • We have expertise which minimizes redevelopment to move applications and data without recoding.
  • We leverage Microsoft Azure Site Recovery (ASR) which provides a simple way to move applications and data without having to redevelop the underlying cloud infrastructure.
  • We implement your new environment on a public or private cloud depending on your preferences and business requirements.
  • We enable access to complete and accurate PHI for better medical care.

Maintain Confidence

  • Ensure you are secure from design through deployment.
  • Eliminate concerns about exposing your PHI and Non-PHI data when using the public cloud.
  • Define your objectives and build the right foundation using best practices and then execute it.
  • You gain the peace of mind that comes from knowing we have planned out your cloud to the smallest details and then made sure it delivers on your needs.
  • Let our team monitor your environment and take real-time actions to keep your applications running at their best.

We deliver solutions that accelerate the value of Azure.

Ready to experience the full power of Microsoft Azure?

Start Today

Blog Home

Stay Connected

Upcoming Events

All Events