In Silverlight, all webservices calls are asynchronous. Therefore, when implementing a repository in Silverlight we have to do things a little bit differently as we would have done in Asp.Net or WPF.
Let’s take an example. We have a website exposing a list of customers through a WCF service. We want our Silverlight application to list all these customers inside a ListBox. The service can return tenth of thousands of customers. Because of that we cannot retrieve all of them within a single call.
Let’s see the definition of the Service :
[ServiceContract(Name = "CustomerService")]
public interface ICustomerService {
[OperationContract]
int Count();
[OperationContract]
IEnumerable<Customer> Get(int start, int count);
}
...
...
public class CustomerReactiveRepository {
public IObservable<Customer> GetAll()
{
return Observable.Create<Customer>(observer => OnSubscribe(observer));
}
private static Action OnSubscribe(IObserver<Customer> observer)
{
try {
var client = new CustomerServiceClient();
client.CountCompleted += (sender, e) =>
{
if (e.Result > 1000)
{
var state = new GetState { Count = e.Result, Offset = 0, Step = 500 };
((CustomerServiceClient)sender).GetAsync(state.Offset, state.Step, state);
}
else ((CustomerServiceClient)sender).GetAsync(0, e.Result);
};
client.GetCompleted += (sender, e) =>
{
foreach (var c in e.Result)
observer.OnNext(c);
var state = e.UserState as GetState;
if (state != null && state.Offset + state.Step < state.Count)
{
state.Offset += state.Step;
((CustomerServiceClient)sender).GetAsync(state.Offset, state.Step,
state);
}
else {
((CustomerServiceClient)sender).CloseAsync();
observer.OnCompleted();
}
};
client.CountAsync();
}
catch (Exception e)
{
observer.OnError(e);
}
return () => { };
}
private class GetState {
public int Offset { get; set; }
public int Step { get; set; }
public int Count { get; set; }
}
}