Datei-Logging und Tray-Benachrichtigung fuer Office365 Device-Code-Login

This commit is contained in:
dimedtec 2026-08-28 16:43:08 +02:00
parent d7869b977f
commit ee3e6124a3
4 changed files with 75 additions and 1 deletions

View file

@ -1,3 +1,4 @@
using System.IO;
using Anrufmonitor.Contacts;
using Anrufmonitor.Sip;
using Microsoft.Extensions.Configuration;
@ -29,6 +30,10 @@ public partial class App : System.Windows.Application
builder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false);
builder.AddJsonFile("appsettings.Local.json", optional: true, reloadOnChange: false);
})
.ConfigureLogging(logging =>
{
logging.AddProvider(new FileLoggerProvider(Path.Combine(AppContext.BaseDirectory, "anrufmonitor.log")));
})
.ConfigureServices((context, services) =>
{
services.Configure<ContactsOptions>(context.Configuration.GetSection(ContactsOptions.SectionName));
@ -42,7 +47,8 @@ public partial class App : System.Windows.Application
return new ContactCache(options.ResolveCacheDatabasePath(), sp.GetRequiredService<ILogger<ContactCache>>());
});
services.AddSingleton<IContactProvider, Office365ContactProvider>();
services.AddSingleton<Office365ContactProvider>();
services.AddSingleton<IContactProvider>(sp => sp.GetRequiredService<Office365ContactProvider>());
services.AddSingleton<IContactProvider, GoogleContactProvider>();
services.AddSingleton<IReverseLookupProvider, PublicDirectoryLookupProvider>();
@ -71,11 +77,19 @@ public partial class App : System.Windows.Application
onExit: () => System.Windows.Application.Current.Shutdown());
_trayIconManager.Show();
var office365Provider = _host.Services.GetRequiredService<Office365ContactProvider>();
office365Provider.DeviceCodeRequired += message =>
{
_trayIconManager?.ShowNotification("Office365-Anmeldung erforderlich", message);
};
sipMonitor.IncomingCall += async (_, args) =>
{
logger.LogInformation("App: IncomingCall-Event empfangen von {Number}", args.CallerNumber);
try
{
var contact = await lookupService.ResolveAsync(args.CallerNumber, CancellationToken.None);
logger.LogInformation("App: Kontakt aufgeloest zu {Name}", contact.DisplayName);
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
var popup = new CallPopupWindow(contact, args.CallId);

View file

@ -0,0 +1,48 @@
using System.IO;
using Microsoft.Extensions.Logging;
namespace Anrufmonitor.App;
/// <summary>
/// Minimaler Datei-Logger fuer die Fehlersuche, da die App als WinExe ohne Konsole
/// laeuft und Konsolen-Redirect beim Starten aus Skripten unzuverlaessig ist.
/// Schreibt nach anrufmonitor.log neben der .exe.
/// </summary>
public sealed class FileLoggerProvider(string filePath) : ILoggerProvider
{
private readonly object _lock = new();
public ILogger CreateLogger(string categoryName) => new FileLogger(categoryName, filePath, _lock);
public void Dispose()
{
}
private sealed class FileLogger(string categoryName, string filePath, object lockObj) : ILogger
{
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Debug;
public void Log<TState>(
LogLevel logLevel, EventId eventId, TState state, Exception? exception,
Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}
var line = $"{DateTime.Now:HH:mm:ss.fff} [{logLevel}] {categoryName}: {formatter(state, exception)}";
if (exception is not null)
{
line += Environment.NewLine + exception;
}
lock (lockObj)
{
File.AppendAllText(filePath, line + Environment.NewLine);
}
}
}
}

View file

@ -35,6 +35,14 @@ public sealed class TrayIconManager : IDisposable
public void Show() => _notifyIcon.Visible = true;
public void ShowNotification(string title, string message)
{
_notifyIcon.Visible = true;
_notifyIcon.BalloonTipTitle = title;
_notifyIcon.BalloonTipText = message;
_notifyIcon.ShowBalloonTip(30000);
}
public void Dispose()
{
_notifyIcon.Visible = false;

View file

@ -26,6 +26,9 @@ public sealed class Office365ContactProvider : IContactProvider
public bool IsEnabled => _options.Office365.Enabled && !string.IsNullOrWhiteSpace(_options.Office365.ClientId);
/// <summary>Feuert mit der fuer den Benutzer bestimmten Anmelde-Nachricht (Code + URL) des Device-Code-Flows.</summary>
public event Action<string>? DeviceCodeRequired;
public async Task<IReadOnlyList<ContactInfo>> GetAllContactsAsync(CancellationToken cancellationToken)
{
if (!IsEnabled)
@ -42,6 +45,7 @@ public sealed class Office365ContactProvider : IContactProvider
_logger.LogWarning(
"Office365-Anmeldung erforderlich: {Message}",
info.Message);
DeviceCodeRequired?.Invoke(info.Message);
return Task.CompletedTask;
},
});