How AgFx Works
AgFx works by managing your data objects so you don't have to.
General request pattern
Each time a Load request is made, AgFx checks the cache to see if a value exists to satisfy that request. If the value is not available, AgFx will attempt to fetch a new value.
If there is a value in memory, and it's within it's valid period (meaning it's not expired), then that value will be returned immediately. But in most cases, the fetch happens asynchronously, with the application receiving the updated value in one of two ways:
- The instance returned from Load has its property values updated. AgFx does instance tracking such that all fetch calls end up updating the same object. So that means, if your the returned is bound to two different parts of your UI, both will be updated.
AgFx will will never return a null value from a Load<> call. The call will either contain the current value, or a new instance that will be updated. In the new instance case, or in the case where the current value is expired, an asynchronous
fetch will be kicked off, and the instance's properties will be updated when it completes.
- The application passed an Action<T> handler into the load call to receive the value, where T is the model object type. This notification will happen
on the UI thread, and it will be the same instance as that returned from the Load call initially.
This diagram summarizes this process, see below for more details.
It all starts with DataManager.Current.Load<T>:
GetLoadRequest is a call to your DataLoader.GetLoadRequest implementation. This returns an object of type LoadRequest, which is an abstract base class that tells AgFx how to request data. In
most cases, your app will simply build a URL and wrap it into a WebLoadRequest instance and then return that value to AgFx. Note that WebLoadRequest is customizable to support POST and other more advanced HttpWebRequest operations, you
can check it out. For more advanced scenarios, see LoadReqeuest.Execute().
Fetch value is generally where the request happens for new data, usually a web request, in which case it happens on a network or thread pool thread. From the point of view of AgFx, this is a call to LoadRequest.Execute().
Deserialize is a call to your DataLoad.Deserialize implementation, where it will receive the Stream of data that was passed back to AgFx from the
LoadRequest.Execute action callback. This method should take this stream and materialize an object of the specified model type (passed as the objectType parameter in case multiple types are sharing a loader). Since the raw stream
is cached by default, a cache-hit Deserialize call receives the same value, but loaded from the store. Deserialize is not aware of where the data is coming from between the store and a new fetch.
Serialize to store happens automatically after Deserialize
has successfully completed. In most cases, this is serializing the raw data passed to Deserialize (see
IDataOptimizer to modify this data before writing).
Check cache policy examines the object type looking for a CachePolicy attribute. If one is not found, it defaults to CachePolicy.CacheThenRefresh, with an expiration of 5 minutes. If CachePolicy is set to NoCache, or if the cache
has expired, then a fetch is initiated. If CachePolicy is set to AutoRefresh or CacheThenRefresh, and a cache exists, that cache value is loaded in parallel with a request for an updated value. If the updated value comes back before the load from
the cache, the cache load will be cancelled or ignored.
AgFx holds values as
Weak References, so simply having an object managed by AgFx will not hold it in memory.
This means that your application must be holding a reference to the object some where, be it as a UI Element's DataContext (preferred in most cases), or as part of page or other view model.
When a request for an object happens, and AgFx discovers that the value has been GC'd, it falls back to the general request pattern described above by first checking the cache for a valid value, then moving on to a fetch of a new value if necessary.