fix(settings): surface real reason behind "Test connection" failures
The catch-all in TestConnectionAsync was just showing
"שגיאת חיבור: One or more errors occurred." which is useless. Walk the
InnerException chain and translate the underlying SocketError /
TaskCanceled / AuthenticationException into a specific Hebrew message:
- HostNotFound → "השרת {host} לא נמצא ב-DNS"
- ConnectionRefused → "החיבור ל-{host}:{port} נדחה"
- TimedOut → "חיבור פג זמן"
- HostUnreachable / NetworkUnreachable → check VPN/network
- AuthenticationException → bad TLS cert
- TaskCanceled → 15s timeout
- otherwise → "{OuterType}: {OuterMsg} — {InnerType}: {InnerMsg}"
Full exception (with stack) keeps going to the addin log via
_logger.Warning, so the user can still file a diagnostic bundle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -138,8 +138,8 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warning(ex, "TestConnection failed");
|
||||
Fail("שגיאת חיבור: " + ex.Message);
|
||||
_logger.Warning(ex, "TestConnection failed for {Url}", baseUrl);
|
||||
Fail("שגיאת חיבור: " + FormatExceptionForUser(ex, baseUrl));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -147,6 +147,55 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Walks the InnerException chain and pulls out the underlying socket
|
||||
/// error code so the dialog actually tells the user something useful
|
||||
/// (DNS miss, connection refused, TLS failure, etc.) instead of just
|
||||
/// "One or more errors occurred".
|
||||
/// </summary>
|
||||
private static string FormatExceptionForUser(Exception ex, Uri target)
|
||||
{
|
||||
var current = ex;
|
||||
while (current.InnerException != null)
|
||||
{
|
||||
current = current.InnerException;
|
||||
}
|
||||
|
||||
if (current is System.Net.Sockets.SocketException sock)
|
||||
{
|
||||
switch (sock.SocketErrorCode)
|
||||
{
|
||||
case System.Net.Sockets.SocketError.HostNotFound:
|
||||
return $"השרת {target.Host} לא נמצא ב-DNS. ודא שהכתובת נכונה ושיש חיבור לאינטרנט.";
|
||||
case System.Net.Sockets.SocketError.ConnectionRefused:
|
||||
return $"החיבור ל-{target.Host}:{target.Port} נדחה. ודא שהשרת רץ ומאזין.";
|
||||
case System.Net.Sockets.SocketError.TimedOut:
|
||||
return $"חיבור ל-{target.Host} פג זמן. ייתכן שהשרת לא זמין או שיש חסימה ברשת.";
|
||||
case System.Net.Sockets.SocketError.NetworkUnreachable:
|
||||
case System.Net.Sockets.SocketError.HostUnreachable:
|
||||
return "לא הצלחתי להגיע לרשת של השרת. בדוק את ה-VPN/חיבור הרשת.";
|
||||
default:
|
||||
return $"שגיאת רשת ({sock.SocketErrorCode}): {sock.Message}";
|
||||
}
|
||||
}
|
||||
if (current is TaskCanceledException)
|
||||
{
|
||||
return "החיבור לא הגיב תוך 15 שניות. השרת אולי לא זמין או שהוא איטי.";
|
||||
}
|
||||
if (current is System.Security.Authentication.AuthenticationException)
|
||||
{
|
||||
return "אישור ה-TLS של השרת לא תקין. בדוק את הקישור (https vs http) או פנה לאדמין.";
|
||||
}
|
||||
|
||||
// Fallback: outer + inner with newline so the user sees the chain.
|
||||
var outer = ex.GetType().Name + ": " + ex.Message;
|
||||
if (current != ex)
|
||||
{
|
||||
outer += " — " + current.GetType().Name + ": " + current.Message;
|
||||
}
|
||||
return outer;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void Save()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user