2using System.Runtime.CompilerServices;
3using System.Runtime.ExceptionServices;
16 internal class NetworkService : LoadableService, INetworkService
18 private const int defaultXmppPortNumber = 5222;
20 public event EventHandler<ConnectivityChangedEventArgs>? ConnectivityChanged;
22 public NetworkService()
27 public override Task Load(
bool IsResuming, CancellationToken CancellationToken)
29 if (this.
BeginLoad(IsResuming, CancellationToken))
31 if (DeviceInfo.Platform != DevicePlatform.Unknown && !DesignMode.IsDesignModeEnabled)
32 Connectivity.ConnectivityChanged += this.Connectivity_ConnectivityChanged;
37 return Task.CompletedTask;
41 public override Task Unload()
45 if (DeviceInfo.Platform != DevicePlatform.Unknown && !DesignMode.IsDesignModeEnabled)
46 Connectivity.ConnectivityChanged -= this.Connectivity_ConnectivityChanged;
51 return Task.CompletedTask;
54 private void Connectivity_ConnectivityChanged(
object? Sender, ConnectivityChangedEventArgs e)
56 this.ConnectivityChanged.Raise(
this, e);
59 public virtual bool IsOnline =>
60 Connectivity.NetworkAccess == NetworkAccess.Internet ||
61 Connectivity.NetworkAccess == NetworkAccess.ConstrainedInternet;
63 public async Task<(
string HostName,
int Port,
bool IsIpAddress)> LookupXmppHostnameAndPort(
string DomainName)
65 if (IPAddress.TryParse(DomainName, out IPAddress?
_))
66 return (DomainName, defaultXmppPortNumber,
true);
72 if (endpoint is not
null && !
string.IsNullOrWhiteSpace(endpoint.
TargetHost) && endpoint.Port > 0)
80 return (DomainName, defaultXmppPortNumber,
false);
83 public async Task<bool> TryRequest(Func<Task> func,
bool rethrowException =
false,
bool displayAlert =
true,
84 [CallerMemberName]
string memberName =
"")
86 (
bool succeeded,
bool _) = await this.PerformRequestInner(async () =>
90 }, memberName, rethrowException, displayAlert);
95 public Task<(
bool Succeeded, TReturn? ReturnValue)> TryRequest<TReturn>(Func<Task<TReturn>> func,
bool rethrowException =
false,
bool displayAlert =
true, [CallerMemberName]
string memberName =
"")
97 return this.PerformRequestInner(async () => await func(), memberName, rethrowException, displayAlert);
100 private async Task<(
bool Succeeded, TReturn? ReturnValue)> PerformRequestInner<TReturn>(Func<Task<TReturn>> func,
string memberName,
bool rethrowException =
false,
bool displayAlert =
true)
102 Exception ThrownException;
108 ServiceRef.LogService.LogException(ThrownException, GetParameter(memberName));
112 await ServiceRef.UiService.DisplayAlert(
123 catch (AggregateException ae)
125 ThrownException = ae;
127 if (ae.InnerException is TimeoutException te)
129 ServiceRef.LogService.LogException(te, GetParameter(memberName));
133 await ServiceRef.UiService.DisplayAlert(
138 else if (ae.InnerException is TaskCanceledException tce)
140 ServiceRef.LogService.LogException(tce, GetParameter(memberName));
144 await ServiceRef.UiService.DisplayAlert(
149 else if (ae.InnerException is not
null)
151 ServiceRef.LogService.LogException(ae.InnerException, GetParameter(memberName));
155 await ServiceRef.UiService.DisplayAlert(
157 ae.InnerException.Message);
162 ServiceRef.LogService.LogException(ae, GetParameter(memberName));
166 await ServiceRef.UiService.DisplayAlert(
172 catch (TimeoutException te)
174 ThrownException = te;
175 ServiceRef.LogService.LogException(te, GetParameter(memberName));
179 await ServiceRef.UiService.DisplayAlert(
184 catch (TaskCanceledException tce)
186 ThrownException = tce;
187 ServiceRef.LogService.LogException(tce, GetParameter(memberName));
191 await ServiceRef.UiService.DisplayAlert(
200 ThrownException = ex;
203 message = xe.Stanza.InnerText;
205 message = ex.Message;
207 ServiceRef.LogService.LogException(ex, GetParameter(memberName));
211 await ServiceRef.UiService.DisplayAlert(
217 if (rethrowException)
218 ExceptionDispatchInfo.Capture(ThrownException).Throw();
220 return (
false,
default);
223 private static KeyValuePair<string, object?>[] GetParameter(
string MemberName)
225 if (!
string.IsNullOrWhiteSpace(MemberName))
229 new KeyValuePair<string, object?>(
"Caller", MemberName)
static readonly TimeSpan GenericRequest
Generic request timeout
A set of never changing property constants and helpful values.
Represents network errors.
A strongly-typed resource class, for looking up localized strings, etc.
static string RequestTimedOut
Looks up a localized string similar to The request timed out.
static string ThereIsNoNetwork
Looks up a localized string similar to There is no network.
static string RequestWasCancelled
Looks up a localized string similar to The request was cancelled.
static string ErrorTitle
Looks up a localized string similar to An error has occurred.
bool BeginLoad(bool IsResuming, CancellationToken CancellationToken)
Sets the IsLoading flag if the service isn't already loading.
void EndLoad(bool isLoaded)
Sets the IsLoading and IsLoaded flags and fires an event representing the current load state of the s...
bool IsResuming
If App is resuming service.
bool BeginUnload()
Sets the IsLoading flag if the service isn't already unloading.
void EndUnload()
Sets the IsLoading and IsLoaded flags and fires an event representing the current load state of the s...
DNS resolver, as defined in:
static Task< SRV > LookupServiceEndpoint(string DomainName, string ServiceName, string Protocol)
Looks up a service endpoint for a domain. If multiple are available, an appropriate one is selected a...
string TargetHost
Target Host
Base class of XMPP exceptions
XmlElement Stanza
Stanza causing exception.