1

I'm storing customer position data using the following class:

  public class CustomerData
{
    public string CustomerName { get; set; }
    public int CustomerNumber { get; set; }
    public string CustomerAddress { get; set; }
    public string CustomerCity { get; set; }
    public string CustomerZip { get; set; }
    public string CustomerState { get; set; }
    public Geopoint CustomerGeopoint { get; set; }

}

inside a JSON file...and retrieving the data using a service like so:

public static async Task<ObservableCollection<CustomerData>> GetCustomerData()
    {
        var folder = ApplicationData.Current.LocalFolder;
        var dataFile = await folder.TryGetItemAsync("CustomerData.json") as IStorageFile;
        var stringResult = await FileIO.ReadTextAsync(dataFile);

        ObservableCollection<CustomerData> CustomersRetrievedData = JsonConvert.DeserializeObject<ObservableCollection<CustomerData>>(stringResult, new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.All
        });
        Customers = CustomersRetrievedData;
        return await Task.FromResult(CustomersRetrievedData);
    }

as well as saving the data like this:

       public static async void SaveCustomerData()
    {
        var folder = ApplicationData.Current.LocalFolder;
        StorageFile newFile = await folder.CreateFileAsync("CustomerData.json", CreationCollisionOption.ReplaceExisting);
        var stringData = JsonConvert.SerializeObject(Customers);
        await FileIO.WriteTextAsync(newFile, stringData);

    }

My problem is, after all the geopoint data is in there, when I try to read the data by deserializing it in the GetCustomerData() method, I get the following error:

Unable to find a constructor to use for type Windows.Devices.Geolocation.Geopoint. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute

I don't understand how to fix this, and I can't find anything on the newtonsoft documentation, anyone know how this is done?

Sam Axe
  • 33,313
  • 9
  • 55
  • 89
  • 2
    Looks like `Geopoint` isn't suitable for deserializing into. Create a new class instead which just has properties on it, and use that in `CustomerData` instead of using `Geopoint` – canton7 Oct 10 '19 at 16:46
  • Can you switch to BasicGeoposition? That struct seems easier to serialize/deserialize. As for Geoposition it could be deserialized by using custom json converter since there is no constructor that accepts serialized fields as parameters. – Optional Option Oct 10 '19 at 17:08
  • As an alternative to my answer below, you could write a custom type deserializer and plug that into Json.Net. – Sam Axe Oct 10 '19 at 17:13
  • You could create a `JsonConverter` for `GeoPoint`. See [JSON.net: how to deserialize without using the default constructor?](https://stackoverflow.com/q/23017716/10263) – Brian Rogers Oct 10 '19 at 17:29

1 Answers1

0

Looking at the documentation for Geopoint we can see that it has 3 .ctors, none of which are parameterless. JSON.NET requires a parameterless .ctor for deserialization, as you can see from the error message you get.

So one thing you can do is change your class to include a property with a type (that you make) that mirrors the Geopoint structure (includes all its properties), but also includes a parameterless .ctor. You could even implement IGeoshape so that it could be used anywhere an IGeoshape was required.

Something along the lines of:

public class GeopointProxy : IGeoshape {
    public GeopointProxy() { }

    private AltitudeReferenceSystem _altitudeReferenceSystem;
    // This is part of the IGeoshape interface, you can't change it's signature, and it's readonly.  Fun.
    [JsonIgnore]
    public AltitudeReferenceSystem AltitudeReferenceSystem { get { return _altitudeReferenceSystem; } }  

    public AltitudeReferenceSystem SettableAltitudeReferenceSystem {
        get {
            return AltitudeReferenceSystem;
        }
        set {
            _altitudeReferenceSystem = value;
        }
    }

    // rinse and repeat as appropriate for the other interface members and class properties

    // Then include a conversion function, or get fancy and add type conversion operators:
    public Geopoint ToGeopoint() {
        return new Geopoint(Position, AltitudeReferenceSystem, SpatialReferenceId);
    }
}
Sam Axe
  • 33,313
  • 9
  • 55
  • 89
  • okay I think I've implemented the class correctly - now what I do is store the GeopointProxy class inside of my json and then use the conversion function to turn it back into a geopoint when I need it, correct? – William Melton Oct 10 '19 at 18:06
  • I am using the Geopoint proxy and it seems to seralize great, in fact, exactly the same way that the default Geopoint class does, but when de-serializing the Position property of the Geopoint proxy is always reading as 0 lat. and 0 long. Any idea why that would happen? – William Melton Oct 10 '19 at 21:19
  • How did you define the `Position` property? – Sam Axe Oct 10 '19 at 21:30
  • And does the JSON file contain data for it? – Sam Axe Oct 10 '19 at 21:30
  • What I actually wound up doing was just scratching the whole thing, and to store only the latitude and longitude in the json and construct the map markers at load time instead. This approach is simple and works great – William Melton Oct 16 '19 at 16:24