MVVM and asynchronous data access - c#

So I have a WPF application using the MVVM pattern (Caliburn.Micro). I got the views and view-models wired up and basicly what is missing is the data. The data is to be retrieved "on-demand" either from a WCF service, local storage or from memory/cache - reason being to allow for offline-mode and to avoid uneccessary server communication. Another requirement is that the data is retrieved asynchronously so the UI thread is not blocked.
So I was thinking to create some kind of "AssetManager" that the viewmodels use to request data:
_someAssetManager.GetSomeSpecificAsset(assetId, OnGetSomeSpecificAssetCompleted)
Note that it is an asynchronous call. I run into a few different problems though. If the same asset is requested at (roughly) the same time by different view-models, how do we ensure that we don't do unecessary work and that they both get the same objects that we can bind against?
Not sure I'm having the right approach. I've been glancing a bit at Reactive Framework - but I have no idea how to use it in this scenario. Any suggestions on framework/techniques/patterns that I can use? This seems to be a rather common scenario.

Dictionary<int, IObservable<IAsset>> inflightRequests;
public IObservable<IAsset> GetSomeAsset(int id)
{
// People who ask for an inflight request just get the
// existing one
lock(inflightRequests) {
if inflightRequests.ContainsKey(id) {
return inflightRequests[id];
}
}
// Create a new IObservable and put in the dictionary
lock(inflightRequests) { inflightRequests[id] = ret; }
// Actually do the request and "play it" onto the Subject.
var ret = new AsyncSubject<IAsset>();
GetSomeAssetForReals(id, result => {
ret.OnNext(id);
ret.OnCompleted();
// We're not inflight anymore, remove the item
lock(inflightRequests) { inflightRequests.Remove(id); }
})
return ret;
}

I've had success with method calls that pass in a delegate that gets called when the data is received. You could layer the requirement of keeping everyone with the same data (if a request is currently happening) by checking a boolean field that determines if a request is happening. I would keep a local collection of delegates that need calling so that when the data is finally received, the class that contains the delegates to call can iterate them, passing in the newly received data.
Something along these lines:
public interface IViewModelDataLoader{
void LoadData(AssignData callback);
}
public delegate void AssignData(IEnumerable<DataObject> results);
The class that actually implements this interface could then keep a running tally on who to notify when the data is done (assuming a singleton model):
public class ViewModelDataLoader : IViewModelDataLoader{
private IList<AssignData> callbacksToCall;
private bool isLoading;
public void LoadData(AssignData callback){
callbacksToCall.add(callback);
if (isLoading) { return; }
// Do some long running code here
var data = something;
// Now iterate the list
foreach(var item in callbacksToCall){
item(data);
}
isLoading = false;
}
}

Using the proxy pattern and events you can provide both synchronous and asynchronous data. Have your proxy returned cached values for synchronous calls and also notify view models via events when your receive asynchronous data. The proxy can also be designed to track data requests and throttle server connections (eg 'reference counting' calls, data requested/data received flags, etc)

I would set up you AssetManager like this:
public interface IAssetManager
{
IObservable<IAsset> GetSomeSpecificAsset(int assetId);
}
Internally you would need to return a Subject<IAsset> that you populate asynchronously. Do it right and you only have a single call for each call to GetSomeSpecificAsset.

Related

Wait for a third-party API callback

I need to create an REST API that connect to a third party SOAP API. The third party API events are sent by callback to an URL I provide.
The typical steps my API go through is it starts a session with the third party by providing an ID and an callback URL. The third party can now send new events to my API through this URL when, for example, a new participant connects. Now sometimes i need to request specific info, like the list of participants for a given session(ID), and wait for the event containing the info.
Note that there may be multiple open sessions at the same time.
An example of what I need:
private string url = "http://myapi/callback";
[HttpGet]
[Route("createSession")]
public async Task<string> CreateSession()
{
var id = Guid.NewGuid().ToString();
var result = await ExternAPI.CreateSession(id, this.url);
return result; //contains the id
}
[HttpGet]
[Route("endSession")]
public async Task<string> EndSession([FromUri] string id)
{
var result = await ExternAPI.EndSession(id);
return result;
}
[HttpGet]
[Route("partipants")]
public async Task<string> Partipants([FromUri] string id)
{
ExternAPI.participants(id); // The results of this method will be sent to the callback function
results = // Wait for the results for this id
return results;
}
[HttpPost]
[Route("callback")]
public void Callback(body)
{
// notify waiting function and pass body
}
I came up with a solution using ReactiveX but I'm not really sure about its reliability in production. What I have in mind is to create a subject that never terminate and handle all the events but it is not a usual lifetime for a subject, what happens on error ? And I don't think I did it the "RX-way" (state concerns).
Here it is (you will need System.Reactive to run this code):
class Data
{
public int id;
public string value;
}
class Program
{
private static Subject<Data> sub;
static void Main(string[] args)
{
sub = new Subject<Data>();
Task.Run(async () => {
int id = 1;
ExternAPI(CallBackHook, id);
Data result = await sub.Where(data => data.id == id).FirstAsync();
Console.WriteLine("{0}", result.value);
});
Console.ReadLine();
}
static void CallBackHook(Data data)
{
sub.OnNext(data);
}
static String ExternAPI(Action<Data> callback, int id)
{
// Third-party API, access via SOAP. callback is normally an url (string)
Task.Run(() =>
{
Thread.Sleep(1000);
callback(new Data { id = id, value = "test" });
});
return "success";
}
}
An other way will be a dictionary of subjects, one for each session, so I could manage their lifetimes.
it is not a usual lifetime for a subject
what happens on error?
And I don't think I did it the "RX-way"
Yes, these are all perfectly valid concerns with this kind of approach. Personally, I don't much mind the last one, because even though Subjects are frowned-upon, many times they're just plain easier to use than the proper Rx way. With the learning curve of Rx what it is, I tend to optimize for developer maintainability, so I do "cheat" and use Subjects unless the alternative is equally understandable.
Regarding lifetime and errors, the solutions there depend on how you want your application to behave.
For lifetime, it looks like currently you have a WebAPI resource (the SOAP connection) requiring an explicit disconnect call from your client; this raises some red flags. At the very least, you'd want some kind of timeout there where that resource is disposed even if endSession is never called. Otherwise, it'll be all too easy to end up with dangling resources.
Also for errors, you'll need to decide the appropriate approach. You could "cache" the error and report it to each call that tries to use that resource, and "clear" the error when endSession is called. Or, if it's more appropriate, you could let an error take down your ASP.NET process. (ASP.NET will restart a new one for you).
To delay an API until you get some other event, use TaskCompletionSource<T>. When starting the SOAP call (e.g., ExternAPI.participants), you should create a new TCS<T>. The API call should then await the TaskCompletionSource<T>.Task. When the SOAP service responds with an event, it should take that TaskCompletionSource<T> and complete it. Points of note:
If you have multiple SOAP calls that are expecting responses over the same event, you'll need a collection of TaskCompletionSource<T> instances, along with some kind of message-identifier to match up which events are for which calls.
Be sure to watch your thread safety. Incoming SOAP events are most likely arriving on the thread pool, with (possibly multiple) API requests on other thread pool threads. TaskCompletionSource<T> itself is threadsafe, but you'd need to make your collection threadsafe as well.
You may want to write a Task-based wrapper for your SOAP service first (handling all the TaskCompletionSource<T> stuff), and then consume that from your WebAPI.
As a very broad alternative, instead of bridging SOAP with WebAPI, I would consider bridging SOAP with SignalR. You may find that this is a more natural translation. Among other things, SignalR will give you client-connect and client-disconnect events (complete with built-in timeouts for clients). So that may solve your lifetime issues more naturally. You can use the same Task-based wrapper for your SOAP service as well, or just expose the SOAP events directly as SignalR messages.

UI Freeze when Implementing custom Asynchronous WCF call handling using tasks and callbacks in WPF application

I have a WPF MVVM Application. The View Model has a couple of properties bound to the view, and those properties are populated by data coming from a database directly or through a wcf service that stays in between the view model and the database. The choice of the mode of data connection depends on the app setting in the App.config file of the client application. I want to implement my own way of calling service methods asynchronously and handling their return values. I would like to know if there are chances for threading issues if I implement it the following way using Tasks:
The service call flow:
ViewModel > ServiceAgent > (MyWCFServiceClient or MyBusinessClient ) > MyBusinessClass> Database
Inorder to consume the service operations I have a MyWCFServiceClient class that implements IMyWCFService (generated when adding the service reference).
Also, I have a MyBusinessClassClient class that implements from the same IMyWCFService interface.
Thus, both MyWCFService and MyBusinessClient have the same method signatures. I have opted not to generate any async methods while generating the service client, because, If I do, I may need to implement so many unnecessary stuff generated by IMyWCFService in MyBusinessClient also.
Let’s assume that I have a method GetEmployee(int id) that returns an Employee object, defined in IMyWCFService. Thus both the classes MyWCFServiceClient and MyBusinessClient will have its implementations.
In my ViewModel, I have:
private void btnGetEmployee_Click()
{
ServiceAgent sa = new ServiceAgent ();
//this call/callback process the service call result
sa.GetEmployee(1673, (IAsyncResult ar) =>
{
Task<Employee> t1 = (Task<Employee>)ar;
Employee = t1.Result;
//do some other operation using the result
//do some UI updation also
});
}
//this property is bound a label in the view
private Employee _employee;
public Employee Employee
{
get
{
return _ employee;
}
set
{
_ employee = value;
OnPropertyChanged(() => Employee);
}
}
The ServiceAgent class is implemented as the following:
public class ServiceAgent
{
private IMyWcfService client;
public ProxyAgent()
{
//The call can go to either MyWCFServiceClient or
//MyBusinessClient depending on this setting
//client = new MyBusinessClient();
//OR
client = new MyWcfServiceClient();
}
public void GetEmployee(int id, AsyncCallback callback)
{
//My implementation to execute the service calls asynchronously using tasks
//I don’t want to use the complex async mechanism generated by wcf service reference ;)
Task<Employee> t = new Task<Employee>(()=>client.GetEmployee(id));
t.Start();
try
{
t.Wait();
}
catch (AggregateException ex)
{
throw ex.Flatten();
}
t.ContinueWith(task=>callback(t));
}
}
This is freezing my UI. I want to avoid that. Also I wonder whether this is a proper way for what I want to achieve. I have less experience with tasks/threads and callbacks, and hence I’d like to know whether I will have any issues I the future (threading/memory management etc).
#Ananth heh, I deleted the comment because on second glance I thought I was misreading the code. Generally speaking, when connecting to a web service, you should always treat the call as asynchronous because you can be dealing with excessive lag which would freeze whatever thread (typically the GUI thread). This is compounded if you need to make multiple WCF calls for a single GUI action. This is also worsened because your WCF interface is written like an asynchronous call but then lies and runs synchronously anyway. Definite cause for future confusion.
So I find it's best just to deal with the asynchronous model, but at least you can do the type-checking/casting/return handling within your WCF call. I did something similar, but instead of using synchronous calls, I would still use callbacks, but I'd have the IAsyncResult handled in the WCF call which would then cast it to my expected type and serve it back to the user.
public void GetEmployee(int id, Action<Employee> getEmployeeCompletedHandler)
{
Task<Employee> t = new Task<Employee>(()=>client.GetEmployee(id));
t.Start();
t.ContinueWith(task=>
{
if (getEmployeeCompletedHandler != null)
getEmployeeCompletedHandler(t1.Result);
});
}
Which makes your typical usage:
sa.GetEmployee(1673, result => this.Employee = result);
If you really want to maintain an synchronous model, then you can move work to a background thread (but that will still "asynchronous" from the GUI thread's perspective). At this point too, you may as well have your GetEmployee method be synchronous and return the value. This way it's obvious to the API consumer using it that there is no asynchronous operation:
public Employee GetEmployee(int id)
{
Task<Employee> t = new Task<Employee>(()=>client.GetEmployee(id));
t.Start();
try
{
t.Wait();
}
catch (AggregateException ex)
{
throw ex.Flatten();
}
return t.Result;
}
Then your calling code might look like:
//spawn a background thread to prevent the GUI from freezing
BackgroundThread.Spawn(() =>
{
this.Employee = sa.GetEmployee(1673);
});
Note, BackgroundThread is a custom class that you can make to wrap the creation/spawning of a background thread. I'll leave that implementation detail to you, but I find it's best just to have a managed wrapper for threading because it makes usage so much simpler and abstracts implementation details (using thread pool? new thread? BackgroundWorker? Who cares!)
Just a note, I haven't tried the synchronous usage for WCF calls I just posted above (I stick to a full asynchronous model like my first code sample), so I think it would work. (I still don't recommend doing it this way though!)

WCF Channel and ChannelFactory Caching

So I've decided to up the performance a bit in my WCF application, and attempt to cache Channels and the ChannelFactory. There's two questions I have about all of this that I need to clear up before I get started.
1) Should the ChannelFactory be implemented as a singleton?
2) I'm kind of unsure about how to cache/reuse individual channels. Do you have any examples of how to do this you can share?
It's probably important to note that my WCF service is being deployed as a stand alone application, with only one endpoint.
EDIT:
Thank you for the responses. I still have a few questions though...
1)I guess I'm confused as to where the caching should occur. I'm delivering a client API that uses this code to another department in our company. Does this caching occur on the client?
2)The client API will be used as part of a Silverlight application, does this change anything? In particular, what caching mechanisms are available in such a scenario?
3)I'm still not clear about the design of the GetChannelFactory method. If I have only one service, should only one ChannelFactory ever be created and cached?
I still haven't implemented any caching feature (because I'm utterly confused about how it should be done!), but here's what I have for the client proxy so far:
namespace MyCompany.MyProject.Proxies
{
static readonly ChannelFactory<IMyService> channelFactory =
new ChannelFactory<IMyService>("IMyService");
public Response DoSomething(Request request)
{
var channel = channelFactory.CreateChannel();
try
{
Response response = channel.DoSomethingWithService(request);
((ICommunicationObject)channel).Close();
return response;
}
catch(Exception exception)
{
((ICommenicationObject)channel).Abort();
}
}
}
Use the ChannelFactory to create an instance of the factory, then cache that instance. You can then create communicatino channels as needed/desired from the cached istance.
Do you have a need for multiple channel factories (i.e.., are there multiple services)? In my experience, that's where you'll see the biggest benefit in performance. Creating a channel is a fairly inexpensive task; it's setting everything up at the start that takes time.
I would not cache individual channels - I'd create them, use them for an operation, and then close them. If you cache them, they may time out and the channel will fault, then you'll have to abort it and create a new one anyway.
Not sure why you'd want to usea singleton to implement ChannelFactory, especially if you're going to create it and cache it, and there's only one endpoint.
I'll post some example code later when I have a bit more time.
UPDATE: Code Examples
Here is an example of how I implemented this for a project at work. I used ChannelFactory<T>, as the application I was developing is an n-tier app with several services, and more will be added. The goal was to have a simple way to create a client once per life of the application, and then create communication channels as needed. The basics of the idea are not mine (I got it from an article on the web), though I modified the implementation for my needs.
I have a static helper class in my application, and within that class I have a dictionary and a method to create communication channels from the channelf factory.
The dictionary is as follows (object is the value as it will contain different channel factories, one for each service). I put "Cache" in the example as sort of a placeholder - replace the syntax with whatever caching mechanism you're using.
public static Dictionary<string, object> OpenChannels
{
get
{
if (Cache["OpenChannels"] == null)
{
Cache["OpenChannels"] = new Dictionary<string, object>();
}
return (Dictionary<string, object>)Cache["OpenChannels"];
}
set
{
Cache["OpenChannels"] = value;
}
}
Next is a method to create a communication channel from the factory instance. The method checks to see if the factory exists first - if it does not, it creates it, puts it in the dictionary and then generates the channel. Otherwise it simply generates a channel from the cached instance of the factory.
public static T GetFactoryChannel<T>(string address)
{
string key = typeof(T.Name);
if (!OpenChannels.ContainsKey(key))
{
ChannelFactory<T> factory = new ChannelFactory<T>();
factory.Endpoint.Address = new EndpointAddress(new System.Uri(address));
factory.Endpoint.Binding = new BasicHttpBinding();
OpenChannels.Add(key, factory);
}
T channel = ((ChannelFactory<T>)OpenChannels[key]).CreateChannel();
((IClientChannel)channel).Open();
return channel;
}
I've stripped this example down some from what I use at work. There's a lot you can do in this method - you can handle multiple bindings, assign credentials for authentication, etc. Its pretty much your one stop shopping center for generating a client.
Finally, when I use it in the application, I generally create a channel, do my business, and close it (or abort it if need be). For example:
IMyServiceContract client;
try
{
client = Helper.GetFactoryChannel<IMyServiceContract>("http://myserviceaddress");
client.DoSomething();
// This is another helper method that will safely close the channel,
// handling any exceptions that may occurr trying to close.
// Shouldn't be any, but it doesn't hurt.
Helper.CloseChannel(client);
}
catch (Exception ex)
{
// Something went wrong; need to abort the channel
// I also do logging of some sort here
Helper.AbortChannel(client);
}
Hopefully the above examples will give you something to go on. I've been using something similar to this for about a year now in a production environment and it's worked very well. 99% of any problems we've encountered have usually been related to something outside the application (either external clients or data sources not under our direct control).
Let me know if anything isn't clear or you have further questions.
You could always just make your ChannelFactory static for each WCF Contract...
You should be aware that from .Net 3.5 the proxy objects are pooled for performance reasons by the channel factory. Calling the ICommunicationObject.Close() method actually returns the object to the pool in the hope it can be reused.
I would look at the profiler if you want to do some optimisation, if you can prevent just one IO call being made in your code it could far outweigh any optimisation you will make with the channel factory. Don't pick an area to optimise, use the profiler to find where you can target an optimisation. If you have an SQL database for instance, you will probably find some low hanging fruit in your queries that will get you orders of magnitude performance increases if these haven't already been optimised.
Creating the Channel costs the performance so much. actually , WCF already has the cache mechanism for the ChannelFactory if you use the ClientBase in the client instead of the pure ChannelFactory. But the cache will be expired if you make some anditional operations(Please google it for details if you want).
For the ErOx's issue i got another solution i think it is better. see below:
namespace ChannelFactoryCacheDemo
{
public static class ChannelFactoryInitiator
{
private static Hashtable channelFactories = new Hashtable();
public static ChannelFactory Initiate(string endpointName)
{
ChannelFactory channelFactory = null;
if (channelFactories.ContainsKey(endpointName))//already cached, get from the table
{
channelFactory = channelFactories[endpointName] as ChannelFactory;
}
else // not cached, create and cache then
{
channelFactory = new ChannelFactory(endpointName);
lock (channelFactories.SyncRoot)
{
channelFactories[endpointName] = channelFactory;
}
}
return channelFactory;
}
}
class AppWhereUseTheChannel
{
static void Main(string[] args)
{
ChannelFactory channelFactory = ChannelFactoryInitiator.Initiate("MyEndpoint");
}
}
interface IMyContract { }
}
you can customize the logic and the parameters of the Initiate method yourself if you got another requirement. but this initiator class is not limited only one endpoint. it is powerful for all of the endpoint in your application. hopefully. it works well for you. BTW. this solution is not from me. i got this from a book.

How to receive value from an asynchronous method located in a seperate class?

I was working on an application that makes quite a few requests using the HttpWebRequest class to bring back data from the web. Now my app makes nearly identical calls in multiple parts of my application. This is turning into a problem because I'm duplicating a lot of code.
The ideal solution would be to encapsulate the logic that makes the calls to the web in it's own class that way updating is a breeze and it can be reused throughout my application. I'm just not sure how to make an asynchronous call in a separate class and return the value to my main code behind so I can update the UI with the data.
Can someone provide me with some guidance on how to make this happen? I know this has to be possible because developers are doing it all the time when following the MVVM pattern.
I'm using Silverlight/C#.
We have code like this in our Silverlight app for use with WCF Data Services. You could probably do something similar for your web requests:
Here is some sample code (untested) (note that I have not actually ever written any code that does web requests, but maybe the async pattern is similar to other stuff that I have done in Silverlight):
public class WebRequesterHelper
{
Action _callback;
public void MakeWebRequest(object whateverYouNeedForTheWebRequest, Action callback)
{
_callback = callback;
//Make your async web request here, passing the helper object's callback.
IAsyncResult result = yourWebRequestObject.BeginGetResponse(new AsyncResultCallback(WebRequestCallback), yourRequestState);
}
public void WebRequestCallback(IAsyncResult result)
{
//Do whatever you need to do as a result of the web request, then call the callback.
if (_callback != null) callback();
}
}
In your code that wants to make a web request:
var helper = new WebRequestHelper();
//Setup the web request
object request = SetUpYourWebRequest();
helper.MakeWebRequest(request, OnWebRequestCompleted);
Your helper callback:
public void OnWebRequestCompleted()
{
//Web request is finished, what do I want to do?
}
Note that you might want your callback (which you pass to the WebRequestHelper object) to accept a parameter and you could pass information back out from the web request callback function (in the WebRequestHelper object).
Since your web download code is effectively your business logic I would definitely encapsulate it in it's own class as you planned. Then you should use events to notify your UI of state changes.
For example, your "WebRequestManager" instance can encapsulate all the thread handling and will raise events to allow the UI to respond accordingly. You would raise an event on TaskCompleted and perhaps also at intervals to provide looking feedback such as AsyncProgressChanged.
NOTE: By way of convention, I would tend to prefix any events that are likely going to be called from a thread other than the original calling one with the name "Async" so that the UI handler knows to join back onto the UI thread.

Fire and Forget (Asynch) ASP.NET Method Call

We have a service to update customer information to server. One service call takes around few seconds, which is normal.
Now we have a new page where at one instance around 35-50 Costumers information can be updated. Changing service interface to accept all customers together is out of question at this point.
I need to call a method (say "ProcessCustomerInfo"), which will loop through customers information and call web service 35-50 times. Calling service asynchronously is not of much use.
I need to call the method "ProcessCustomerInfo" asynchronously. I am trying to use RegisterAsyncTask for this. There are various examples available on web, but the problem is after initiating this call if I move away from this page, the processing stops.
Is it possible to implement Fire and Forget method call so that user can move away (Redirect to another page) from the page without stopping method processing?
Details on: http://www.codeproject.com/KB/cs/AsyncMethodInvocation.aspx
Basically you can create a delegate which points to the method you want to run asynchronously and then kick it off with BeginInvoke.
// Declare the delegate - name it whatever you would like
public delegate void ProcessCustomerInfoDelegate();
// Instantiate the delegate and kick it off with BeginInvoke
ProcessCustomerInfoDelegate d = new ProcessCustomerInfoDelegate(ProcessCustomerInfo);
simpleDelegate.BeginInvoke(null, null);
// The method which will run Asynchronously
void ProcessCustomerInfo()
{
// this is where you can call your webservice 50 times
}
This was something I whipped just to do that...
public class DoAsAsync
{
private Action action;
private bool ended;
public DoAsAsync(Action action)
{
this.action = action;
}
public void Execute()
{
action.BeginInvoke(new AsyncCallback(End), null);
}
private void End(IAsyncResult result)
{
if (ended)
return;
try
{
((Action)((AsyncResult)result).AsyncDelegate).EndInvoke(result);
}
catch
{
/* do something */
}
finally
{
ended = true;
}
}
}
And then
new DoAsAsync(ProcessCustomerInfo).Execute();
Also need to set the Async property in the Page directive <%# Page Async="true" %>
I'm not sure exactly how reliable this is, however it did work for what I needed it for. Wrote this maybe a year ago.
I believe the issue is the fact is your web service is expecting a client to return the response to, that the service call itself is not a one way communication.
If you're using WCF for your webservices look at http://moustafa-arafa.blogspot.com/2007/08/oneway-operation-in-wcf.html for making a one way service call.
My two cents: IMO whoever put the construct on you that you're not able to alter the service interface to add a new service method is the one making unreasonable demands. Even if your service is a publicly consumed API adding a new service method shouldn't impact any existing consumers.
Sure you can.
I think what you are wanting is a true background thread:
Safely running background threads in ASP.NET 2.0
Creating a Background Thread to Log IP Information

Categories