Tag Archives: In App Purchase

Cannot change thread mode after it is set

I recently published this article on using asynchonous methods within a Windows Game, and this article on enabling consumables within a Windows Game

However, I encountered a problem when I tried to use these two methods in combination. My code looked something like this:

var result = MessageBoxHelper.MsgBox.ShowAsync(string.Format("You do not have sufficient widgets for this.\n" +
    "Would you like to purchase more?"), MessageBoxButton.YesNo).ContinueWith(async (answer) =>
{
    if (answer.Result == MessageBoxResult.Yes)
    {
        bool purchTask = await Purchase.RequestProductPurchase(WIDGETS);

However, when I ran this; I got the following exception:

cannotchangethread

This is a marginally documented error:

By Microsoft and by Stack Overflow

I could call the function Purchase.RequestProductPurchase directly, but not, for some reason, in conjunction with ContinueWith. I tried this combination in a basic console application:

        static void Main(string[] args)
        {
            continueWithTest();
        }

        private static void continueWithTest()
        {
            MyAsyncFunc().ContinueWith(async (a) =>
            {
                Console.WriteLine("test");
                await Task.Delay(2000);                
            }).Wait();
            Console.ReadLine();
        }
        static async Task MyAsyncFunc()
        {
            await Task.Delay(2000);
            Console.WriteLine("Test1");
    }

And it worked fine. Based on what is available to read on the web, it looks like the threading model is, in some way, different when using ContinueWith. Although, it would appear that if you specify the TaskScheduler.Current, you should be able to use this in place of await, but that seems to make no difference.

The fix, as so many people are quick to point out, is use await:

        private void MakePurchase(int cost, Action onSuccess, bool interactive)
        {
            if (App.settings.CashPot.Total > cost)
            {
                App.settings.CashPot.Total -= cost;
                onSuccess.Invoke();                
            }
            else if (interactive)
            {
                InsufficientFunds(cost, onSuccess);
            }
        }


        private async void InsufficientFunds(int cost, Action onSuccess)
        {
            var result = await MessageBoxHelper.MsgBox.ShowAsync(string.Format("You do not have sufficient funds for this.\n" +
                "Would you like to purchase additional cash?"),
                "Insufficient Funds", MessageBoxButton.YesNo);                
                            
            if (result == MessageBoxResult.Yes)
            {
                bool purchTask = await Purchase.RequestProductPurchase(WIDGETS);

                MakePurchase(cost, onSuccess, false);
            }
        }

Enabling Consumable Purchases in Windows Store Apps

What are consumables

Consumables are a type of in-app purchase that can be used within your app or game; by used, I mean, for example, coin, food, life-force, credit; anything that can be bought and then the same item be bought again. This is opposed to durables, which are in-app purchases, such as removing adverts, premium features, etc.

Where to go first

The MSDN article does cover most of what you need. However, it doesn’t seem to cover everything, hence this post.

The documentation for the CurrentAppSimulator is also useful.

The Principle

Actual purchasing is done through the CurrentApp class. However, there is an identical test version of this, which simulates the purchasing of in-app products. Part of the store certification process is to ensure you haven’t forgotten to switch these to their live counterparts; although using the #Debug and #Release configurations might be an idea, too (see the bottom of this post for more details on this).

Step 1 – WindowsStoreProxy.xml

When you run your application in real life, it will download the purchase information from the store. However, when you’re testing, you need to simulate this. The linked documents do have examples; however, IMHO, they don’t completely explain the implications of each section. Here’s an XML file:

<?xml version="1.0" encoding="utf-16" ?>
<CurrentApp>
  <ListingInformation>
    <App>
      <AppId>988b90e4-5d4d-4dea-99d0-e423e414ffbc</AppId>
      <LinkUri>http://apps.windows.microsoft.com/app/988b90e4-5d4d-4dea-99d0-e423e414ffbc</LinkUri>
      <CurrentMarket>en-gb</CurrentMarket>
      <AgeRating>12</AgeRating>
      <MarketData xml:lang="en-gb">
        <Name>App with several in-app products</Name>
        <Description>Sample app for demonstrating an expiring in-app product and a consumable in-app product</Description>
        <Price>0.00</Price>
        <CurrencySymbol>£</CurrencySymbol>
      </MarketData>
    </App>
    <Product ProductId="MORE_CASH_1000" LicenseDuration="0" ProductType="Consumable">
      <MarketData xml:lang="en-gb">
        <Name>Consumable Item</Name>
        <Price>0.99</Price>
        <CurrencySymbol>£</CurrencySymbol>
      </MarketData> 
    </Product>
  </ListingInformation>
  <LicenseInformation>
    <App>
      <IsActive>true</IsActive>
      <IsTrial>false</IsTrial>
    </App>
  </LicenseInformation>
  <!--
  <ConsumableInformation>
    <Product ProductId="MORE_CASH_1000" TransactionId="00000001-0000-0000-0000-000000000000" Status="Active" />
  </ConsumableInformation>
  -->
</CurrentApp>

It looks a lot like the MS example, with a few key differences: firstly, it only contains a single consumable; second, it’s in GBP; and thirdly, the “ConsumableInformation” is commented out. The single consumable is just because that’s what I’m working with, but the other two burnt me:

  • If you change the language or currency, you need to be consistent. I left an en-us in and it, point blank, refused to read the document. I spent a while checking the XML was the correct format, and finally just guessed at this.
  • The ConsumableInformation node is commented out. If you put it in, then when you read the license, it will tell you that it is unfulfilled. This is definitely useful for testing, but looks like a bug in your code if you don’t know this.

Store this in a Data folder within the project:

consumables1

Step 2 – Create a helper class for managing the purchase

Obviously, this isn’t a requirement; but I would create a class for each consumable purchase. If you have common code then create a helper and base class as well.

namespace BetRaces.Purchases
{
    public class Purchase
    {
        public const string MORE_CASH_PRODUCT = "MORE_CASH_1000";
        public const int MORE_CASH_AMOUNT = 1000;

The following steps are building on the existence of such a class.

Step 3 – Create a dictionary of purchased GUIDs

The idea here is that you can track what has been bought.

private Dictionary<string, List<Guid>> grantedConsumableTransactionIds;

Step 4 – Grant Feature Locally

If you read the linked documents, they suggest a version of this function; basically, you need a function that will perform the task that you’ve asked for. In this case, it will manage the purchase of the coins, time, bonus, whatever. The following code is pretty much an exact duplicate of that offered by MS:

        private async void GrantFeatureLocally(string productId, Guid transactionId)
        {
            if (grantedConsumableTransactionIds == null)
                grantedConsumableTransactionIds = new Dictionary<string, List<Guid>>();

            if (!grantedConsumableTransactionIds.ContainsKey(productId))
            {
                grantedConsumableTransactionIds.Add(productId, new List<Guid>());
            }
            grantedConsumableTransactionIds[productId].Add(transactionId);

            // Grant the user their content. You will likely increase some kind of gold/coins/some other asset count.
            App.settings.CashPot.Total += MORE_CASH_AMOUNT;
            App.settings.SaveSettings();  // Ensure that the purchase is saved before reporting it as successful.
            FulfillmentResult result = await CurrentAppSimulator.ReportConsumableFulfillmentAsync(MORE_CASH_PRODUCT, transactionId);

        }

Step 5 – Get Unfulfilled Consumables

The reasoning here is that you have started to make a purchase, but the line above `ReportConsumableFulfillmentAsync` has not been called. This then sits in a status which blocks future purchases.

        private async Task GetUnfulfilledConsumables()
        {
            var products = await CurrentAppSimulator.GetUnfulfilledConsumablesAsync();

            foreach (UnfulfilledConsumable product in products)
            {
                GrantFeatureLocally(product.ProductId, product.TransactionId);
            }
        }

Obviously, there is a risk that the code in step 4 will crash just at the point before you report the fulfilment; however, I’d rather that, than the user having paid for something they haven’t received.

Step 6 – Purchase

The next stage is a RequestProductPurchase() method; here’s the code:

        public async Task<bool> RequestProductPurchase(string productId)
        {
            Uri uri = new Uri("ms-appx:///Data/WindowsStoreProxy.xml");
            Windows.Storage.StorageFile storeProxy = await StorageFile.GetFileFromApplicationUriAsync(uri);

            await CurrentAppSimulator.ReloadSimulatorAsync(storeProxy);
            
            Guid product1TempTransactionId;

            PurchaseResults purchaseResults = await CurrentAppSimulator.RequestProductPurchaseAsync(productId);
            if (purchaseResults == null) return false;

            switch (purchaseResults.Status)
            {
                case ProductPurchaseStatus.Succeeded:
                    product1TempTransactionId = purchaseResults.TransactionId;

                    // Grant the user their purchase here, and then pass the product ID and transaction ID to currentAppSimulator.reportConsumableFulfillment
                    // To indicate local fulfillment to the Windows Store.
                    GrantFeatureLocally(productId, product1TempTransactionId);
                    return true;

                case ProductPurchaseStatus.NotFulfilled:
                    product1TempTransactionId = purchaseResults.TransactionId;

                    // First check for unfulfilled purchases and grant any unfulfilled purchases from an earlier transaction.
                    await GetUnfulfilledConsumables();

                    // Once products are fulfilled pass the product ID and transaction ID to currentAppSimulator.reportConsumableFulfillment
                    // To indicate local fulfillment to the Windows Store.
                    if (grantedConsumableTransactionIds != null && grantedConsumableTransactionIds.ContainsKey(productId))
                        return true;
                    return false;                    
            }

            return false;
        }

The above code is what I was referring to in Step 1, when I mentioned the NotFulfilled return status.

Step 7 – Test the change

When you try to make a purchase, you should see a screen such as this:

consumables2

You can then test possible eventualities.

Step 8 – Enable them in the store

The next step is to enable your purchases in the App Store. The code has to be the same; and for larger games (the producers of which will probably not be reading posts such as this) the codes will be generated on a server, so they can manage special offers, etc. centrally.

In the Services section of the dashboard:

consumables3

Now enter your offer code, along with the price and make it a “Consumable”:

consumables4

Step 9 – The Old Switcheroo

All you need to do now is to substitute CurrentAppSimulator for CurrentApp.

Because both classes are static, I couldn’t find a better way than this:

#if DEBUG
            PurchaseResults purchaseResults = await CurrentAppSimulator.RequestProductPurchaseAsync(productId);
#else
            PurchaseResults purchaseResults = await CurrentApp.RequestProductPurchaseAsync(productId);
#endif

Windows Store Apps automatically compile in Release mode for the store.

Once you’ve found all the CurrentAppSimulator references and replaced them with this conditional construct (by my count there are 4 places for this); you should see the following when you try to make the purchase:

consumables5

consumables6

Conclusion

The links at the start are by far the best resource available for this; but hopefully this will fill in a couple of the gaps that tripped me up.

Using Asynchronous methods within a Windows Game

The new async / await syntax in .NET 4.5 + makes asynchronous programming really easy. However, there are times when having an assumption of asynchrony can impede you. One such example is programming for games (see my post on why you might want to avoid this).

However, what happens when you want to display a windows message box, or some other action that is asynchronous; See my post on a message box helper for an example.

In my particular case, I was to show a message box asynchronously, and perform a certain action based on the result; however, I don’t want to stop the game, and I don’t want to have to introduce an async / await into the programming model (for reasons in the linked post).

My solution was to use a combination of two, slightly outdated, methods of asynchronous programming: call backs and continuation blocks (strictly speaking, async / await does use continuation blocks behind the scenes admittedly). The following code will attempt to make an in-app purchase from the store:

        internal static async Task<bool> PurchaseCash()
        {
            var result = await Windows.ApplicationModel.Store.CurrentApp.RequestProductPurchaseAsync(PURCHASE);
            return (result.Status == ProductPurchaseStatus.Succeeded);
        }

What that function actually does it not important; however, it needs to be called from within a game loop. Here’s how it is called:

                        Purchase.PurchaseCash().ContinueWith((purchaseTask) =>
                        {
                            purchaseTask.Wait();
                            if (purchaseTask.Result)
                            {
                                App.settings.CashPot.Total += Purchases.Purchase.MORE_CASH_AMOUNT;
                            }

                        });

This will only execute the purchase action if the purchase was successful; it’s completely asynchronous, and it doesn’t affect the main thread. All well and good, but what if, instead of a specific task, we wanted to execute a conditional command; for example: when the purchase is called, we want to turn on a specific feature.

In this case, I decided to use a call back; the method signature looks like this:

        private bool MakePurchase(int cost, Action onSuccess)

And it is called like this:

                    if (!App.settings.Purchase1)
                    {
                        MakePurchase(PURCHASE1_COST, () =>
                        {
                            App.settings.Feature1 = true;
                        });
                    }

Inside MakePurchase, I only call the onSuccess method where the purchase was successful:

                        Purchase.PurchaseCash().ContinueWith((purchaseTask) =>
                        {
                            purchaseTask.Wait();
                            if (purchaseTask.Result)
                            {
                                onSuccess.Invoke();
                            }
                        }

Conclusion

The syntax above is nowhere near as clear and concise as a simple await statement; however, await statements can’t be used outside of an async method and, especially when programming games, that’s not always practical. The other thing that I haven’t mentioned here is exception handling – I may make that the subject of a later post.