2

I'm working on a Xamarin Forms app for Android & iOS

I'm trying to figure out how to pass none english letters to Json file.

My language is Swedish and whenever I use characters like (Å, Ä, Ö) the app crashes.

So how do I fix this please ?

DrawerViewModel.cs

class DrawerViewModel : BaseViewModel {
     ...

     public static DrawerViewModel BindingContext => 
        drawerViewModel = PopulateData<DrawerViewModel>("drawer.json");

     ...

     private static T PopulateData<T>(string fileName)
    {
        var file = "CykelStaden.Data." + fileName;

        var assembly = typeof(App).GetTypeInfo().Assembly;

        T data;

        using (var stream = assembly.GetManifestResourceStream(file))
        {
            var serializer = new DataContractJsonSerializer(typeof(T));
            data = (T)serializer.ReadObject(stream);
        }

        return data;
    }
     
}

drawer.json

{
    "itemList": [
     {
         "itemIcon": "\ue729",
         "itemName": "Länd"
      },
      {
          "itemIcon": "\ue72c",
          "itemName": "Höjd"
      },
      {
          "itemIcon": "\ue733",
          "itemName": "Mått"
      },
      {
          "itemIcon": "\ue72b",
          "itemName": "Inställningar"
      }
  ]
}
dbc
  • 104,963
  • 20
  • 228
  • 340
Jaser
  • 245
  • 1
  • 7
  • 21
  • 1
    How does it crash? Can you produce a [mcve]? If everything is unicode you should be fine. Check your encodings. – J... Nov 03 '21 at 16:17
  • 1
    What encoding do you use for the input file? – choroba Nov 03 '21 at 16:17
  • Which specific line causes the crash? What is the exception? What encoding do you use? Have you tried using Newtonsoft instead of the Microsoft serializer? – Jason Nov 03 '21 at 16:19
  • Are you talking about the file name or the file content? If it is the latter make sure that the file is saved with UTF-8 encoding. – Robert Nov 03 '21 at 16:19
  • I have added the drawer.json file, and I actually do not know how to check the encoding of my app. – Jaser Nov 03 '21 at 16:26
  • Don't use that old 'DataContractJsonSerializer' Microsoft recommends using `System.Text.Json` namespace. – Poul Bak Nov 03 '21 at 16:39
  • What do you mean don't use --> "Don't use that old 'DataContractJsonSerializer' Microsoft recommends using System.Text.Json namespace." – Jaser Nov 03 '21 at 19:53

3 Answers3

1

The json parser crashes, because the json data is not encoded correctly. The special caracters (ä, ö, å) have to be encoded with the same \u syntax.

Using this should work:

{
  "itemList": [
    {
      "itemIcon": "\uE729",
      "itemName": "L\u00E4nd"
    },
    {
      "itemIcon": "\uE72C",
      "itemName": "H\u00F6jd"
    },
    {
      "itemIcon": "\uE733",
      "itemName": "M\u00E5tt"
    },
    {
      "itemIcon": "\uE72B",
      "itemName": "Inst\u00E4llningar"
    }
  ]
}
Dominik Viererbe
  • 387
  • 2
  • 12
  • How did you know how to change these special characters like this? – Jaser Nov 03 '21 at 16:42
  • I am from Germany, so i know the trouble. I wrote a simple console application for myself that transforms the data, but you can look up the values in any unicode table. Its the hex value of the character padded to length 4 with leading zeros. – Dominik Viererbe Nov 03 '21 at 16:49
  • https://datatracker.ietf.org/doc/html/rfc8259#section-7 – Dominik Viererbe Nov 03 '21 at 16:55
0

Out of curiosity I found another Solution: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-character-encoding using the JsonSerializer:

public class DrawerItem
{
    [JsonPropertyName("itemIcon")]
    public string Icon { get; set; }

    [JsonPropertyName("itemName")]
    public string Name { get; set; }
}

public class DrawerItemList
{
    private static readonly JsonSerializerOptions _serializerOptions = new JsonSerializerOptions
    {
        // This Encoder allows to parse Unicode Symbols without \uXXXX escaping
        Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
    };

    [JsonPropertyName("itemList")]
    public IEnumerable<DrawerItem> DrawerItems { get; set; }

    public static DrawerItemList LoadFromEmbeddedJsonFile(CancellationToken cancellationToken = default)
    {
        return LoadFromEmbeddedJsonFileAsync(cancellationToken).Result;
    }

    public static async Task<DrawerItemList> LoadFromEmbeddedJsonFileAsync(CancellationToken cancellationToken = default)
    {
        const string ManifestResourceName = "CykelStaden.Data.drawer.json";

        var assembly = Assembly.GetExecutingAssembly();

        using (var stream = assembly.GetManifestResourceStream(ManifestResourceName))
        {
            return await JsonSerializer.DeserializeAsync<DrawerItemList>(stream, _serializerOptions, cancellationToken); 
        }
    }
}

Make it work with Xamarin/netstandard2.0/netstandard2.1

IMPORTANT: To make this work in a Xamarin Project to have to reference the System.Text.Json Nuget Package. (https://www.nuget.org/packages/System.Text.Json).

You can do this with the .NET CLI (Command Line Interface):

dotnet add package System.Text.Json

The Reason for this is that the System.Text.Json API's were first shipped with .NET Core 3 (https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/) and are therefore not included in the netstandard2.0 or netstandard2.1 framework, which existed before .NET Core 3.

How can I see that I am targeting netstandard2.0 or netstandard2.1?

When you look into the .csproj File you should see a line like this:

<TargetFramework>netstandard2.0</TargetFramework>

or

<TargetFramework>netstandard2.1</TargetFramework>

If <TargetFramework> contains another value you most likely don't have to add the System.Text.Json Nuget Package.

Dominik Viererbe
  • 387
  • 2
  • 12
0

Use JsonConvert instead,I test it on my side and it works fine. The code is from the sample I create under this question:Write a Text File (or PDF File) from Json in Xamarin.forms

code like:

 private void saveload_clicked(object sender, EventArgs e)
{
    string myfile=Path.Combine(FileSystem.AppDataDirectory,"myjson.txt");
    var obj = JsonConvert.DeserializeObject(File.ReadAllText(myfile));
}
Adrain
  • 1,946
  • 1
  • 3
  • 7