Windows Run Time GetFileFromPathAsync Not Returning - windows-store-apps

I am hoping someone can shed some light on a problem I am having. I am writing a Windows Store app which on startup needs to copy a "seed" database from the App installation folder Windows.ApplicationModel.Package.Current.InstalledLocation.Path to the Local data folder Windows.Storage.ApplicationData.Current.LocalFolder. To do this I have used the following called from my OnNavigatedTo method in Main().
protected override void OnNavigatedTo(NavigationEventArgs e)
{
//Calls method in Dal Class which ensures database is in correct location and if not copies it
Dal.LoadData();
RefreshScenarioList();
ScenarioList.SelectedIndex = 0; //this is the Default Item
}
public static async void LoadData()
{
await CopyIfNotExists(dbName);
}
private static async Task CopyIfNotExists(string dbName)
{
if (await GetIfFileExistsAsync(dbName) == null)
{
StorageFile seedFile = await StorageFile.GetFileFromPathAsync(
Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path,
dbName));
await seedFile.CopyAsync(Windows.Storage.ApplicationData.Current.LocalFolder);
}
}
private static async Task<StorageFile> GetIfFileExistsAsync(string key)
{
try
{
return await ApplicationData.Current.LocalFolder.GetFileAsync(key);
}
catch (FileNotFoundException) { return default(StorageFile); }
}
Please also note that I have also used GetFileAsync and also tried using a uri to obtain the seed file (to see if there was any difference). With the combination here I seem to be having the highest success rate. This seems to work 2-3 times out of every 4 tries but I would be much more comfortable with something that works 100% of the time. It only needs to copy the database once on startup.
When it doesn't work it "seems" to never return (ie CopyIfNotExists never seems to complete). The issue appears to be in the CopyIfNotExists method. The problem is that virtually the next line of code in my OnNavigatedTo method is a query on the database and it falls over when the database doesn't copy.
Any insights that anyone may have would be greatly appreciated.

From what I can see, the problem here is that your use of async and await does not go as far up the call stack as it can.
When writing async code, there are a couple of general rules to follow -
If a function Foo uses the async keyword, then any other function that calls Foo must also use the async keyword.
Never use async void in a function signature - use async Task instead. The exceptions are:
your function is an event handler (e.g. button press)
or you are overriding a method that happens to return void
Let's take a look at the method signatures on your call stack. OnNavigatedTo is shown here at the top:
override void OnNavigatedTo()
async void LoadData()
async Task CopyIfNotExists()
async Task<StorageFile> GetIfFileExistsAsync()
The bottom two methods of the call stack uses async Task in the method signatures. Above those on the call stack is LoadData, which follows rule 1 above, but breaks rule 2. LoadData should be changed to this:
public static async Task LoadData()
{
await CopyIfNotExists(dbName);
}
Next we try to make OnNavigatedTo follow the above rules:
async protected override void OnNavigatedTo(NavigationEventArgs e)
Note that we cannot use async Task, since your method is an override. We have to stick to async void.
Now you just need to add await to your LoadData call since it is an async method. We do this so that your program waits for LoadData to complete prior to calling RefreshScenarioList:
async protected override void OnNavigatedTo(NavigationEventArgs e)
{
//Calls method in Dal Class which ensures database is in correct location and if not copies it
await Dal.LoadData();
RefreshScenarioList();
ScenarioList.SelectedIndex = 0; //this is the Default Item
}
Now you will want to also ensure that the call stack for RefreshScenarioList follows the async rules above.
One more thing that I noticed with your code. In Windows 8.1 or later, you should use TryGetItemAsync instead of GetFileAsync:
private static async Task<StorageFile> GetIfFileExistsAsync(string key)
{
return await ApplicationData.Current.LocalFolder.TryGetItemAsync(key) as StorageFile;
}
The new method returns null when it cannot find a file. The old method throws an exception. Throwing exceptions on a UI thread can cause your UI to stall, so it is advantageous to use the new method.

Related

Apache HttpAsyncClient and CountDownLatch

When using apache htttpasyncclient how does one handle various exception cases properly? Consider the following pseudo code based on this example where I have added the consumer parameter to the execute call. The intention is to make an asynchronous http request where the data is processed as a stream when the bytes come in rather than waiting for the full response to be done before processing. Various issues can occur such as a timeout exception on the http request, failure to connect (could be no network), etc. Is it always guaranteed that for example on a timeout with a response not coming back in time that releaseResources() is always called. The question is where does latch.countDown() need to be put in the below code to always guarantee that the await call doesn't just hang no matter what the exception. Is the call to latch.countDown() in StreamConsumer.releaseResources() enough to prevent hanging on the await?
public static void main(final String[] args) throws Exception {
client.execute(HttpAsyncMethods.createGet(u), new StreamConsumer(...), new FutureCallback<Boolean>() {
#Override
public void cancelled() {
// Is latch call needed here?
// latch.countDown();
}
#Override
public void completed(Boolean response) {
// Is latch call needed here?
// latch.countDown();
}
#Override
public void failed(Exception e) {
// Is latch call needed here?
// latch.countDown();
}
});
latch.await();
}
static class StreamConsumer extends AsyncByteConsumer<Boolean> {
#Override
protected void onResponseReceived(final HttpResponse response) {
latch.countDown();
}
#Override
protected void onByteReceived(final ByteBuffer buf, final IOControl ioctrl) throws IOException {
}
#Override
protected void releaseResources() {
latch.countDown();
}
}
CloseableHttpAsyncClient#execute method terminates immediately upon submission of a request into the request execution pipeline and returns a Future object representing the future result of the operation.
Therefore the latch in the example is required to make sure that the client does not get shut down immediately after CloseableHttpAsyncClient#execute call.
If one uses CloseableHttpAsyncClient as a singleton with a defined life-cycle (as one should) synchronization of request completion and the client shutdown may be unnecessary.

Why does this handler not return anything?

I'm just starting the ASP.NET tutorial and I don't understand why there is no return statement in the method:
public async Task OnGetAsync()
{
Movie = await _context.Movie.ToListAsync();
}
Are one line methods automatically returned like arrow statements or does it have to do with the Task in ASP?
Its a model that have property Movie. That property gets set when method OnGetAsync is called. So, you don't need return.
Method return type is Task because it has await. Its analogous to void type if it would be a sync method.
if you want to return the list of Movie
then your function should be :
public async Task<List<Movie>> OnGetAsync()
{
return await _context.Movie.ToListAsync();
}

Async and await methods in MvvmCross

I am creating PCL using MvvmCross.
I am calling one method in Command which fetch data by calling web service.
I want to do this data fetch operation asynchronously.
How can I apply async and await to methods in Command ?
Any ideas?
There are a couple of options.
1) You can implement the command with an async void method/delegate. If you do this, I recommend you have the async void method just await a Task from an async Task method that contains the actual logic because async Task methods are easier to unit test. Also, you'll need a try/catch for proper error handling.
2) You can have the command just start a method returning Task<T> and expose the result of the operation as a property using NotifyTaskCompletion from my AsyncEx library. This allows you to data bind to the result as well as errors. However, AsyncEx does not support all the platforms MvvmCross does (in particular, Windows Phone 7.0 and Xamarin.Mac).
Update - examples:
Using the first option:
public ICommand ContactSlodgeCommand
{
get
{
return new MvxCommand(async () =>
{
await ComposeEmailAsync("me#slodge.com", "About MvvmCross and the SQL Bits app", "I've got a question"));
}
}
}
Using the second option:
private INotifyTaskCompletion<MyResource> _resource;
public INotifyTaskCompletion<MyResource> Resource
{
get { return _resource; }
set { _resource = value; NotifyPropertyChanged(); }
}
public ICommand LoadResourceCommand
{
get
{
return new MvxCommand(() =>
{
Resource = NotifyTaskCompletion.Create(LoadResourceAsync());
}
}
}
You should do data-binding for that property by using databinding of mvvmcross and use async await or Task like #Stephen Cleary said
void FetchData(Action<T> callback)
{
Task.Run<T>(()=>{
return Service.GetDataSynchronous();
}).ContinueWith((data)=>{
callback(data);
});
}
public MvxCommand
{
get
{
return new MvxCommand(()=>{
FetchData((data)=>{
this.Property = data;
});
});
}
}

Windows Phone link from Tile error

I have a list of theaters and I created a secondary tile from my application to navigate directly to specific theater. I pass the id of the theater in query string :
I load the theaters from a WCF service in the file "MainViewModel.cs"
In my home page, I have a list of theaters and I can navigate to a details page.
But when I want to navigate from the tile, I have an error...
The Tile :
ShellTile.Create(new Uri("/TheaterDetails.xaml?selectedItem=" + theater.idTheater, UriKind.Relative), tile, false);
My TheaterDetails page :
public partial class TheaterDetails : PhoneApplicationPage
{
theater theater = new theater();
public TheaterDetails()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
if (DataContext == null)
{
string selectedIndex = "";
if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
{
int index = int.Parse(selectedIndex);
theater = (from t in App.ViewModel.Theaters
where t.idTheater == index
select t).SingleOrDefault();
DataContext = theater;
....
....
....
The error :
https://dl.dropboxusercontent.com/u/9197067/error.png
Like if the data were not loaded...
Do you have an idea where the problem come from ?
The solution could be easy but I am a beginner... Maybe it's because I load the data asynchronously and the application doesn't wait until it's done...
Thanks
EDIT :
My LoadData() method :
public void LoadData()
{
client.GetTheatersCompleted += new EventHandler<ServiceReference1.GetTheatersCompletedEventArgs>(client_GetTheatersCompleted);
client.GetTheatersAsync();
// Other get methods...
this.IsDataLoaded = true;
}
private void client_GetTheatersCompleted(object sender, ServiceReference1.GetTheatersCompletedEventArgs e)
{
Theaters = e.Result;
}
You should check to see which variable is actually null. In this case it looks to be Theaters (otherwise the error would have thrown earlier).
Since Theaters is populated from a web call it is most likely being called asynchronously, in other words when you return from LoadData() the data is not yet there (it's still waiting for the web call to come back), and is waiting for the web service to return its values.
Possible solutions:
Make LoadData() an async function and then use await LoadData(). This might require a bit of rewriting / refactoring to fit into the async pattern (general introduction to async here, and specific to web calls on Windows Phone here)
A neat way of doing this that doesn't involve hacks (like looping until the data is there) is to raise a custom event when the data is actually populated and then do your Tile navigation processing in that event. There's a basic example here.
So the solution that I found, thanks to Servy in this post : Using async/await with void method
I managed to use async/await to load the data.
I replaced my LoadData() method by :
public static Task<ObservableCollection<theater>> WhenGetTheaters(ServiceClient client)
{
var tcs = new TaskCompletionSource<ObservableCollection<theater>>();
EventHandler<ServiceReference1.GetTheatersCompletedEventArgs> handler = null;
handler = (obj, args) =>
{
tcs.SetResult(args.Result);
client.GetTheatersCompleted -= handler;
};
client.GetTheatersCompleted += handler;
client.GetTheatersAsync();
return tcs.Task;
}
public async Task LoadData()
{
var theatersTask = WhenGetTheaters(client);
Theaters = await theatersTask;
IsDataLoaded = true;
}
And in my page :
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
await App.ViewModel.LoadData();
}

gwt with RequestFactory, handling server side exception on client and RequestFactoryEditorDriver

i use RequestFactory for communicating with server and RequestFactoryEditorDriver on the client side. So editing workflow looks like such way. Create new proxy for editing:
RequestContext reqCtx = clientFactory.getRequestFactory().Request();
UserAndAccountProxy userAndAccountProxy = reqCtx.create(UserAndAccountProxy.class);
reqCtx.saveAndReturnProfileAndAccount(userAndAccountProxy).to(
new Receiver<UserAndAccountProxy>() {
#Override
public void onSuccess(UserAndAccountProxy response) {
...
}
#Override
public void onFailure(ServerFailure error) {
...
}}
And Save button click handling:
RequestContext reqCtx = view.getEditorDriver().flush();
reqCtx.fire();
On server side saveAndReturnProfileAndAccount method can throw exceptions on persisting, which i can handle in onFailure method. After that if I create new proxy with new request context and pass it to my editor all fields will be blanked.
So what is proper way to execute request and if something goes wrong use data that user allready fill or maybe I made mistake in my editing worklow?
So, I think, I found solution. I made changes to function, which create RequestContext:
private void edit(MyProxy proxy) {
RequestContext reqCtx = clientFactory.getRequestFactory().Request();
if (proxy == null) {
// create proxy first time
proxy = reqCtx.create(UserAndAccountProxy.class);
} else {
// create immutable copy
proxy = reqCtx.edit(proxy);
}
final UserAndAccountProxy tmp = proxy;
reqCtx.saveAndReturnMyProxy(proxy).to(new Receiver<MyProxy>() {
#Override
public void onFailure(ServerFailure error) {
eventBus.showErrorInformation(error.getMessage());
//recursive call with already filled proxy
edit(tmp);
}
#Override
public void onSuccess(UserAndAccountProxy response) {
eventBus.showInformation("It`s ok!");
eventBus.goToMainPage(null);
}
});
// start editing with editor
getView().onEdit(tmp, reqCtx);
}
When we start editing proxy function edit need to bee called with null argument and new clean proxy will be created. After that we start edit it with Editor. On Save button click we execute request to server. If it ends with success - we open another page. If request ends with error, we create new immutable copy ant push it to editor.