I'm using monogame as a framework for games and I'm trying to implement a in-app-purchase-functionality in an UWP-App which throws an exception when I'm calling RequestProductPurchaseAsync. It states:
Cannot change thread mode after it is set. (Exception from HRESULT:
0x80010106 (RPC_E_CHANGED_MODE)) at
Windows.ApplicationModel.Store.CurrentAppSimulator.RequestProductPurchaseAsync(String
productId) at
Crocs_World__Xbox_Edition_.App.d__7.MoveNext()
That's what I'm doing in code:
public async Task LoadInAppPurchaseProxyFileAsync()
{
StorageFolder proxyDataFolder = await Package.Current.InstalledLocation.GetFolderAsync("data");
StorageFile proxyFile = await proxyDataFolder.GetFileAsync("in-app-purchase.xml");
licenseChangeHandler = new LicenseChangedEventHandler(InAppPurchaseRefreshScenario);
CurrentAppSimulator.LicenseInformation.LicenseChanged += licenseChangeHandler;
await CurrentAppSimulator.ReloadSimulatorAsync(proxyFile);
// setup application upsell message
try
{
ListingInformation listing = await CurrentAppSimulator.LoadListingInformationAsync();
var product1 = listing.ProductListings["product1"];
var product2 = listing.ProductListings["product2"];
}
catch (Exception e)
{
Debug.WriteLine("LoadListingInformationAsync API call failed:" + e);
}
}
private async void InAppPurchaseRefreshScenario()
{
Debug.WriteLine("InAppPurchaseRefreshScenario");
}
public async Task BuyFeature()
{
LicenseInformation licenseInformation = CurrentAppSimulator.LicenseInformation;
if (!licenseInformation.ProductLicenses["product2"].IsActive)
{
Debug.WriteLine("Buying Product 2...");
try
{
await CurrentAppSimulator.RequestProductPurchaseAsync("product2");
if (licenseInformation.ProductLicenses["product2"].IsActive)
{
Debug.WriteLine("You bought Product 2.");
}
else
{
Debug.WriteLine("Product 2 was not purchased.");
}
}
catch (Exception e)
{
Debug.WriteLine("Unable to buy Product 2." + e);
}
}
else
{
Debug.WriteLine("You already own Product 2.");
}
}
Whenever I call BuyFeature it throws the exception. Except if I call it right in LoadInAppPurchaseProxyFileAsync. Then it seems to be in the same thread I guess.
If I replace Task with void in both methods it doesn't work either. It also doesn't matter if I call it from app.xaml.cs or the game.cs.
Does anybody have an idea what I'm doing wrong?
Thank you,
Harry
You have to call await CurrentAppSimulator.RequestProductPurchaseAsync(...) in the UI thread, because if you run it in release mode with await CurrentApp.RequestProductPurchaseAsync(...) it shows a "Buy item" content dialog on the screen which is only possible in the UI thread.
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
await CurrentAppSimulator.RequestProductPurchaseAsync("product2");
};
Related
btnSave Event: in this event i wana update datagridview but it's not working :(
private async void btnSave_Click(object sender, EventArgs e)
{
if (this.ValidateChildren(ValidationConstraints.Enabled))
{
Remember remember = new Remember();
remember.RememberTitle = txtTitle.Text;
remember.RememberDate = dateTimePickerRememberDate.Value.Date;
remember.RememberTime = dateTimePickerRememberTime.Value.TimeOfDay;
remember.RememberContent = txtDescription.Text;
remember.RememberTransaction = false;
remember.RememberExpire = false;
var res = await Rep_App.NewRemember(remember).ConfigureAwait(false);
if (res)
{
MessageBox.Show("Success");
//this line did not executed
await GetRemembers();
}
else
{
MessageBox.Show("...");
}
}
}
GetRemember method :
private async Task GetRemembers()
{
try
{
// Instantiate a new DBContext
ParkingManager.Context.DataBaseContext dbContext = new ParkingManager.Context.DataBaseContext(PublicVariables.ConnectionString);
// Call the LoadAsync method to asynchronously get the data for the given DbSet from the database.
await dbContext.Remembers.LoadAsync().ContinueWith(loadTask =>
{
// Bind data to control when loading complete
remembersBindingSource.DataSource = dbContext.Remembers.ToList();
}, System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext());
}
catch (InvalidOperationException)
{
return;
}
catch (Exception)
{
MessageBox.Show(MessagesStruct.Exception);
}
}
GetRemember() did not execute in Save Event but when the form loaded GetRemember() executed completely, what's wrong?
The problem is caused by ConfigureAwait(false) and ContinueWith. ConfigureAwait(false) will cause execution to continue on a background thread instead of getting back to the UI. LoadAsync isn't needed either, the data will be loaded by ToList or ToListAsync().
EF Core and async/await don't need so much code. All of this can be replaced with
var res = await Rep_App.NewRemember(remember);
if (res)
{
MessageBox.Show("Success");
using(var dbContext = new DataBaseContext(PublicVariables.ConnectionString))
{
remembersBindingSource.DataSource = await dbContext.Remembers.ToListAsync();
}
}
else
{
MessageBox.Show("...");
}
I'm using Two await function in my program, and first one is working flawlessly but on encountering second await, my program comes out of function without executing that awaitable function and any line after that.
Not giving error and not even crashing.
Tried "wait()", "Running on main thread", "Task Run", "Threading Sleep"..
here a snippet of the code along
private async void Btn_Clicked(object sender, EventArgs e)
{
//this statement works perfectly fine
var status = await CrossPermissions.Current.RequestPermissionAsync<LocationPermission>();
//on debugging i found out it return out of function at this point without executing
var check = await CrossPermissions.Current.RequestPermissionAsync<CameraPermission>();
//None of the code is executed
Console.WriteLine("Granted");
Console.WriteLine("Granted");
}
You try to use the below method :
private async void Btn_Clicked(object sender, EventArgs e)
{
await GetPermissions();
}
public static async Task<bool> GetPermissions()
{
bool permissionsGranted = true;
var permissionsStartList = new List<Permission>()
{
Permission.Location,
Permission.Camera,
};
var permissionsNeededList = new List<Permission>();
try
{
foreach (var permission in permissionsStartList)
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
if (status != Plugin.Permissions.Abstractions.PermissionStatus.Granted)
{
permissionsNeededList.Add(permission);
}
}
}
catch (Exception ex)
{
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(permissionsNeededList.ToArray());
try
{
foreach (var permission in permissionsNeededList)
{
var status = Plugin.Permissions.Abstractions.PermissionStatus.Unknown;
//Best practice to always check that the key exists
if (results.ContainsKey(permission))
status = results[permission];
if (status == Plugin.Permissions.Abstractions.PermissionStatus.Granted || status == Plugin.Permissions.Abstractions.PermissionStatus.Unknown)
{
permissionsGranted = true;
}
else
{
permissionsGranted = false;
break;
}
}
}
catch (Exception ex)
{
}
return permissionsGranted;
}
I would like to know if the code I produced is good practice and does not produce leaks, I have more than 7000 objects Participant which I will push individually and Handle the Response to save the "external" id in our database. First I use the Parallel ForEach on the list pPartcipant:
Parallel.ForEach(pParticipant, participant =>
{
try
{
//Create
if (participant.id == null)
{
ExecuteRequestCreate(res, participant);
}
else
{//Update
ExecuteRequestUpdate(res, participant);
}
}
catch (Exception ex)
{
LogHelper.Log("Fail Parallel ", ex);
}
});
Then I do a classic (not async request), but after I need to "handle" the response (print in the console, save in a text file in async mode, and Update in my database)
private async void ExecuteRequestCreate(Uri pRes, ParticipantDo pParticipant)
{
try
{
var request = SetRequest(pParticipant);
//lTaskAll.Add(Task.Run(() => { ExecuteAll(request, pRes, pParticipant); }));
//Task.Run(() => ExecuteAll(request, pRes, pParticipant));
var result = RestExecute(request, pRes);
await HandleResult(result, pParticipant);
//lTaskHandle.Add(Task.Run(() => { HandleResult(result, pParticipant); }));
}
catch (Exception e)
{
lTaskLog.Add(LogHelper.Log(e.Message + " " + e.InnerException));
}
}
Should I run a new task for handeling the result (as commented) ? Will it improve the performance ?
In comment you can see that I created a list of tasks so I can wait all at the end (tasklog is all my task to write in a textfile) :
int nbtask = lTaskHandle.Count;
try
{
Task.WhenAll(lTaskHandle).Wait();
Task.WhenAll(lTaskLog).Wait();
}
catch (Exception ex)
{
LogHelper.Log("Fail on API calls tasks", ex);
}
I don't have any interface it is a console program.
I would like to know if the code I produced is good practice
No; you should avoid async void and also avoid Parallel for async work.
Here's a similar top-level method that uses asynchronous concurrency instead of Parallel:
var tasks = pParticipant
.Select(participant =>
{
try
{
//Create
if (participant.id == null)
{
await ExecuteRequestCreateAsync(res, participant);
}
else
{//Update
await ExecuteRequestUpdateAsync(res, participant);
}
}
catch (Exception ex)
{
LogHelper.Log("Fail Parallel ", ex);
}
})
.ToList();
await Task.WhenAll(tasks);
And your work methods should be async Task instead of async void:
private async Task ExecuteRequestCreateAsync(Uri pRes, ParticipantDo pParticipant)
{
try
{
var request = SetRequest(pParticipant);
var result = await RestExecuteAsync(request, pRes);
await HandleResult(result, pParticipant);
}
catch (Exception e)
{
LogHelper.Log(e.Message + " " + e.InnerException);
}
}
I am trying a Background Downloader for Windows 8.1. This is the HandleDownloadAsync() which I got from the Background Downloader sample.
It started getting a FileNotFound Exception at
await download.StartAsync().AsTask(cts.Token, progressCallback);
It was working a few days back and I haven't changed the code. All the variables are assigned the correct values too.
What is wrong?
async void HandleDownloadAsync(DownloadOperation download, bool start)
{
activeDownloads.Add(download);
try
{
Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(ProgressCallback);
if (start)
{
await download.StartAsync().AsTask(cts.Token, progressCallback);
}
else
{
await download.AttachAsync().AsTask(cts.Token, progressCallback);
}
}
catch (Exception ex)
{
}
finally
{
activeDownloads.Remove(download);
}
}
The fact that we can't use the await keyword in catch blocks makes it quite awkward to show error messages from async methods in WinRT, since the MessageDialog API is asynchronous. Ideally I would like be able to write this:
private async Task DoSomethingAsync()
{
try
{
// Some code that can throw an exception
...
}
catch (Exception ex)
{
var dialog = new MessageDialog("Something went wrong!");
await dialog.ShowAsync();
}
}
But instead I have to write it like this:
private async Task DoSomethingAsync()
{
bool error = false;
try
{
// Some code that can throw an exception
...
}
catch (Exception ex)
{
error = true;
}
if (error)
{
var dialog = new MessageDialog("Something went wrong!");
await dialog.ShowAsync();
}
}
All methods that need to do this have to follow a similar pattern, which I really don't like, because it reduces the code readability.
Is there a better way to handle this?
EDIT: I came up with this (which is similar to what svick suggested in his comments):
static class Async
{
public static async Task Try(Func<Task> asyncAction)
{
await asyncAction();
}
public static async Task Catch<TException>(this Task task, Func<TException, Task> handleExceptionAsync, bool rethrow = false)
where TException : Exception
{
TException exception = null;
try
{
await task;
}
catch (TException ex)
{
exception = ex;
}
if (exception != null)
{
await handleExceptionAsync(exception);
if (rethrow)
ExceptionDispatchInfo.Capture(exception).Throw();
}
}
}
Usage:
private async Task DoSomethingAsync()
{
await Async.Try(async () =>
{
// Some code that can throw an exception
...
})
.Catch<Exception>(async ex =>
{
var dialog = new MessageDialog("Something went wrong!");
await dialog.ShowAsync();
});
}
.Catch<...> calls can be chained to mimick multiple catch blocks.
But I'm not really happy with this solution; the syntax is even more awkward than before...
you already have that functionality in TPL
await Task.Run(async () =>
{
// Some code that can throw an exception
...
}).ContinueWith(async (a) =>
{
if (a.IsFaulted)
{
var dialog = new MessageDialog("Something went wrong!\nError: "
+ a.Exception.Message);
await dialog.ShowAsync();
}
else
{
var dialog2 = new MessageDialog("Everything is OK: " + a.Result);
await dialog2.ShowAsync();
}
}).Unwrap();
In this machine I don't have Windows 8 so I tested in Windows 7 but I think is the same.
*Edit
as stated in the comments its needed .Unwrap(); in the end for the await to work
C# 6 now supports await in catch and finally, so the code can be written the way I wanted it; a workaround is no longer needed.