http://forums.lhotka.net/forums/t/11789.aspx
Hi Rocky
Since moving over from 4.3 to 4.5 I'm experiencing a strange issue with the Xaml ViewModelBase when calling BeginSave() and the DataPortal throws an exception.
BeginSave works just fine when there is no exception on the server side data portal, however what I'm observing is that if the server side data portal throws an exception the exception is never received. Also, IsBusy stays stuck on true and OnError is never called.
I have a suspicion that the ViewModelBase class was initially a great help to work with the DataPortalResult callback pattern that was used pre-Async pattern.
I'm not sure which is now the preferred way of saving the business object under Silverlight when using the ViewModel and CSLA 4.5 with the Async pattern available.
Do we still call BeginSave() - doesn't this still employ the Callback pattern?
I see there is a new method on the ViewModel called SaveAsync() - this would typically be awaited upon, but then I'm curious what the exception handling strategy with that is, because I'm assuming that the SaveAsync on the ViewModel still sets the Error property and still calls OnError. Would an (aggregate task) exception ever be "returned" then when you call SaveAsync()?
Hopefully this makes some sense - love to get your input.
On a related note, I'm thinking that the following method is "missing" from CSLA ViewModel class:
protected virtual async Task RefreshAsync( Func<Task<T>> factoryMethod )
{
Error = null;
try
{
IsBusy = true;
var model = await factoryMethod();
OnRefreshing( model );
Model = model;
IsBusy = false;
}
catch ( Exception ex )
{
IsBusy = false;
Error = ex;
}
OnRefreshed();
}
In addition to the above, it looks like the issue has to do with the ISupportUndo.Saved event not being raised on the Silverlight client side in the event of an exception being thrown on the server side data portal.
This event is key to the current implementations of the BeginSave() and SaveAsync() methods on the Xaml.ViewModelBase class.
If I override the SaveAsync implementation with an awaited implementation (and not use the Saved event) then the exception reaches back to the Silverlight client. So it might be that the Saved event isn't being called correctly by the DataPortalClient implementation or that the event isn't being serialised correctly.
Here's the override implementation of ViewModelBase.SaveAsync() that fixes the above bug and works quite well. Perhaps this should be the replacement implementation?
protected override async Task<T> SaveAsync()
{
try
{
var savable = Model as Csla.Core.ISavable;
if ( ManageObjectLifetime )
{
// clone the object if possible
var clonable = Model as Csla.ICloneable;
if ( clonable != null )
savable = (Csla.Core.ISavable)clonable.Clone();
//apply changes
var undoable = savable as Csla.Core.ISupportUndo;
if ( undoable != null )
undoable.ApplyEdit();
}
Error = null;
IsBusy = true;
var model = await savable.SaveAsync();
OnSaving( model as T );
Model = (T)model;
IsBusy = false;
OnSaved();
return Model;
}
catch ( Exception ex )
{
IsBusy = false;
Error = ex;
OnSaved();
return null;
}
}