Improve cadastral GPS reliability and mobile overlays
This commit is contained in:
1 parent
29c3848a22
commit
5ea424b46c
7 files changed
+243
-30
No files matched your search
@@ -1,4 +1,6 @@
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace LMEMappeCatastaliApp.Services;
|
||||
@@ -13,8 +15,9 @@ public sealed class OfficialCadastreService
|
||||
|
||||
public OfficialCadastreService()
|
||||
{
|
||||
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LMEMappeCatastali/0.2");
|
||||
_httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/gml+xml");
|
||||
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LMEMappeCatastali/1.0 (Android)");
|
||||
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/gml+xml"));
|
||||
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml", 0.9));
|
||||
}
|
||||
|
||||
public async Task<string> GetParcelsNearAsync(
|
||||
@@ -22,14 +25,30 @@ public sealed class OfficialCadastreService
|
||||
double longitude,
|
||||
double radiusMeters,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> await GetFeaturesNearAsync(
|
||||
{
|
||||
var firstRadius = Math.Clamp(radiusMeters, 12, 30);
|
||||
var xml = await GetFeaturesNearAsync(
|
||||
latitude,
|
||||
longitude,
|
||||
radiusMeters,
|
||||
firstRadius,
|
||||
"CP:CadastralParcel",
|
||||
100,
|
||||
cancellationToken);
|
||||
|
||||
if (firstRadius >= 30 || ContainsFeatures(xml))
|
||||
{
|
||||
return xml;
|
||||
}
|
||||
|
||||
return await GetFeaturesNearAsync(
|
||||
latitude,
|
||||
longitude,
|
||||
30,
|
||||
"CP:CadastralParcel",
|
||||
100,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<string> GetSheetsNearAsync(
|
||||
double latitude,
|
||||
double longitude,
|
||||
@@ -78,15 +97,65 @@ public sealed class OfficialCadastreService
|
||||
var url = WfsEndpoint + "?" + string.Join("&", query.Select(item =>
|
||||
$"{Uri.EscapeDataString(item.Key)}={Uri.EscapeDataString(item.Value)}"));
|
||||
|
||||
using var response = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseContentRead, cancellationToken);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
for (var attempt = 0; attempt < 3; attempt++)
|
||||
{
|
||||
throw new HttpRequestException($"Il servizio WFS AdE ha risposto {((int)response.StatusCode)}.");
|
||||
try
|
||||
{
|
||||
using var request = new HttpRequestMessage(HttpMethod.Get, url)
|
||||
{
|
||||
Version = HttpVersion.Version11,
|
||||
VersionPolicy = HttpVersionPolicy.RequestVersionOrLower
|
||||
};
|
||||
request.Headers.CacheControl = new CacheControlHeaderValue { NoCache = true };
|
||||
|
||||
using var response = await _httpClient.SendAsync(
|
||||
request,
|
||||
HttpCompletionOption.ResponseContentRead,
|
||||
cancellationToken);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var xml = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
ThrowIfExceptionReport(xml);
|
||||
return xml;
|
||||
}
|
||||
|
||||
if (attempt < 2 && IsTransient(response.StatusCode))
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(500 * (attempt + 1)), cancellationToken);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new HttpRequestException($"Il servizio WFS AdE ha risposto {((int)response.StatusCode)}.");
|
||||
}
|
||||
catch (HttpRequestException) when (attempt < 2)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(500 * (attempt + 1)), cancellationToken);
|
||||
}
|
||||
catch (TaskCanceledException) when (!cancellationToken.IsCancellationRequested && attempt < 2)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(500 * (attempt + 1)), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
var xml = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
ThrowIfExceptionReport(xml);
|
||||
return xml;
|
||||
throw new HttpRequestException("Il servizio WFS AdE non ha risposto dopo tre tentativi.");
|
||||
}
|
||||
|
||||
private static bool IsTransient(HttpStatusCode statusCode) =>
|
||||
statusCode is HttpStatusCode.RequestTimeout or HttpStatusCode.TooManyRequests
|
||||
|| (int)statusCode >= 500;
|
||||
|
||||
private static bool ContainsFeatures(string xml)
|
||||
{
|
||||
try
|
||||
{
|
||||
var document = XDocument.Parse(xml);
|
||||
return document.Descendants().Any(element =>
|
||||
element.Name.LocalName is "member" or "featureMember");
|
||||
}
|
||||
catch (System.Xml.XmlException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string Format(double value) => value.ToString("R", CultureInfo.InvariantCulture);
|
||||
|
||||
Reference in new issue
Block a user