fix(sidebar): resolve MatchingService live + settings "סגור" label
Sidebar lookups threw ObjectDisposedException on the EspoCrmClient's HttpClient after any settings save. TryInitializeCrm rebuilds the CRM stack (new HttpClient + MatchingService) and disposes the old HttpClient, but the long-lived sidebar ReadingPaneViewModel had captured the old MatchingService and kept calling into the disposed client. ReadingPaneViewModel now resolves the MatchingService live on each lookup via a Func<IMatchingService?> provider (() => host.MatchingService), so it always uses the current stack and degrades gracefully (shows "not configured") when none exists. SidebarController no longer captures a snapshot. Also: rename the Settings dialog's bottom button from "ביטול" to "סגור". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -152,7 +152,7 @@
|
|||||||
MinWidth="100" />
|
MinWidth="100" />
|
||||||
<Button Command="{Binding CancelCommand}"
|
<Button Command="{Binding CancelCommand}"
|
||||||
IsCancel="True"
|
IsCancel="True"
|
||||||
Content="ביטול"
|
Content="סגור"
|
||||||
Padding="20,5"
|
Padding="20,5"
|
||||||
MinWidth="100" />
|
MinWidth="100" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -27,7 +27,12 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
|
|
||||||
public sealed partial class ReadingPaneViewModel : ObservableObject
|
public sealed partial class ReadingPaneViewModel : ObservableObject
|
||||||
{
|
{
|
||||||
private readonly IMatchingService _matchingService;
|
// Resolved live on each lookup rather than captured once: the host
|
||||||
|
// rebuilds the CRM stack (new HttpClient + MatchingService) whenever
|
||||||
|
// settings are saved and disposes the old HttpClient. A captured
|
||||||
|
// snapshot would then call into a disposed HttpClient and throw
|
||||||
|
// ObjectDisposedException on every sidebar lookup.
|
||||||
|
private readonly Func<IMatchingService?> _matchingServiceProvider;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private CancellationTokenSource? _activeLookup;
|
private CancellationTokenSource? _activeLookup;
|
||||||
// Stashes the ambiguous MatchResult while the user is drilling into
|
// Stashes the ambiguous MatchResult while the user is drilling into
|
||||||
@@ -94,9 +99,9 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<string>? OpenInBrowserRequested;
|
public event EventHandler<string>? OpenInBrowserRequested;
|
||||||
|
|
||||||
public ReadingPaneViewModel(IMatchingService matchingService, ILogger logger)
|
public ReadingPaneViewModel(Func<IMatchingService?> matchingServiceProvider, ILogger logger)
|
||||||
{
|
{
|
||||||
_matchingService = matchingService ?? throw new ArgumentNullException(nameof(matchingService));
|
_matchingServiceProvider = matchingServiceProvider ?? throw new ArgumentNullException(nameof(matchingServiceProvider));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,12 +167,20 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
_ambiguousReturnTarget = null;
|
_ambiguousReturnTarget = null;
|
||||||
State = ReadingPaneState.Loading;
|
State = ReadingPaneState.Loading;
|
||||||
|
|
||||||
|
var svc = _matchingServiceProvider();
|
||||||
|
if (svc == null)
|
||||||
|
{
|
||||||
|
ErrorMessage = "התוסף עדיין לא מוגדר. עדכן בהגדרות.";
|
||||||
|
State = ReadingPaneState.Error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
_activeLookup = cts;
|
_activeLookup = cts;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await _matchingService.LookupAsync(senderEmail, cts.Token).ConfigureAwait(true);
|
var result = await svc.LookupAsync(senderEmail, cts.Token).ConfigureAwait(true);
|
||||||
if (cts.IsCancellationRequested) return;
|
if (cts.IsCancellationRequested) return;
|
||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
@@ -296,6 +309,14 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
{
|
{
|
||||||
if (candidate == null || string.IsNullOrWhiteSpace(candidate.Id)) return;
|
if (candidate == null || string.IsNullOrWhiteSpace(candidate.Id)) return;
|
||||||
|
|
||||||
|
var svc = _matchingServiceProvider();
|
||||||
|
if (svc == null)
|
||||||
|
{
|
||||||
|
ErrorMessage = "התוסף עדיין לא מוגדר. עדכן בהגדרות.";
|
||||||
|
State = ReadingPaneState.Error;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CancelInFlight();
|
CancelInFlight();
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
_activeLookup = cts;
|
_activeLookup = cts;
|
||||||
@@ -310,7 +331,7 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await _matchingService.LookupContactAsync(candidate.Id, rememberedEmail, cts.Token).ConfigureAwait(true);
|
var result = await svc.LookupContactAsync(candidate.Id, rememberedEmail, cts.Token).ConfigureAwait(true);
|
||||||
if (cts.IsCancellationRequested) return;
|
if (cts.IsCancellationRequested) return;
|
||||||
|
|
||||||
if (result == null || result.Contact == null)
|
if (result == null || result.Contact == null)
|
||||||
|
|||||||
@@ -33,6 +33,6 @@ using System.Security;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.2.16.0")]
|
[assembly: AssemblyVersion("1.2.17.0")]
|
||||||
[assembly: AssemblyFileVersion("1.2.16.0")]
|
[assembly: AssemblyFileVersion("1.2.17.0")]
|
||||||
|
|
||||||
|
|||||||
@@ -367,7 +367,6 @@ namespace OutlookAddin.Services
|
|||||||
_sidebarController = new SidebarController(
|
_sidebarController = new SidebarController(
|
||||||
taskPanes,
|
taskPanes,
|
||||||
_outlookApp,
|
_outlookApp,
|
||||||
MatchingService!,
|
|
||||||
this,
|
this,
|
||||||
System.Windows.Threading.Dispatcher.CurrentDispatcher,
|
System.Windows.Threading.Dispatcher.CurrentDispatcher,
|
||||||
Logger);
|
Logger);
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ namespace OutlookAddin.Services
|
|||||||
|
|
||||||
private readonly CustomTaskPaneCollection _taskPanes;
|
private readonly CustomTaskPaneCollection _taskPanes;
|
||||||
private readonly Outlook.Application _app;
|
private readonly Outlook.Application _app;
|
||||||
private readonly IMatchingService _matchingService;
|
|
||||||
private readonly AddInHost _host;
|
private readonly AddInHost _host;
|
||||||
private readonly Dispatcher _dispatcher;
|
private readonly Dispatcher _dispatcher;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
@@ -38,14 +37,12 @@ namespace OutlookAddin.Services
|
|||||||
public SidebarController(
|
public SidebarController(
|
||||||
CustomTaskPaneCollection taskPanes,
|
CustomTaskPaneCollection taskPanes,
|
||||||
Outlook.Application app,
|
Outlook.Application app,
|
||||||
IMatchingService matchingService,
|
|
||||||
AddInHost host,
|
AddInHost host,
|
||||||
Dispatcher dispatcher,
|
Dispatcher dispatcher,
|
||||||
ILogger logger)
|
ILogger logger)
|
||||||
{
|
{
|
||||||
_taskPanes = taskPanes ?? throw new ArgumentNullException(nameof(taskPanes));
|
_taskPanes = taskPanes ?? throw new ArgumentNullException(nameof(taskPanes));
|
||||||
_app = app ?? throw new ArgumentNullException(nameof(app));
|
_app = app ?? throw new ArgumentNullException(nameof(app));
|
||||||
_matchingService = matchingService ?? throw new ArgumentNullException(nameof(matchingService));
|
|
||||||
_host = host ?? throw new ArgumentNullException(nameof(host));
|
_host = host ?? throw new ArgumentNullException(nameof(host));
|
||||||
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
|
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
@@ -83,7 +80,7 @@ namespace OutlookAddin.Services
|
|||||||
if (_bindings.ContainsKey(key)) return;
|
if (_bindings.ContainsKey(key)) return;
|
||||||
|
|
||||||
var view = new ReadingPaneView();
|
var view = new ReadingPaneView();
|
||||||
var vm = new ReadingPaneViewModel(_matchingService, _logger)
|
var vm = new ReadingPaneViewModel(() => _host.MatchingService, _logger)
|
||||||
{
|
{
|
||||||
EspoCrmBaseUrl = _host.Settings.EspoCrmUrl
|
EspoCrmBaseUrl = _host.Settings.EspoCrmUrl
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user