Restsharp and Newton - SearchResults

Hi all,

Can anyone help me figure this one out?


foreach (var row in ttCustomer.ToList())
{
    decimal? longi = row.Longitude_c;
    decimal? lati = row.Latitude_c;

    if (longi == null && lati == null)
    {
        Console.WriteLine("Both fields are null");
        Ice.Diagnostics.Log.WriteEntry($"Updating the fields now..(Lat and Long)");

        //Use open streetmaps to get our lat/long
        var client = new RestClient("https://nominatim.openstreetmap.org/");

        // Set the address parameter for the request
        var request = new RestRequest("search?format=json&limit=1&q={address}", Method.GET);

        //Lets build the address 
        string[] location = { row.Address1, row.Address2, row.Address3, row.City, row.State, row.Country, row.Zip };
        string addr = string.Join(", ", location);

        Ice.Diagnostics.Log.WriteEntry($"Address: {addr}");

        //Append the address to the url of the request..
        request.AddUrlSegment("address", addr);

        // Execute the request and get the response
        IRestResponse response = client.Execute(request);

        Ice.Diagnostics.Log.WriteEntry($"Status code: {response.StatusCode}");
        Ice.Diagnostics.Log.WriteEntry($"Error message: {response.ErrorMessage}");

        // Deserialize the response into a list of search results
        var searchResults = JsonConvert.DeserializeObject<List<SearchResult>>(response.Content);

        Ice.Diagnostics.Log.WriteEntry($"Number of search results: {searchResults.Count}");

        // Get the first search result
        var firstResult = searchResults.FirstOrDefault();

        if (firstResult == null)
        {
            this.PublishInfoMessage("First result is null",Ice.Common.BusinessObjectMessageType.Information, Ice.Bpm.InfoMessageDisplayMode.Individual,"","");
        }
        else
        {
            // Update the latitude and longitude fields with the values from the search result
            lati = firstResult.lat;
            longi = firstResult.lon;
        }
    }
}

Need another pair of eyes, I can’t see my problem :frowning:

I’m on a phone so can’t help right now, but could you give some more context on what’s not working?

No worries. It’s this lovely error.

The type or namespace name 'SearchResult' could not be found (are you missing a using directive or an assembly reference?)

``

Try List<dynamic> or List<JObject>

Damn, before you edited it…
YARN | No. It is a trick question. | My Cousin Vinny (1992) | Video clips by quotes | 2a119335 | ç´—

Damn phone

List<dynamic> may be the winner…

1 Like

For those interested:

url: https://nominatim.openstreetmap.org/search?format=json&limit=1&q=Lake%20Buena%20Vista%20Florida%2032830

returns

[
    {
        "place_id": 298706900,
        "licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
        "osm_type": "relation",
        "osm_id": 1102870,
        "boundingbox": [
            "28.3620643",
            "28.3986361",
            "-81.5430629",
            "-81.5013437"
        ],
        "lat": "28.38034955",
        "lon": "-81.5297578369267",
        "display_name": "Lake Buena Vista, Reedy Creek Improvement District, Orange County, Florida, United States",
        "class": "boundary",
        "type": "administrative",
        "importance": 0.8597372270874096,
        "icon": "https://nominatim.openstreetmap.org/ui/mapicons/poi_boundary_administrative.p.20.png"
    }
]
string retString = "";
string nl = Environment.NewLine;

string lati  = "";
string longi = "";

string json = "[{\"place_id\":298706900,\"licence\":\"Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright\",\"osm_type\":\"relation\",\"osm_id\":1102870,\"boundingbox\":[\"28.3620643\",\"28.3986361\",\"-81.5430629\",\"-81.5013437\"],\"lat\":\"28.38034955\",\"lon\":\"-81.5297578369267\",\"display_name\":\"Lake Buena Vista, Reedy Creek Improvement District, Orange County, Florida, United States\",\"class\":\"boundary\",\"type\":\"administrative\",\"importance\":0.8597372270874096,\"icon\":\"https://nominatim.openstreetmap.org/ui/mapicons/poi_boundary_administrative.p.20.png\"}]";

var searchResults = JsonConvert.DeserializeObject<List<dynamic>>(json);


var firstResult = searchResults.FirstOrDefault();

if (firstResult == null)
{
    InfoMessage.Publish("First result is null");
}
else
{
    // Update the latitude and longitude fields with the values from the search result
    lati = firstResult.lat;
    longi = firstResult.lon;
}

retString += $"{lati}    {longi}";
InfoMessage.Publish(retString);

throwaway

3 Likes

Looks like a Disney property to me.

1 Like

Well I had my address in there and I don’t need any more junk mail.

The final code uses the address from the customer table, which passes it to Google Maps API for geocoding, then returns the data back to two custom fields on the customer table adding the latitude and longitude it found. We use this for plotting on our customer portal.

If anyone wants the code. Let me know. I am happy to share it. I obviously can’t share the code between the customer portal and epicor, but i am happy to share this…

1 Like

Sharing is caring.

1 Like

Here it is…

foreach (var row in ttResults.ToList())
{
    //decimal? longi = row.Customer_Longitude_c;
    //decimal? lati = row.Customer_Latitude_c;


        // Set up the API client
        var client = new RestClient("https://maps.googleapis.com/maps/api/geocode/");

        // Set up the API request
        var request = new RestRequest("json?key={apiKey}&address={address}", Method.GET);
        request.AddUrlSegment("apiKey", "YOUR_API_KEY");

        // Build the address string
        string[] loc = { row.Customer_Address1, row.Customer_Address2, row.Customer_Address3, row.Customer_City, row.Customer_State, row.Customer_Country, row.Customer_Zip };
        string addr = string.Join(", ", loc);

        Ice.Diagnostics.Log.WriteEntry($"Address: {addr}");

        // Set the address parameter for the request
        request.AddUrlSegment("address", addr);

        // Execute the request and get the response
        IRestResponse response = client.Execute(request);
        
            // Check if the request was successful
        if (response.StatusCode != HttpStatusCode.OK)
        {
            // Log the error and skip to the next iteration
            Ice.Diagnostics.Log.WriteEntry($"API request failed with status code [{response.StatusCode}] and error message: {response.ErrorMessage}");
            continue;
        }

    // Parse the API response
        JObject data;
        try
        {
            data = JObject.Parse(response.Content);
        }
        catch (JsonReaderException ex)
        {
            // Log the error and skip to the next iteration
            Ice.Diagnostics.Log.WriteEntry($"Error parsing JSON: {ex.Message}");
            continue;
        }

    // Check if the data object has a "results" property
        if (!data.ContainsKey("results"))
        {
            // Log the error and skip to the next iteration
            Ice.Diagnostics.Log.WriteEntry("JSON data does not contain a 'results' property");
            continue;
        }
        
    // Check if status is ZERO_RESULTS
      
        if (data["status"].ToString() == "ZERO_RESULTS")
          continue;


        Ice.Diagnostics.Log.WriteEntry($"API Status code: [{response.StatusCode}]");
        Ice.Diagnostics.Log.WriteEntry($"API Error message: [{response.ErrorMessage}]");

        // Parse the API response
        
        JObject location = (JObject)data["results"][0]["geometry"]["location"];
        decimal latitude = (decimal)location["lat"];
        decimal longitude = (decimal)location["lng"];
        
        Ice.Diagnostics.Log.WriteEntry($"Google returned this lat and long: Lat: {latitude} ~ Long: {longitude} ");
        
        Ice.Diagnostics.Log.WriteEntry($"Updating the fields now..(Lat and Long)");
        
        // Update the latitude and longitude fields with the values from the search result
        using(var txscope = IceContext.CreateDefaultTransactionScope()) {
            var custLL = Db.Customer.Where(p =>
                p.Company == Constants.CompanyID &&
                p.CustNum == row.Customer_CustNum &&
                p.CustID == row.Customer_CustID
            ).FirstOrDefault();

            if (custLL != null) {
                custLL.Latitude_c = latitude;
                custLL.Longitude_c = longitude;
                Ice.Diagnostics.Log.WriteEntry($"Task has been completed, sucessfully..");
            }
            Db.Validate();
            txscope.Complete();
        }
}

2 Likes

This is brilliant - thank you!!. Stupid question - what’s the reference assembly for RestClient.
I tried using Epicor.Ice.Lib.RestClient but this didn’t work (does not contain a constructor that takes 1 arguments), I wasn’t sure if you were accessing the restsharp reference (if so how did you get this in?)
Thanks in advance
Mark

Please can I see your references

Hi Aaron,
I added the Epicor Restclient:
image
Is this correct or have you installed RestSharp and then copied that dll to the server?

Thanks

Mark

Yes that’s correct. I believe RestClient now comes built into later versions of Epicor than I was previously on when I wrote that.

You will also need to reference Newtonsoft.Json in your Custom Assemblies and add using Newtonsoft.Json.Linq; etc.

Are you getting errors?

Thanks for the quick response - is that a yes to the RestSharp?

Yes, sorry. RestSharp

1 Like

Great, thanks Aaron. Really good post. Thanks for the help, much appreciated.