#c# #json #geocoding #restsharp #esri
Вопрос:
TLDR: У меня есть функционирующий скрипт на C#, который вызывает службу геокодирования ESRI. Он передает адреса и возвращает данные LAT/LON. Это работает нормально, пока я встраиваю адреса в URL-адрес. У меня возникли трудности с получением аналогичного кода для работы с содержимым адреса в теле вызова. Цель здесь-позвонить в службу ОТДЫХА с более чем 500 адресами одновременно.
Непосредственно ниже приведен сценарий, который отлично работает, пока я вставляю адреса как часть URL-адреса. Он обрабатывает 2-5 адресов, никаких проблем. Но (вполне предсказуемо) — при попытке увеличить до 100 адресов я получаю сообщение об ошибке «Недопустимый URI: строка Uri слишком длинная».
```C#
SqlDataAdapter geoA = new SqlDataAdapter(SQLStatement, GEOconn);
DataSet GeoDS = new DataSet();
geoA.Fill(GeoDS, "records");
var obj = JObject.FromObject(GeoDS);
obj["records"] = new JArray(obj["records"].Select(jo => new JObject(new JProperty("attributes", jo))));
string geoAJSON = obj.ToString();
geoAJSON = HttpUtility.UrlEncode(geoAJSON);
var con1 = "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/geocodeAddresses?f=pjsonamp;token=abc123amp;outFields=ResultID,Status,Score,Addr_type,ShortLabel,City,Subregion,RegionAbbr,Postal,PostalExt,Country,X,Yamp;addresses=";
var client = new RestClient(con1 geoAJSON);
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Cookie", "AGS_ROLES=abc123");
IRestResponse response = client.Execute(request);
ESRIcls esri = JsonConvert.DeserializeObject<ESRIcls>(response.Content);
```
Поэтому я пытаюсь использовать тело URL-запроса и перенести все адреса в его тело. Фрагмент сценария, который я использовал до этого момента, приведен ниже (небольшая модификация сверху).
SqlDataAdapter geoA = new SqlDataAdapter(SQLStatement, GEOconn);
DataSet GeoDS = new DataSet();
geoA.Fill(GeoDS, "records");
var obj = JObject.FromObject(GeoDS);
obj["records"] = new JArray(obj["records"].Select(jo => new JObject(new JProperty("attributes", jo))));
string geoAJSON = obj.ToString();
geoAJSON = HttpUtility.UrlEncode(geoAJSON);
var con1 = "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/geocodeAddresses?f=pjsonamp;token=abc123amp;outFields=ResultID,Status,Score,Addr_type,ShortLabel,City,Subregion,RegionAbbr,Postal,PostalExt,Country,X,Y";
var client = new RestClient(con1)
client.Timeout = -1
var request = new RestRequest(Method.POST);
request.AddJsonBody(geoAJSON);
//request.AddParameter("application/json", geoAJSON, ParameterType.RequestBody);
request.AddHeader("Cookie", "AGS_ROLES=abc123");
IRestResponse response = client.Execute(request);
ESRIcls esri = JsonConvert.DeserializeObject<ESRIcls>(response.Content);
При запуске я получаю следующую ошибку при выполнении этой строки IRestResponse:
код ошибки 400 Расширенный код -2147467259 сообщение: Не удается завершить операцию.
Для справки, вот фрагмент содержимого переменной geoAJSON. Я пробовал несколько вариантов кодировки URL-адресов и не пробовал. Неясно, в какой части этого я ошибся, и был бы признателен за любые предложения.
"{rn "records": [rn {rn "attributes": {rn
"OBJECTID": 144,rn "Address": "02483 BERRY RD",rn
"City": "CEDARTOWN",rn "Region": "GA",rn
"Postal": "30125"rn }rn },rn {rn
"attributes": {rn "OBJECTID": 145,rn "Address":
"0N321 SILVERLEAF BLVD",rn "City": "WHEATON",rn
"Region": "IL",rn "Postal": "60187-2913"rn }rn
},rn {rn "attributes": {rn "OBJECTID": 146,rn
"Address": "1",rn "City": "ROME",rn
"Region": "GA",rn "Postal": "30165"rn }rn
}rn ]rn}"
Ответ №1:
Для других, столкнувшихся с аналогичной проблемой при геокодировании esri, сработало следующее
using System;
using System.Data;
using System.Linq;
using System.Data.SqlClient;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using System.Collections.Generic;
namespace GeoCode
{
class GeoCode_Main
{
readonly static string strDDInstance = @"server"; // where is geo.datasources table?
readonly static string strddDB = "database";
readonly static string connDDstring = "Data Source=" strDDInstance ";Initial Catalog=" strddDB ";Integrated Security=True;MultipleActiveResultSets = True";
readonly static int intBatchSize = 250; // how many rows to send to batch geocoder at one time?
public static int intRowsProcessed = 0; // how many geocode addresses have we done this run?
static void Main()
{
Console.WriteLine("Launching GeoCode_Main_BI routine");
string SQLStatement = "select top " intBatchSize " MAFid as OBJECTID, FMCaddr as Address, FMCcity as City, FMCstate as Region, FMCzip as Postal from maf.addresses where GSscore is null "; // and bitwise_nulls = 30 and MAFid < 750";
string SQLTempRecCount = "select count(*) as RecCnt from maf.addresses_temp";
using SqlConnection GEOconn = new SqlConnection(connDDstring);
GEOconn.Open();
// if maf.addresses_temp has data in it -- some prior run failed -- hit the exit ramp until that gets fixed
SqlCommand selectCommand = new SqlCommand(SQLTempRecCount, GEOconn);
int MafTempRecCnt = (int)selectCommand.ExecuteScalar();
if (MafTempRecCnt > 1)
{
Console.WriteLine("Rows exist in maf.addresses_temp and they shouldn't -- bailing out - 1");
Console.ReadKey();
return; } // bailout
do
{
// now open up maf.addresses and see if any rows flagged for geocoding.
SqlDataAdapter geoDA = new SqlDataAdapter(SQLStatement, GEOconn);
DataSet GeoDS = new DataSet();
geoDA.Fill(GeoDS, "records");
int GeoDSCnt = GeoDS.Tables[0].Rows.Count;
// likewise - if no recs return -- just exit
if (GeoDSCnt == 0)
{
Console.WriteLine("Finished processing records - about to exit");
Console.ReadKey();
return;
}
intRowsProcessed = GeoDSCnt;
Console.WriteLine("{0} rows so far", intRowsProcessed);
var JSONobj = JObject.FromObject(GeoDS);
JSONobj["records"] = new JArray(JSONobj["records"].Select(jo => new JObject(new JProperty("attributes", jo))));
string geoAJSON = JSONobj.ToString();
var client = new RestClient("https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/geocodeAddresses");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("addresses", geoAJSON);
request.AddParameter("forStorage", "true");
request.AddParameter("outFields", "ResultID,Status,Score,Addr_type,ShortLabel,City,Subregion,RegionAbbr,Postal,PostalExt,Country,X,Y");
request.AddParameter("f", "pjson");
request.AddParameter("token", "blahblah");
request.AddParameter("Cookie", "blahblah");
IRestResponse response = client.Execute(request);
ESRIcls esri = JsonConvert.DeserializeObject<ESRIcls>(response.Content);
int Cntr = 0;
while (Cntr < esri.locations.Count)
{
// Console.WriteLine(esri.locations[Cntr].attributes.Addr_type);
var cmd = new SqlCommand
{
CommandText = "maf.spPopMAF",
CommandType = CommandType.StoredProcedure,
Connection = GEOconn
};
cmd.Parameters.Clear();
cmd.Parameters.Add("@MAFid", SqlDbType.Int).Value = esri.locations[Cntr].attributes.ResultID;
cmd.Parameters.Add("@GSstatus", SqlDbType.VarChar).Value = esri.locations[Cntr].attributes.Status;
cmd.Parameters.Add("@GSscore", SqlDbType.Decimal).Value = esri.locations[Cntr].attributes.Score;
cmd.Parameters.Add("@GSaddresstype", SqlDbType.VarChar).Value = esri.locations[Cntr].attributes.Addr_type;
cmd.Parameters.Add("@GSaddress", SqlDbType.VarChar).Value = esri.locations[Cntr].attributes.ShortLabel;
cmd.Parameters.Add("@GScity", SqlDbType.VarChar).Value = esri.locations[Cntr].attributes.City;
cmd.Parameters.Add("@GScounty", SqlDbType.VarChar).Value = esri.locations[Cntr].attributes.Subregion;
cmd.Parameters.Add("@GSstate", SqlDbType.VarChar).Value = esri.locations[Cntr].attributes.RegionAbbr;
cmd.Parameters.Add("@GSzip5", SqlDbType.VarChar).Value = esri.locations[Cntr].attributes.Postal;
cmd.Parameters.Add("@GSzip4", SqlDbType.VarChar).Value = esri.locations[Cntr].attributes.PostalExt;
cmd.Parameters.Add("@GSlongitude", SqlDbType.Decimal).Value = esri.locations[Cntr].attributes.X;
cmd.Parameters.Add("@GSlatitude", SqlDbType.Decimal).Value = esri.locations[Cntr].attributes.Y;
cmd.Parameters.Add("@GScountry", SqlDbType.VarChar).Value = esri.locations[Cntr].attributes.Country;
cmd.ExecuteNonQuery();
Cntr ;
};
// Console.WriteLine("Just populated esri feed into maf.addresses_temp table");
// now move content from temp to maf.addresses
var cmdsp = new SqlCommand
{
CommandText = "maf.spESRIGeoCodedUpToMAFAddresses",
CommandType = CommandType.StoredProcedure,
Connection = GEOconn
};
cmdsp.ExecuteNonQuery();
// Console.WriteLine("Just executed maf.spESRIGeoCodedUpToMAFAddresses routine");
SqlCommand scTemp = new SqlCommand(SQLTempRecCount, GEOconn);
int MafTempRecCnt2 = (int)scTemp.ExecuteScalar();
if (MafTempRecCnt2 > 0)
{
Console.WriteLine("Rows exist in maf.addresses_temp and they shouldn't -- bailing out - 2 ");
Console.ReadKey();
return; }
}
while (true);
}
}
public class SpatialReference
{
public int wkid { get; set; }
public int latestWkid { get; set; }
}
public class Attributes
{
public int ResultID { get; set; }
public string Loc_name { get; set; }
public string Status { get; set; }
public Decimal Score { get; set; }
public string Match_addr { get; set; }
public string LongLabel { get; set; }
public string ShortLabel { get; set; }
public string Addr_type { get; set; }
public string Type { get; set; }
public string PlaceName { get; set; }
public string Place_addr { get; set; }
public string Phone { get; set; }
public string URL { get; set; }
public Decimal Rank { get; set; }
public string AddBldg { get; set; }
public string AddNum { get; set; }
public string AddNumFrom { get; set; }
public string AddNumTo { get; set; }
public string AddRange { get; set; }
public string Side { get; set; }
public string StPreDir { get; set; }
public string StPreType { get; set; }
public string StName { get; set; }
public string StType { get; set; }
public string StDir { get; set; }
public string BldgType { get; set; }
public string BldgName { get; set; }
public string LevelType { get; set; }
public string LevelName { get; set; }
public string UnitType { get; set; }
public string UnitName { get; set; }
public string SubAddr { get; set; }
public string StAddr { get; set; }
public string Block { get; set; }
public string Sector { get; set; }
public string Nbrhd { get; set; }
public string District { get; set; }
public string City { get; set; }
public string MetroArea { get; set; }
public string Subregion { get; set; }
public string Region { get; set; }
public string RegionAbbr { get; set; }
public string Territory { get; set; }
public string Zone { get; set; }
public string Postal { get; set; }
public string PostalExt { get; set; }
public string Country { get; set; }
public string LangCode { get; set; }
public int Distance { get; set; }
public Decimal X { get; set; }
public Decimal Y { get; set; }
public Decimal DisplayX { get; set; }
public Decimal DisplayY { get; set; }
public Decimal Xmin { get; set; }
public Decimal Xmax { get; set; }
public Decimal Ymin { get; set; }
public Decimal Ymax { get; set; }
public string ExInfo { get; set; }
}
public class Location
{
public string address { get; set; }
public Location location { get; set; }
public Decimal score { get; set; }
public Attributes attributes { get; set; }
}
public class ESRIcls
{
public SpatialReference spatialReference { get; set; }
public IList<Location> locations { get; set; }
}
}