2

Actually I've implmented ios in-app purchase & upon success, I receive json response. The json response contains PurchaseToken, which is basically a base64 encoded javascript string.

{
    "Id": "1000000872920320",
    "TransactionDateUtc": "2021-09-06T14:42:17Z",
    "ProductId": "1",
    "AutoRenewing": false,
    "PurchaseToken": "ewoJInNpZ25hdHVyZSIgPSAic29tZSBsb25nIGJhc2U2NCBzdHJpbmciOwoJInB1cmNoYXNlLWluZm8iID0gImV3b0pJbTl5YVdkcGJtRnNMWEIxY21Ob1lYTmxMV1JoZEdVdGNITjBJaUE5SUNJeU1EQXdMVEF4TFRBeElEQXhPakF4T2pBeElFRnRaWEpwWTJFdlRHOXpYMEZ1WjJWc1pYTWlPd29KSW5WdWFYRjFaUzFwWkdWdWRHbG1hV1Z5SWlBOUlDSnpiMjFsVlVsRUlqc0tDU0p2Y21sbmFXNWhiQzEwY21GdWMyRmpkR2x2YmkxcFpDSWdQU0FpVTI5dFpWUkpSQ0k3Q2draVluWnljeUlnUFNBaU15NDJJanNLQ1NKMGNtRnVjMkZqZEdsdmJpMXBaQ0lnUFNBaVUyOXRaVlJKUkNJN0Nna2ljWFZoYm5ScGRIa2lJRDBnSWpFaU93b0pJbWx1TFdGd2NDMXZkMjVsY25Ob2FYQXRkSGx3WlNJZ1BTQWlVRlZTUTBoQlUwVkVJanNLQ1NKdmNtbG5hVzVoYkMxd2RYSmphR0Z6WlMxa1lYUmxMVzF6SWlBOUlDSnpiMjFsSUc1MWJXVnlhV01nZEdsdFpTQnpkR0Z0Y0NCcGJpQnRjeUk3Q2draWRXNXBjWFZsTFhabGJtUnZjaTFwWkdWdWRHbG1hV1Z5SWlBOUlDSnpiMjFsSUZWSlJDSTdDZ2tpY0hKdlpIVmpkQzFwWkNJZ1BTQWlNU0k3Q2draWFYUmxiUzFwWkNJZ1BTQWljMjl0WlNCVmJtbHhkV1VnU1hSbGJTQkpSQ0k3Q2draWRtVnljMmx2YmkxbGVIUmxjbTVoYkMxcFpHVnVkR2xtYVdWeUlpQTlJQ0l3SWpzS0NTSnBjeTFwYmkxcGJuUnlieTF2Wm1abGNpMXdaWEpwYjJRaUlEMGdJbVpoYkhObElqc0tDU0p3ZFhKamFHRnpaUzFrWVhSbExXMXpJaUE5SUNKemIyMWxJRzUxYldWeWFXTWdkR2x0WlNCemRHRnRjQ0JwYmlCdGN5STdDZ2tpY0hWeVkyaGhjMlV0WkdGMFpTSWdQU0FpTWpBd01DMHdNUzB3TVNBd01Ub3dNVG93TVNCRmRHTXZSMDFVSWpzS0NTSnBjeTEwY21saGJDMXdaWEpwYjJRaUlEMGdJbVpoYkhObElqc0tDU0p2Y21sbmFXNWhiQzF3ZFhKamFHRnpaUzFrWVhSbElpQTlJQ0l5TURBd0xUQXhMVEF4SURBeE9qQXhPakF4SUVWMFl5OUhUVlFpT3dvSkltSnBaQ0lnUFNBaWFYQmhJR0Z3Y0NCaWRXNWtiR1VnYm1GdFpTSTdDZ2tpY0hWeVkyaGhjMlV0WkdGMFpTMXdjM1FpSUQwZ0lqSXdNREF0TURFdE1ERWdNREU2TURFNk1ERWdRVzFsY21sallTOU1iM05mUVc1blpXeGxjeUk3Q24wPSI7CgkiZW52aXJvbm1lbnQiID0gIlNhbmRib3giOwoJInBvZCIgPSAiMTAwIjsKCSJzaWduaW5nLXN0YXR1cyIgPSAiMCI7Cn0=",
    "State": 0,
    "ConsumptionState": 0,
    "IsAcknowledged": false,
    "Payload": null
}

I deserialize the above object & decode the base64 purchaseToken, but the decoded string is javascript string rather then json (look at the = & ;).

{
    "signature" = "some long base64 string";
    "purchase-info" = "ewoJIm9yaWdpbmFsLXB1cmNoYXNlLWRhdGUtcHN0IiA9ICIyMDAwLTAxLTAxIDAxOjAxOjAxIEFtZXJpY2EvTG9zX0FuZ2VsZXMiOwoJInVuaXF1ZS1pZGVudGlmaWVyIiA9ICJzb21lVUlEIjsKCSJvcmlnaW5hbC10cmFuc2FjdGlvbi1pZCIgPSAiU29tZVRJRCI7CgkiYnZycyIgPSAiMy42IjsKCSJ0cmFuc2FjdGlvbi1pZCIgPSAiU29tZVRJRCI7CgkicXVhbnRpdHkiID0gIjEiOwoJImluLWFwcC1vd25lcnNoaXAtdHlwZSIgPSAiUFVSQ0hBU0VEIjsKCSJvcmlnaW5hbC1wdXJjaGFzZS1kYXRlLW1zIiA9ICJzb21lIG51bWVyaWMgdGltZSBzdGFtcCBpbiBtcyI7CgkidW5pcXVlLXZlbmRvci1pZGVudGlmaWVyIiA9ICJzb21lIFVJRCI7CgkicHJvZHVjdC1pZCIgPSAiMSI7CgkiaXRlbS1pZCIgPSAic29tZSBVbmlxdWUgSXRlbSBJRCI7CgkidmVyc2lvbi1leHRlcm5hbC1pZGVudGlmaWVyIiA9ICIwIjsKCSJpcy1pbi1pbnRyby1vZmZlci1wZXJpb2QiID0gImZhbHNlIjsKCSJwdXJjaGFzZS1kYXRlLW1zIiA9ICJzb21lIG51bWVyaWMgdGltZSBzdGFtcCBpbiBtcyI7CgkicHVyY2hhc2UtZGF0ZSIgPSAiMjAwMC0wMS0wMSAwMTowMTowMSBFdGMvR01UIjsKCSJpcy10cmlhbC1wZXJpb2QiID0gImZhbHNlIjsKCSJvcmlnaW5hbC1wdXJjaGFzZS1kYXRlIiA9ICIyMDAwLTAxLTAxIDAxOjAxOjAxIEV0Yy9HTVQiOwoJImJpZCIgPSAiaXBhIGFwcCBidW5kbGUgbmFtZSI7CgkicHVyY2hhc2UtZGF0ZS1wc3QiID0gIjIwMDAtMDEtMDEgMDE6MDE6MDEgQW1lcmljYS9Mb3NfQW5nZWxlcyI7Cn0=";
    "environment" = "Sandbox";
    "pod" = "100";
    "signing-status" = "0";
}

And the purchase info:

{
    "original-purchase-date-pst" = "2000-01-01 01:01:01 America/Los_Angeles";
    "unique-identifier" = "someUID";
    "original-transaction-id" = "SomeTID";
    "bvrs" = "3.6";
    "transaction-id" = "SomeTID";
    "quantity" = "1";
    "in-app-ownership-type" = "PURCHASED";
    "original-purchase-date-ms" = "some numeric time stamp in ms";
    "unique-vendor-identifier" = "some UID";
    "product-id" = "1";
    "item-id" = "some Unique Item ID";
    "version-external-identifier" = "0";
    "is-in-intro-offer-period" = "false";
    "purchase-date-ms" = "some numeric time stamp in ms";
    "purchase-date" = "2000-01-01 01:01:01 Etc/GMT";
    "is-trial-period" = "false";
    "original-purchase-date" = "2000-01-01 01:01:01 Etc/GMT";
    "bid" = "ipa app bundle name";
    "purchase-date-pst" = "2000-01-01 01:01:01 America/Los_Angeles";
}

I'm facing this issue with deserializing of the javascript string into a C# object. Any proper way to handle this deserialization? Newtonsoft.Json is not able to handle it & I have looked its docs again & again to find any suitable methods but no success.

Is there any way other then to replace characters & make its json like?

Any help would be highly appreciated.

5
  • 2
    That isn't valid in JSON or Javascript. If you are able to tell the other end to encode that stuff properly, then do that, otherwise you're going to have to decode it all manually. Commented Sep 7, 2021 at 10:17
  • 1
    I know & that would have been great, but that is what apple is returning after performing in app purchase & I can't tell the other end to properly encode as the api would have been getting used by others. Commented Sep 7, 2021 at 10:21
  • 1
    It's not valid JS, it will give you a Uncaught SyntaxError: Invalid left-hand side in assignment message Commented Sep 7, 2021 at 10:30
  • 1
    yup true, just now checked it in console, I guess manually parsing it is the only wo to go forwards. Thanks Commented Sep 7, 2021 at 10:33
  • 1
    I guess you could string.Replace(';', ',') & string.Replace('=', ':') but this would of course be horribly hacky and I'd be afraid to deploy something like that to production, unless you can be 100% sure that those characters will never appear inside the keys or values. The alternative of developing your own parser is equally hacky, though. So I'm really not sure about this one. Commented Sep 7, 2021 at 11:41

4 Answers 4

3

As others already mentioned, it's not JSON. But based on the example you provided you should be able to transform it to a readable JSON. It's not the most pretty solution, but it seems to work. It have some draw-backs:

  • It will only work when " = " is the separator.

  • It will only work when each field is separated by ; followed by line-break (windows-style).

      private string MakeReadableJson(string base64Input)
      {
          var data = System.Convert.FromBase64String(base64Input);
          string readableString = Encoding.UTF8.GetString(data);
          var json = readableString.Replace("\" = \"", "\":\"").Replace(";\n", ",");
          return json;
      }
    

I use System.Text.JsonSerializer. Use it like so:

            string json = @"{
                   ""Id"": ""1000000872920320"",
                   ""TransactionDateUtc"": ""2021-09-06T14:42:17Z"",
                   ""ProductId"": ""1"",
                   ""AutoRenewing"": false,
                   ""PurchaseToken"": ""ewoJInNpZ25hdHVyZSIgPSAic29tZSBsb25nIGJhc2U2NCBzdHJpbmciOwoJInB1cmNoYXNlLWluZm8iID0gImV3b0pJbTl5YVdkcGJtRnNMWEIxY21Ob1lYTmxMV1JoZEdVdGNITjBJaUE5SUNJeU1EQXdMVEF4TFRBeElEQXhPakF4T2pBeElFRnRaWEpwWTJFdlRHOXpYMEZ1WjJWc1pYTWlPd29KSW5WdWFYRjFaUzFwWkdWdWRHbG1hV1Z5SWlBOUlDSnpiMjFsVlVsRUlqc0tDU0p2Y21sbmFXNWhiQzEwY21GdWMyRmpkR2x2YmkxcFpDSWdQU0FpVTI5dFpWUkpSQ0k3Q2draVluWnljeUlnUFNBaU15NDJJanNLQ1NKMGNtRnVjMkZqZEdsdmJpMXBaQ0lnUFNBaVUyOXRaVlJKUkNJN0Nna2ljWFZoYm5ScGRIa2lJRDBnSWpFaU93b0pJbWx1TFdGd2NDMXZkMjVsY25Ob2FYQXRkSGx3WlNJZ1BTQWlVRlZTUTBoQlUwVkVJanNLQ1NKdmNtbG5hVzVoYkMxd2RYSmphR0Z6WlMxa1lYUmxMVzF6SWlBOUlDSnpiMjFsSUc1MWJXVnlhV01nZEdsdFpTQnpkR0Z0Y0NCcGJpQnRjeUk3Q2draWRXNXBjWFZsTFhabGJtUnZjaTFwWkdWdWRHbG1hV1Z5SWlBOUlDSnpiMjFsSUZWSlJDSTdDZ2tpY0hKdlpIVmpkQzFwWkNJZ1BTQWlNU0k3Q2draWFYUmxiUzFwWkNJZ1BTQWljMjl0WlNCVmJtbHhkV1VnU1hSbGJTQkpSQ0k3Q2draWRtVnljMmx2YmkxbGVIUmxjbTVoYkMxcFpHVnVkR2xtYVdWeUlpQTlJQ0l3SWpzS0NTSnBjeTFwYmkxcGJuUnlieTF2Wm1abGNpMXdaWEpwYjJRaUlEMGdJbVpoYkhObElqc0tDU0p3ZFhKamFHRnpaUzFrWVhSbExXMXpJaUE5SUNKemIyMWxJRzUxYldWeWFXTWdkR2x0WlNCemRHRnRjQ0JwYmlCdGN5STdDZ2tpY0hWeVkyaGhjMlV0WkdGMFpTSWdQU0FpTWpBd01DMHdNUzB3TVNBd01Ub3dNVG93TVNCRmRHTXZSMDFVSWpzS0NTSnBjeTEwY21saGJDMXdaWEpwYjJRaUlEMGdJbVpoYkhObElqc0tDU0p2Y21sbmFXNWhiQzF3ZFhKamFHRnpaUzFrWVhSbElpQTlJQ0l5TURBd0xUQXhMVEF4SURBeE9qQXhPakF4SUVWMFl5OUhUVlFpT3dvSkltSnBaQ0lnUFNBaWFYQmhJR0Z3Y0NCaWRXNWtiR1VnYm1GdFpTSTdDZ2tpY0hWeVkyaGhjMlV0WkdGMFpTMXdjM1FpSUQwZ0lqSXdNREF0TURFdE1ERWdNREU2TURFNk1ERWdRVzFsY21sallTOU1iM05mUVc1blpXeGxjeUk3Q24wPSI7CgkiZW52aXJvbm1lbnQiID0gIlNhbmRib3giOwoJInBvZCIgPSAiMTAwIjsKCSJzaWduaW5nLXN0YXR1cyIgPSAiMCI7Cn0="",
                   ""State"": 0,
                   ""ConsumptionState"": 0,
                   ""IsAcknowledged"": false,
                   ""Payload"": null
               }";

            var info = JsonSerializer.Deserialize<ResultFromApple>(json);

            var purchaseTokenJson = MakeReadableJson(info.PurchaseToken);
            PurchaseToken purchaseToken = JsonSerializer.Deserialize<PurchaseToken>(purchaseTokenJson, new JsonSerializerOptions()
            {
                AllowTrailingCommas = true
            });

            var purchaseInfoJson = MakeReadableJson(purchaseToken.PurchaseInfo);
            PurchaseInfo purchaseInfo = JsonSerializer.Deserialize<PurchaseInfo>(purchaseInfoJson, new JsonSerializerOptions()
            {
                AllowTrailingCommas = true
            });

And your models:

public class PurchaseToken
{
    public string signature { get; set; }

    [JsonPropertyName("purchase-info")]
    public string PurchaseInfo { get; set; }
    public string environment { get; set; }
    public string pod { get; set; }

    [JsonPropertyName("signing-status")]
    public string SigningStatus { get; set; }
}

public class ResultFromApple
{
    public string Id { get; set; }
    public DateTime TransactionDateUtc { get; set; }
    public string ProductId { get; set; }
    public bool AutoRenewing { get; set; }
    public string PurchaseToken { get; set; }
    public int State { get; set; }
    public int ConsumptionState { get; set; }
    public bool IsAcknowledged { get; set; }
    public object Payload { get; set; }
}

public class PurchaseInfo
{
    [JsonPropertyName("original-purchase-date-pst")]
    public string OriginalPurchaseDatePst { get; set; }

    [JsonPropertyName("unique-identifier")]
    public string UniqueIdentifier { get; set; }

    [JsonPropertyName("original-transaction-id")]
    public string OriginalTransactionId { get; set; }
    public string bvrs { get; set; }

    [JsonPropertyName("transaction-id")]
    public string TransactionId { get; set; }
    public string quantity { get; set; }

    [JsonPropertyName("in-app-ownership-type")]
    public string InAppOwnershipType { get; set; }

    [JsonPropertyName("original-purchase-date-ms")]
    public string OriginalPurchaseDateMs { get; set; }

    [JsonPropertyName("unique-vendor-identifier")]
    public string UniqueVendorIdentifier { get; set; }

    [JsonPropertyName("product-id")]
    public string ProductId { get; set; }

    [JsonPropertyName("item-id")]
    public string ItemId { get; set; }

    [JsonPropertyName("version-external-identifier")]
    public string VersionExternalIdentifier { get; set; }

    [JsonPropertyName("is-in-intro-offer-period")]
    public string IsInIntroOfferPeriod { get; set; }

    [JsonPropertyName("purchase-date-ms")]
    public string PurchaseDateMs { get; set; }

    [JsonPropertyName("purchase-date")]
    public string PurchaseDate { get; set; }

    [JsonPropertyName("is-trial-period")]
    public string IsTrialPeriod { get; set; }

    [JsonPropertyName("original-purchase-date")]
    public string OriginalPurchaseDate { get; set; }
    public string bid { get; set; }

    [JsonPropertyName("purchase-date-pst")]
    public string PurchaseDatePst { get; set; }
}
Sign up to request clarification or add additional context in comments.

9 Comments

This will break when any of the values contain a semicolon or the space-equals-space sequence. It's pretty fragile.
@DavidG Agreed. That's why I explicitly stated that it's not pretty and it will work on THIS example.
Ugly code should still work robustly, this does not.
@DavidG, You're obviously right. But we're trying to work with the material at hand. I made some minor improvements which make it less fragile.
Thanks, but its error prone, the above would replace = in the base64 text also & there would be a trailing , at the last line which is not valid for JSON
|
1

I would use Pidgin to parse something like this.

Here's some code that parses your data into a Dictionary<string, string> and prints out the results:

using System;
using System.Collections.Generic;
using System.Linq;
using Pidgin;
using static Pidgin.Parser;

namespace NotQuiteJsonParsing
{
    class Program
    {
        const string PurchaseInfo = @"{
            ""original-purchase-date-pst"" = ""2000-01-01 01:01:01 America/Los_Angeles"";
            ""unique-identifier"" = ""someUID"";
            ""original-transaction-id"" = ""SomeTID"";
            ""bvrs"" = ""3.6"";
            ""transaction-id"" = ""SomeTID"";
            ""quantity"" = ""1"";
            ""in-app-ownership-type"" = ""PURCHASED"";
            ""original-purchase-date-ms"" = ""some numeric time stamp in ms"";
            ""unique-vendor-identifier"" = ""some UID"";
            ""product-id"" = ""1"";
            ""item-id"" = ""some Unique Item ID"";
            ""version-external-identifier"" = ""0"";
            ""is-in-intro-offer-period"" = ""false"";
            ""purchase-date-ms"" = ""some numeric time stamp in ms"";
            ""purchase-date"" = ""2000-01-01 01:01:01 Etc/GMT"";
            ""is-trial-period"" = ""false"";
            ""original-purchase-date"" = ""2000-01-01 01:01:01 Etc/GMT"";
            ""bid"" = ""ipa app bundle name"";
            ""purchase-date-pst"" = ""2000-01-01 01:01:01 America/Los_Angeles"";
        }";

        private static string IEnumerableCharToString(IEnumerable<char> value)
        {
            // Feel free to swap this with an alternative answer to https://stackoverflow.com/questions/8108313
            return new string(value.ToArray());
        }

        // Parsers can be slow to build, so minimise the
        // number of times this setup method is called.  See
        // https://github.com/benjamin-hodgson/Pidgin#speed-tips
        private static Parser<char, Dictionary<string, string>> BuildBlockParser()
        {
            var stringParser = Char('"').Then(AnyCharExcept('"').AtLeastOnceUntil(Char('"')));

            var lineParser = Map(
                (key, value) => new KeyValuePair<string, string>(IEnumerableCharToString(key), IEnumerableCharToString(value)),
                stringParser.Before(SkipWhitespaces).Before(Char('=')).Before(SkipWhitespaces),
                stringParser.Before(SkipWhitespaces).Before(Char(';')).Before(SkipWhitespaces));

            var linesParser = lineParser.AtLeastOnce().Map(pairs => new Dictionary<string, string>(pairs));

            var blockParser = SkipWhitespaces.Then(Char('{')).Then(SkipWhitespaces).Then(linesParser).Before(Char('}'));
            return blockParser;
        }

        static void Main()
        {
            var blockParser = BuildBlockParser();
            var result = blockParser.ParseOrThrow(PurchaseInfo);
            foreach (var (key, value) in result)
            {
                Console.WriteLine($"{key} = {value}");
            }
        }
    }
}

This parser has the following limitations:

  • Values in key-value pairs are always strings, not numbers, booleans or anything else.
  • There is no support for escaped " characters in keys or values. I don't know how they would be escaped.
  • There is no support for escape sequences such as \r, \n, \t or \u0123.

Comments

1

It's a bit embarrassing. I saw the problem as the opposite before. Try this, I think this can meet the needs:

Parse JavaScript string

static void Main(string[] args)
{
    var jsStr = @"{
                    ""signature"" = ""some long base64 string"";
                    ""purchase-info"" = ""ewoJIm9yaWdpbmFsLXB1cmNoYXNlLWRhdGUtcHN0IiA9ICIyMDAwLTAxLTAxIDAxOjAxOjAxIEFtZXJpY2EvTG9zX0FuZ2VsZXMiOwoJInVuaXF1ZS1pZGVudGlmaWVyIiA9ICJzb21lVUlEIjsKCSJvcmlnaW5hbC10cmFuc2FjdGlvbi1pZCIgPSAiU29tZVRJRCI7CgkiYnZycyIgPSAiMy42IjsKCSJ0cmFuc2FjdGlvbi1pZCIgPSAiU29tZVRJRCI7CgkicXVhbnRpdHkiID0gIjEiOwoJImluLWFwcC1vd25lcnNoaXAtdHlwZSIgPSAiUFVSQ0hBU0VEIjsKCSJvcmlnaW5hbC1wdXJjaGFzZS1kYXRlLW1zIiA9ICJzb21lIG51bWVyaWMgdGltZSBzdGFtcCBpbiBtcyI7CgkidW5pcXVlLXZlbmRvci1pZGVudGlmaWVyIiA9ICJzb21lIFVJRCI7CgkicHJvZHVjdC1pZCIgPSAiMSI7CgkiaXRlbS1pZCIgPSAic29tZSBVbmlxdWUgSXRlbSBJRCI7CgkidmVyc2lvbi1leHRlcm5hbC1pZGVudGlmaWVyIiA9ICIwIjsKCSJpcy1pbi1pbnRyby1vZmZlci1wZXJpb2QiID0gImZhbHNlIjsKCSJwdXJjaGFzZS1kYXRlLW1zIiA9ICJzb21lIG51bWVyaWMgdGltZSBzdGFtcCBpbiBtcyI7CgkicHVyY2hhc2UtZGF0ZSIgPSAiMjAwMC0wMS0wMSAwMTowMTowMSBFdGMvR01UIjsKCSJpcy10cmlhbC1wZXJpb2QiID0gImZhbHNlIjsKCSJvcmlnaW5hbC1wdXJjaGFzZS1kYXRlIiA9ICIyMDAwLTAxLTAxIDAxOjAxOjAxIEV0Yy9HTVQiOwoJImJpZCIgPSAiaXBhIGFwcCBidW5kbGUgbmFtZSI7CgkicHVyY2hhc2UtZGF0ZS1wc3QiID0gIjIwMDAtMDEtMDEgMDE6MDE6MDEgQW1lcmljYS9Mb3NfQW5nZWxlcyI7Cn0="";
                    ""environment"" = ""Sandbox"";
                    ""pod"" = ""100"";
                    ""signing-status"" = ""0"";
                }";

    var model = GetModelFromJsStr<PurchaseToken>(jsStr);
}

public class PurchaseToken
{
    [JsonPropertyName("signature")]
    public string Signature { get; set; }
    [JsonPropertyName("purchase-info")]
    public string PurchaseInfo { get; set; }
    [JsonPropertyName("environment")]
    public string Environment { get; set; }
    [JsonPropertyName("pod")]
    public int Pod { get; set; }
    [JsonPropertyName("signing-status")]
    public int SigningStatus { get; set; }
}

public static T GetModelFromJsStr<T>(string jsStr) where T : new()
{
    var model = new T();
    var rows = jsStr.Split("\n").Select(item => item.Trim()).ToList();
    foreach (var prop in typeof(T).GetProperties())
    {
        var jsonProperty = prop.GetCustomAttribute<JsonPropertyNameAttribute>();

        if (jsonProperty != null)
        {
            var matchRow = rows.FirstOrDefault(row => row.StartsWith(@$"""{jsonProperty.Name}"" ="));
            if (matchRow != null)
            {
                var pattern = @$"^""{jsonProperty.Name}"" = ""(.*)"";$";
                var match = Regex.Match(matchRow, pattern);
                if (match?.Groups?.Count > 1)
                {
                    // convertible types can be extended
                    if (prop.PropertyType == typeof(int))
                    {
                        int.TryParse(match.Groups[1].Value, out var propValue);
                        prop.SetValue(model, propValue);
                    }
                    else
                    {
                        prop.SetValue(model, match.Groups[1].Value);
                    }
                }
            }
        }
    };

    return model;
}

2 Comments

But I need to do exactly the other way around, JsString To Json
@DavidG modified the answer
0

Was able to handle this by with following code using Newtonsoft.Json.JsonConverter:

Create models for the data

public class InAppPurchaseToken
{
    public string Signature { get; set; }
    [JsonProperty("purchase-info")]
    public string PurchaseInfo { get; set; }
    public string Environment { get; set; }
    public string Pod { get; set; }
    public string SigningStatus { get; set; }
}


public class InAppPurchaseInfo
{
    [JsonProperty("original-purchase-date-pst")]
    public string originalpurchasedatepst { get; set; }
    [JsonProperty("unique-identifier")]
    public string uniqueidentifier { get; set; }
    [JsonProperty("original-transaction-id")]
    public string originaltransactionid { get; set; }
    public string bvrs { get; set; }
    [JsonProperty("transaction-id")]
    public string transactionid { get; set; }
    public string quantity { get; set; }
    [JsonProperty("in-app-ownership-type")]
    public string inappownershiptype { get; set; }
    [JsonProperty("original-purchase-date-ms")]
    public string originalpurchasedatems { get; set; }
    [JsonProperty("unique-vendor-identifier")]
    public string uniquevendoridentifier { get; set; }
    [JsonProperty("product-id")]
    public string productid { get; set; }
    [JsonProperty("item-id")]
    public string itemid { get; set; }
    [JsonProperty("version-external-identifier")]
    public string versionexternalidentifier { get; set; }
    [JsonProperty("is-in-intro-offer-period")]
    public string isinintroofferperiod { get; set; }
    [JsonProperty("purchase-date-ms")]
    public string purchasedatems { get; set; }
    [JsonProperty("purchase-date")]
    public string purchasedate { get; set; }
    [JsonProperty("is-trial-period")]
    public string istrialperiod { get; set; }
    [JsonProperty("original-purchase-date")]
    public string originalpurchasedate { get; set; }
    public string bid { get; set; }
    [JsonProperty("purchase-date-pst")]
    public string purchasedatepst { get; set; }
}

And the handle the parsing using following code (assuming you have deserialized the initial json as inAppPayData C# object):

public string GetJsonFromBase64JsStr(string base64JsStr)
{
    if (string.IsNullOrWhiteSpace(base64JsStr))
        return "";

    var decodedStr2Parse = Encoding.UTF8.GetString(Convert.FromBase64String(base64JsStr));

    //var ConvertedJsonStrComplete = decodedStr2Parse.Replace("\" = \"", "\":\"").Replace(";\n", ",").Replace(",}", "}");  //more error prone
    var ConvertedJsonStrPartial = decodedStr2Parse.Replace("\" = \"", "\":\"").Replace(";\n", ",");
    var ConvertedJsonStrComplete = ConvertedJsonStrPartial.Remove(ConvertedJsonStrPartial.LastIndexOf(",}"), 1);

     return ConvertedJsonStrComplete;
}

//call the above function with base64JsString
var purchaseJsonStr = GetJsonFromBase64JsStr(inAppPayData.PurchaseToken);

var purchaseTokenObj = JsonConvert.DeserializeObject<InAppPurchaseToken>(purchaseJsonStr);


var purchaseInfoJsonStr = GetJsonFromBase64JsStr(purchaseTokenObj.PurchaseInfo);

var purchaseInfoObj = JsonConvert.DeserializeObject<InAppPurchaseInfo>(purchaseInfoJsonStr);


Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.