From cceedf2883ecea89f5596e149c2f11f8297adb4f Mon Sep 17 00:00:00 2001 From: Seji64 Date: Wed, 10 Jul 2024 14:51:05 +0200 Subject: [PATCH] Code refactor, remove newtonsoft.json --- Classes/ConvertOptions.cs | 4 +- Classes/ConvertTask.cs | 10 ++-- Classes/GpsRow.cs | 35 ++++++++++++++ Classes/Gpx11SerializerAsync.cs | 10 ++-- Classes/Itinerary.cs | 20 ++++---- Classes/ItineraryFile.cs | 16 +++---- Classes/JsonDateTimeConverter.cs | 20 ++++++++ Classes/Preferences.cs | 14 +++--- Classes/Stop.cs | 14 +++--- Classes/Trip.cs | 56 ++++++++++++++++++++++ GPXRide.csproj | 9 ++-- Pages/Index.razor | 79 ++++++++++++++------------------ Pages/Index.razor.cs | 79 +++++++++++++++----------------- Program.cs | 2 +- 14 files changed, 231 insertions(+), 137 deletions(-) create mode 100644 Classes/GpsRow.cs create mode 100644 Classes/JsonDateTimeConverter.cs create mode 100644 Classes/Trip.cs diff --git a/Classes/ConvertOptions.cs b/Classes/ConvertOptions.cs index e3d033e..2e44613 100644 --- a/Classes/ConvertOptions.cs +++ b/Classes/ConvertOptions.cs @@ -3,8 +3,8 @@ namespace GPXRide.Classes public class ConvertOptions { public bool Motorway { get; set; } = true; - public bool TollFree { get; set; } = false; - public bool DirtyRoads { get; set; } = false; + public bool TollFree { get; set; } + public bool DirtyRoads { get; set; } public bool Tunnel { get; set; } = true; public bool Trains { get; set; } = true; public bool Ferry { get; set; } = true; diff --git a/Classes/ConvertTask.cs b/Classes/ConvertTask.cs index 88bee42..70e1c1e 100644 --- a/Classes/ConvertTask.cs +++ b/Classes/ConvertTask.cs @@ -1,18 +1,16 @@ using Geo.Gps.Serialization.Xml.Gpx.Gpx11; using GPXRide.Enums; -using MudBlazor; namespace GPXRide.Classes { public class ConvertTask { - public int? Id { get; set; } = null; - public GpxFile OriginalGpxFile { get; set; } = null; - public string FileName { get; set; } - public ItineraryFile ConvertedItineraryFile { get; set; } = null; + public int? Id { get; init; } + public GpxFile OriginalGpxFile { get; set; } + public string FileName { get; init; } + public ItineraryFile ConvertedItineraryFile { get; set; } public ConvertState State { get; set; } = ConvertState.None; public ConvertOptions ConvertOptions { get; set; } = new(); - public MudChip SelectedSourceChip { get; set; } public SourceType SourceType { get; set; } } } \ No newline at end of file diff --git a/Classes/GpsRow.cs b/Classes/GpsRow.cs new file mode 100644 index 0000000..5245fad --- /dev/null +++ b/Classes/GpsRow.cs @@ -0,0 +1,35 @@ +using System.Text.Json.Serialization; + +namespace GPXRide.Classes; +public class GpsRow +{ + [JsonPropertyName("rollAngle")] + public double RollAngle { get; set; } + [JsonPropertyName("gear")] + public int Gear { get; set; } + [JsonPropertyName("index")] + public int Index { get; set; } + [JsonPropertyName("engineSpeed")] + public int EngineSpeed { get; set; } + [JsonPropertyName("tripId")] + public string TripId { get; set; } + [JsonPropertyName("throttle")] + public int Throttle { get; set; } + [JsonPropertyName("fix")] + public int Fix { get; set; } + [JsonPropertyName("altitude")] + public double Altitude { get; set; } + [JsonPropertyName("time")] + public string Time { get; set; } + [JsonPropertyName("airTemperature")] + public int AirTemperature { get; set; } + [JsonPropertyName("latitude")] + public double Latitude { get; set; } + [JsonPropertyName("distanceInMeterFromStart")] + public int DistanceInMeterFromStart { get; set; } + [JsonPropertyName("rpm")] + public int Rpm { get; set; } + [JsonPropertyName("longitude")] + public double Longitude { get; set; } +} + diff --git a/Classes/Gpx11SerializerAsync.cs b/Classes/Gpx11SerializerAsync.cs index 6f0cb35..c9a0287 100644 --- a/Classes/Gpx11SerializerAsync.cs +++ b/Classes/Gpx11SerializerAsync.cs @@ -10,12 +10,12 @@ public class Gpx11SerializerAsync : Gpx11Serializer { public static async Task DeserializeAsync(Stream stream) { - using var streamReader = new StreamReader(stream); - var data = await streamReader.ReadToEndAsync(); - var xmlSerializer = new XmlSerializer(typeof(GpxFile)); + using StreamReader streamReader = new StreamReader(stream); + string data = await streamReader.ReadToEndAsync(); + XmlSerializer xmlSerializer = new XmlSerializer(typeof(GpxFile)); - using var stringReader = new StringReader(data); - var gpxFile = (GpxFile)xmlSerializer.Deserialize(stringReader); + using StringReader stringReader = new StringReader(data); + GpxFile gpxFile = (GpxFile)xmlSerializer.Deserialize(stringReader); return gpxFile; } } diff --git a/Classes/Itinerary.cs b/Classes/Itinerary.cs index b027a69..bb3f11d 100644 --- a/Classes/Itinerary.cs +++ b/Classes/Itinerary.cs @@ -1,36 +1,36 @@ using System; using System.Collections.Generic; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace GPXRide.Classes { public class Itinerary { - [JsonProperty("length")] + [JsonPropertyName("length")] public int Length { get; set; } - [JsonProperty("preferences")] + [JsonPropertyName("preferences")] public Preferences Preferences { get; set; } = new(); - [JsonProperty("id")] + [JsonPropertyName("id")] public string Id { get; set; } - [JsonProperty("creationDate")] + [JsonPropertyName("creationDate")] public DateTime CreationDate { get; set; } = DateTime.Now; - [JsonProperty("nations")] + [JsonPropertyName("nations")] public List Nations { get; set; } = []; - [JsonProperty("duration")] + [JsonPropertyName("duration")] public int Duration { get; set; } - [JsonProperty("stops")] + [JsonPropertyName("stops")] public List Stops { get; set; } = []; - [JsonProperty("name")] + [JsonPropertyName("name")] public string Name { get; set; } - [JsonProperty("vehicleClass")] + [JsonPropertyName("vehicleClass")] public string VehicleClass { get; set; } } } \ No newline at end of file diff --git a/Classes/ItineraryFile.cs b/Classes/ItineraryFile.cs index f1916ed..c5b2d04 100644 --- a/Classes/ItineraryFile.cs +++ b/Classes/ItineraryFile.cs @@ -1,23 +1,23 @@ using System.IO; using System.IO.Compression; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; +using System.Text; +using System.Text.Json; namespace GPXRide.Classes { public class ItineraryFile { - public Itinerary Itinerary { get; set; } = new(); + public Itinerary Itinerary { get; } = new(); public MemoryStream ToZipArchiveStream() { MemoryStream memoryStream = new(); - using var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true); - var demoFile = archive.CreateEntry("itinerary.json"); + using ZipArchive archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true); + ZipArchiveEntry demoFile = archive.CreateEntry("itinerary.json"); - using var entryStream = demoFile.Open(); - var ItineraryText = JsonConvert.SerializeObject(Itinerary, new IsoDateTimeConverter() { DateTimeFormat = "yyyy-MM-ddTHH:mm:ssZ" }); - MemoryStream stream = new(System.Text.Encoding.UTF8.GetBytes(ItineraryText)); + using Stream entryStream = demoFile.Open(); + string itineraryText = JsonSerializer.Serialize(Itinerary, new JsonSerializerOptions() { Converters = { new JsonDateTimeConverter() }}); + MemoryStream stream = new(Encoding.UTF8.GetBytes(itineraryText)); stream.WriteTo(entryStream); return memoryStream; diff --git a/Classes/JsonDateTimeConverter.cs b/Classes/JsonDateTimeConverter.cs new file mode 100644 index 0000000..7f8ed8d --- /dev/null +++ b/Classes/JsonDateTimeConverter.cs @@ -0,0 +1,20 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace GPXRide.Classes; + +public class JsonDateTimeConverter : JsonConverter +{ + private const string DateTimeFormat = "yyyy-MM-ddTHH:mm:ssZ"; + + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return DateTime.ParseExact(reader.GetString() ?? string.Empty, DateTimeFormat, null); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString(DateTimeFormat)); + } +} \ No newline at end of file diff --git a/Classes/Preferences.cs b/Classes/Preferences.cs index da4c20a..3e4a69f 100644 --- a/Classes/Preferences.cs +++ b/Classes/Preferences.cs @@ -1,25 +1,25 @@ -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace GPXRide.Classes { public class Preferences { - [JsonProperty("motorway")] + [JsonPropertyName("motorway")] public bool Motorway { get; set; } - [JsonProperty("tunnel")] + [JsonPropertyName("tunnel")] public bool Tunnel { get; set; } - [JsonProperty("dirtRoads")] + [JsonPropertyName("dirtRoads")] public bool DirtRoads { get; set; } - [JsonProperty("trains")] + [JsonPropertyName("trains")] public bool Trains { get; set; } - [JsonProperty("tollFree")] + [JsonPropertyName("tollFree")] public bool TollFree { get; set; } - [JsonProperty("ferry")] + [JsonPropertyName("ferry")] public bool Ferry { get; set; } } } \ No newline at end of file diff --git a/Classes/Stop.cs b/Classes/Stop.cs index 7ae1f19..3c7bc54 100644 --- a/Classes/Stop.cs +++ b/Classes/Stop.cs @@ -1,26 +1,26 @@ using System; -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace GPXRide.Classes { public class Stop { - [JsonProperty("date")] + [JsonPropertyName("date")] public DateTime Date { get; set; } = DateTime.Now; - [JsonProperty("isMyPosition")] + [JsonPropertyName("isMyPosition")] public bool IsMyPosition { get; set; } - [JsonProperty("latitude")] + [JsonPropertyName("latitude")] public decimal Latitude { get; set; } - [JsonProperty("city")] + [JsonPropertyName("city")] public string City { get; set; } - [JsonProperty("longitude")] + [JsonPropertyName("longitude")] public decimal Longitude { get; set; } - [JsonProperty("address")] + [JsonPropertyName("address")] public string Address { get; set; } } } \ No newline at end of file diff --git a/Classes/Trip.cs b/Classes/Trip.cs new file mode 100644 index 0000000..0c92d0a --- /dev/null +++ b/Classes/Trip.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace GPXRide.Classes; + +public class Trip +{ + [JsonPropertyName(nameof(Id))] + public string Id { get; set; } + [JsonPropertyName("bikeModel")] + public string BikeModel { get; set; } + [JsonPropertyName("totalTimeInSeconds")] + public int TotalTimeInSeconds { get; set; } + [JsonPropertyName("downloadedSizeInBytes")] + public int DownloadedSizeInBytes { get; set; } + [JsonPropertyName("maxThrottle")] + public int MaxThrottle { get; set; } + [JsonPropertyName("isCompleted")] + public bool IsCompleted { get; set; } + [JsonPropertyName("startAddress")] + public int StartAddress { get; set; } + [JsonPropertyName("endDate")] + public string EndDate { get; set; } + [JsonPropertyName("skippedRowsForMissingData")] + public int SkippedRowsForMissingData { get; set; } + [JsonPropertyName("countries")] + public string[] Countries { get; set; } + [JsonPropertyName("maxRollAngle")] + public double MaxRollAngle { get; set; } + [JsonPropertyName("uom")] + public string Uom { get; set; } + [JsonPropertyName("title")] + public string Title { get; set; } + [JsonPropertyName("stopAddress")] + public int StopAddress { get; set; } + [JsonPropertyName("startDate")] + public string StartDate { get; set; } + [JsonPropertyName("maxSpeedKmh")] + public int MaxSpeedKmh { get; set; } + [JsonPropertyName("imageName")] + public string ImageName { get; set; } + [JsonPropertyName("totalDistanceInMeters")] + public int TotalDistanceInMeters { get; set; } + [JsonPropertyName("temporaryGpsUnitTripId")] + public int TemporaryGpsUnitTripId { get; set; } + [JsonPropertyName("skippedRowsForInvalidLocation")] + public int SkippedRowsForInvalidLocation { get; set; } + [JsonPropertyName("avgSpeedKmh")] + public double AvgSpeedKmh { get; set; } + [JsonPropertyName("language")] + public string Language { get; set; } + + [JsonIgnore] + public List GpsRows { get; set; } + +} \ No newline at end of file diff --git a/GPXRide.csproj b/GPXRide.csproj index 6307df8..b711f9c 100644 --- a/GPXRide.csproj +++ b/GPXRide.csproj @@ -12,11 +12,10 @@ - - - - - + + + + diff --git a/Pages/Index.razor b/Pages/Index.razor index 766ecd3..da704cb 100644 --- a/Pages/Index.razor +++ b/Pages/Index.razor @@ -1,41 +1,38 @@ @page "/" -@using BlazorDownloadFile @using Geo.Gps.Serialization.Xml.Gpx.Gpx11 @using GPXRide.Classes @using GPXRide.Enums -@using Serilog @inject ISnackbar Snackbar -@inject IJSRuntime JS +@inject IJSRuntime Js - + + StartIcon="@Icons.Material.Filled.CloudUpload"> Upload & Convert GPX Files - + - @foreach (var m_task in ConvertTasks) + @foreach (ConvertTask task in _convertTasks) { - var m_gpxFile = m_task.OriginalGpxFile; - m_task.ConvertOptions.RouteName = string.IsNullOrWhiteSpace(m_task.ConvertOptions.RouteName) ? m_task.FileName : m_task.ConvertOptions.RouteName; + GpxFile gpxFile = task.OriginalGpxFile; + task.ConvertOptions.RouteName = string.IsNullOrWhiteSpace(task.ConvertOptions.RouteName) ? task.FileName : task.ConvertOptions.RouteName; - @if (m_gpxFile is null) + @if (gpxFile is null) { @@ -50,7 +47,7 @@ - + } @@ -58,24 +55,24 @@ { - @m_gpxFile.metadata.name + @gpxFile.metadata.name - + Route Preferences - - - + + + - - - + + + @@ -83,56 +80,56 @@ Convert Options - + - @if (GetSourceTypes(m_gpxFile).Count >= 2) + @if (GetSourceTypes(gpxFile).Count >= 2) { Select Source Type - - @if (m_gpxFile.wpt != null && m_gpxFile.wpt.Any()) + + @if (gpxFile.wpt != null && gpxFile.wpt.Any()) { - Waypoints + Waypoints } - @if (m_gpxFile.trk != null && m_gpxFile.trk.Any()) + @if (gpxFile.trk != null && gpxFile.trk.Any()) { - Track + Track } - @if (m_gpxFile.rte != null && m_gpxFile.rte.Any()) + @if (gpxFile.rte != null && gpxFile.rte.Any()) { - Route + Route } } - + - @switch (m_task.State) + @switch (task.State) { case ConvertState.Working: - Converting... + Converting... break; case ConvertState.Completed: - Conversion successfull - await BlazorDownloadFileService.DownloadFile($"{m_task.ConvertOptions.RouteName}.mvitinerary",m_task.ConvertedItineraryFile.ToZipArchiveStream(),"application/octet-stream")) Icon="@Icons.Material.Filled.FileDownload" Color="Color.Primary" aria-label="Download" /> + Conversion successful + await BlazorDownloadFileService.DownloadFile($"{task.ConvertOptions.RouteName}.mvitinerary",task.ConvertedItineraryFile.ToZipArchiveStream(),"application/octet-stream")) Icon="@Icons.Material.Filled.FileDownload" Color="Color.Primary" aria-label="Download" /> @if (_webShareSupported) { - + } break; case ConvertState.Error: - Conversion failed - + Conversion failed + break; default: - Convert to Itinerary + Convert to Itinerary break; } @@ -141,12 +138,6 @@ } - - - - - - \ No newline at end of file diff --git a/Pages/Index.razor.cs b/Pages/Index.razor.cs index c417f39..545bc87 100644 --- a/Pages/Index.razor.cs +++ b/Pages/Index.razor.cs @@ -1,24 +1,25 @@ -using BlazorDownloadFile; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using BlazorDownloadFile; +using Geo.Gps.Serialization.Xml.Gpx.Gpx11; using GPXRide.Classes; using GPXRide.Enums; -using Microsoft.AspNetCore.Components.Forms; using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Forms; using Microsoft.JSInterop; using MudBlazor; -using System.Collections.Generic; -using System.Threading.Tasks; -using System; using Serilog; -using Geo.Gps.Serialization.Xml.Gpx.Gpx11; -using System.Linq; namespace GPXRide.Pages { public partial class Index { [Inject] IBlazorDownloadFileService BlazorDownloadFileService { get; set; } - readonly List ConvertTasks = []; - private bool _webShareSupported = false; + readonly List _convertTasks = []; + private bool _webShareSupported; protected override async Task OnInitializedAsync() { @@ -36,7 +37,7 @@ private static async Task ConvertToItinerary(ConvertTask convertTask) try { - ItineraryFile m_ItineraryFile = new() + ItineraryFile mItineraryFile = new() { Itinerary = { @@ -57,7 +58,7 @@ private static async Task ConvertToItinerary(ConvertTask convertTask) } } }; - SourceType type = convertTask.SelectedSourceChip is null ? (SourceType)Enum.Parse(typeof(SourceType), GetSourceTypes(convertTask.OriginalGpxFile).FirstOrDefault()) : (SourceType)Enum.Parse(typeof(SourceType), convertTask.SelectedSourceChip.Text); + SourceType type = convertTask.SourceType; Log.Debug("Selected Route Type:{Type}", type.ToString()); GpxWaypoint[] waypoints = type switch { @@ -72,11 +73,11 @@ private static async Task ConvertToItinerary(ConvertTask convertTask) throw new InvalidOperationException("failed to get any Waypoints"); } - foreach (var point in waypoints) + foreach (GpxWaypoint point in waypoints) { Log.Debug("Waypoint: Latitude: {Lat} , Longitude: {Lon}", point.lat, point.lon); - var stop = new Stop() + Stop stop = new Stop { Latitude = point.lat, Longitude = point.lon, @@ -85,15 +86,15 @@ private static async Task ConvertToItinerary(ConvertTask convertTask) }; - if (convertTask.ConvertOptions.FirstWaypointAsMyPosition && m_ItineraryFile.Itinerary.Stops.Count == 0) + if (convertTask.ConvertOptions.FirstWaypointAsMyPosition && mItineraryFile.Itinerary.Stops.Count == 0) { stop.IsMyPosition = true; } - m_ItineraryFile.Itinerary.Stops.Add(stop); + mItineraryFile.Itinerary.Stops.Add(stop); } - return m_ItineraryFile; + return mItineraryFile; } catch (Exception ex) @@ -109,22 +110,22 @@ private static async Task ConvertToItinerary(ConvertTask convertTask) private void UploadFiles(IReadOnlyList files) { - long MAXALLOWEDSIZE = 2097152; + long maxallowedsize = 2097152; bool errorOnUpload = false; - object _lock = new(); + object @lock = new(); files.AsParallel().AsOrdered().ForAll(async fileentry => { - int? _Id = 0; + int? id = 0; - lock (_lock) + lock (@lock) { - _Id = ConvertTasks.Count != 0 ? (ConvertTasks[^1].Id + 1) : 0; - ConvertTasks.Add(new ConvertTask() + id = _convertTasks.Count != 0 ? (_convertTasks[^1].Id + 1) : 0; + _convertTasks.Add(new ConvertTask { - Id = _Id, + Id = id, OriginalGpxFile = null, - FileName = System.IO.Path.GetFileNameWithoutExtension(fileentry.Name) + FileName = Path.GetFileNameWithoutExtension(fileentry.Name) }); } @@ -133,14 +134,14 @@ private void UploadFiles(IReadOnlyList files) try { Log.Debug("Deserialize GPX File..."); - var gpxFile = await Gpx11SerializerAsync.DeserializeAsync(fileentry.OpenReadStream(MAXALLOWEDSIZE)); + GpxFile gpxFile = await Gpx11SerializerAsync.DeserializeAsync(fileentry.OpenReadStream(maxallowedsize)); if (gpxFile != null) { Log.Debug("GPX File deserialized!"); - Log.Debug("Attaching GpxFile to ConvertTask with Id {Id}", _Id); + Log.Debug("Attaching GpxFile to ConvertTask with Id {Id}", id); - ConvertTasks.Single(x => x.Id == _Id).OriginalGpxFile = gpxFile; + _convertTasks.Single(x => x.Id == id).OriginalGpxFile = gpxFile; Log.Debug(("Done")); } else @@ -152,8 +153,8 @@ private void UploadFiles(IReadOnlyList files) { Log.Error("{ErrorMessage}", ex.Message); errorOnUpload = true; - Log.Debug("Removing Convert Task with Id {Id}", _Id); - ConvertTasks.RemoveAll(x => x.Id == _Id); + Log.Debug("Removing Convert Task with Id {Id}", id); + _convertTasks.RemoveAll(x => x.Id == id); } finally { @@ -167,14 +168,8 @@ private void UploadFiles(IReadOnlyList files) } else { - if (ConvertTasks.Count != 0) - { - Snackbar.Add("Some files failed to upload", Severity.Warning); - } - else - { - Snackbar.Add("Failed to upload files", Severity.Warning); - } + Snackbar.Add(_convertTasks.Count != 0 ? "Some files failed to upload" : "Failed to upload files", + Severity.Warning); } } @@ -200,27 +195,27 @@ private static List GetSourceTypes(GpxFile gpxFile) private void DisposeConvertTask(ConvertTask convertTask) { - ConvertTasks.Remove(convertTask); + _convertTasks.Remove(convertTask); } private async Task IsWebShareSupportedAsync() { - return (await JS.InvokeAsync("IsShareSupported")); + return (await Js.InvokeAsync("IsShareSupported")); } private async Task ShareItineraryFile(ConvertTask task) { string payload = Convert.ToBase64String(task.ConvertedItineraryFile.ToZipArchiveStream().ToArray()); - if (await JS.InvokeAsync("CanShareThisFile", $"{task.ConvertOptions.RouteName}.mvitinerary", "application/octet-stream", $"data:text/plain;base64,{payload}")) + if (await Js.InvokeAsync("CanShareThisFile", $"{task.ConvertOptions.RouteName}.mvitinerary", "application/octet-stream", $"data:text/plain;base64,{payload}")) { try { - await JS.InvokeVoidAsync("ShareFile", "Share Itinerary File", task.ConvertOptions.RouteName, $"{task.ConvertOptions.RouteName}.mvitinerary", "application/octet-stream", $"data:text/plain;base64,{payload}"); + await Js.InvokeVoidAsync("ShareFile", "Share Itinerary File", task.ConvertOptions.RouteName, $"{task.ConvertOptions.RouteName}.mvitinerary", "application/octet-stream", $"data:text/plain;base64,{payload}"); } catch (JSException ex) { - if (ex.Message != null && ex.Message.Contains("Permission denied")) + if (ex.Message.Contains("Permission denied")) { Snackbar.Add("Sorry! - Your Browser does not support sharing of this type of file!", Severity.Error); } diff --git a/Program.cs b/Program.cs index 55f905f..575daef 100644 --- a/Program.cs +++ b/Program.cs @@ -1,10 +1,10 @@ using System; using System.Net.Http; using System.Threading.Tasks; +using BlazorDownloadFile; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.Extensions.DependencyInjection; using MudBlazor.Services; -using BlazorDownloadFile; using Serilog; namespace GPXRide