fix(updater): replace broken ApplicationDeployment API with manifest GET
Log shows TrustNotGrantedException thrown inside CheckForDetailedUpdate itself (ApplicationTrust.RequestTrust → DetermineTrustCore → DetermineTrust). The misleading "המשתמש סירב להעניק את ההרשאות" fires even when the user accepted the trust dialog on install and the publisher cert is unchanged: ApplicationDeployment.CheckForDetailedUpdate re-runs the TrustManager evaluation, which can't show a UAC-style prompt from inside a hosted Outlook process and falls through to a denial exception. Bypass the ClickOnce update API entirely: 1. Read CurrentVersion from ApplicationDeployment (this part is fine) 2. HTTP GET the .vsto manifest at UpdateLocation, parse the top-level <assemblyIdentity> version 3. Compare versions 4. If newer, Process.Start the .vsto URL with UseShellExecute=true so Windows hands it to VSTOInstaller.exe — which is the only thing that actually knows how to update a running VSTO add-in correctly ApplicationDeployment.Update() is also dropped because it has the same in-process limitation as the trust check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
@@ -178,18 +179,61 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
var deployment = System.Deployment.Application.ApplicationDeployment.CurrentDeployment;
|
var deployment = System.Deployment.Application.ApplicationDeployment.CurrentDeployment;
|
||||||
var info = await Task.Run(() => deployment.CheckForDetailedUpdate(false)).ConfigureAwait(true);
|
var currentVersion = deployment.CurrentVersion;
|
||||||
if (!info.UpdateAvailable)
|
var manifestUri = deployment.UpdateLocation;
|
||||||
|
|
||||||
|
// ApplicationDeployment.CheckForDetailedUpdate triggers a
|
||||||
|
// TrustManager re-evaluation which throws TrustNotGranted
|
||||||
|
// inside a hosted VSTO process even when the publisher and
|
||||||
|
// permissions are unchanged. Bypass it by fetching the
|
||||||
|
// deployment manifest directly and reading the version.
|
||||||
|
Version? availableVersion = null;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
UpdateStatusBrush = SuccessBrush;
|
availableVersion = await Task.Run(() => FetchManifestVersion(manifestUri)).ConfigureAwait(true);
|
||||||
UpdateStatus = "אתה על הגרסה האחרונה (" + deployment.CurrentVersion + ").";
|
}
|
||||||
|
catch (Exception fetchEx)
|
||||||
|
{
|
||||||
|
_logger.Warning(fetchEx, "CheckForUpdate: manifest fetch failed");
|
||||||
|
UpdateStatusBrush = ErrorBrush;
|
||||||
|
UpdateStatus = "שגיאה בבדיקת השרת: " + fetchEx.Message;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateStatus = $"זמינה גרסה {info.AvailableVersion} — מוריד…";
|
if (availableVersion == null)
|
||||||
var result = await Task.Run(() => deployment.Update()).ConfigureAwait(true);
|
{
|
||||||
|
UpdateStatusBrush = ErrorBrush;
|
||||||
|
UpdateStatus = "לא ניתן לקרוא את גרסת השרת מ-" + manifestUri;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availableVersion <= currentVersion)
|
||||||
|
{
|
||||||
UpdateStatusBrush = SuccessBrush;
|
UpdateStatusBrush = SuccessBrush;
|
||||||
UpdateStatus = $"הותקנה גרסה {info.AvailableVersion}. סגור ופתח את Outlook כדי לטעון אותה.";
|
UpdateStatus = "אתה על הגרסה האחרונה (" + currentVersion + ").";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// VSTO add-ins cannot be updated programmatically from inside
|
||||||
|
// a running Outlook — ApplicationDeployment.Update() throws.
|
||||||
|
// Open the .vsto URL via the shell; Windows hands it to
|
||||||
|
// VSTOInstaller.exe which installs the update correctly.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(manifestUri.ToString())
|
||||||
|
{
|
||||||
|
UseShellExecute = true
|
||||||
|
});
|
||||||
|
UpdateStatusBrush = SuccessBrush;
|
||||||
|
UpdateStatus = $"זמינה גרסה {availableVersion} — אשר את ההתקנה בחלון שנפתח, ואז סגור ופתח את Outlook.";
|
||||||
|
}
|
||||||
|
catch (Exception launchEx)
|
||||||
|
{
|
||||||
|
_logger.Warning(launchEx, "CheckForUpdate: shell launch of installer URL failed");
|
||||||
|
UpdateStatusBrush = ErrorBrush;
|
||||||
|
UpdateStatus = $"זמינה גרסה {availableVersion} אבל לא הצלחנו לפתוח את חלון ההתקנה. גש ידנית ל-{manifestUri}";
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
catch (System.Deployment.Application.DeploymentDownloadException ex)
|
catch (System.Deployment.Application.DeploymentDownloadException ex)
|
||||||
{
|
{
|
||||||
@@ -215,6 +259,33 @@ namespace MarcusLaw.OutlookAddin.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the top-level <assemblyIdentity> version from the
|
||||||
|
/// .vsto deployment manifest at <paramref name="manifestUri"/>.
|
||||||
|
/// Returns null if the document doesn't look like a deployment
|
||||||
|
/// manifest. Runs on a worker thread (synchronous HTTP).
|
||||||
|
/// </summary>
|
||||||
|
private static Version? FetchManifestVersion(Uri manifestUri)
|
||||||
|
{
|
||||||
|
// The .vsto manifest is small (≈6KB). Keep this synchronous —
|
||||||
|
// no point pulling in HttpClient and its lifecycle just for one
|
||||||
|
// GET. WebRequest works fine on .NET FW 4.8 and through proxies.
|
||||||
|
var req = System.Net.WebRequest.Create(manifestUri);
|
||||||
|
req.Timeout = 10_000;
|
||||||
|
using (var response = req.GetResponse())
|
||||||
|
using (var stream = response.GetResponseStream())
|
||||||
|
{
|
||||||
|
var doc = System.Xml.Linq.XDocument.Load(stream);
|
||||||
|
System.Xml.Linq.XNamespace asmv1 = "urn:schemas-microsoft-com:asm.v1";
|
||||||
|
var identity = doc.Root?
|
||||||
|
.Elements()
|
||||||
|
.FirstOrDefault(e => e.Name.LocalName == "assemblyIdentity" && e.Name.Namespace == asmv1);
|
||||||
|
var versionAttr = identity?.Attribute("version")?.Value;
|
||||||
|
if (string.IsNullOrWhiteSpace(versionAttr)) return null;
|
||||||
|
return Version.TryParse(versionAttr, out var v) ? v : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool CanCheckForUpdate() => !IsCheckingForUpdate;
|
private bool CanCheckForUpdate() => !IsCheckingForUpdate;
|
||||||
|
|
||||||
partial void OnIsCheckingForUpdateChanged(bool value)
|
partial void OnIsCheckingForUpdateChanged(bool value)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<PublishUrl>C:\Users\Chaim\source\repos\OutlookAddin\Publish\</PublishUrl>
|
<PublishUrl>C:\Users\Chaim\source\repos\OutlookAddin\Publish\</PublishUrl>
|
||||||
<InstallUrl>https://gitea.dev.marcus-law.co.il/espocrm-extensions/OutlookAddin/raw/branch/main/Publish/</InstallUrl>
|
<InstallUrl>https://gitea.dev.marcus-law.co.il/espocrm-extensions/OutlookAddin/raw/branch/main/Publish/</InstallUrl>
|
||||||
<TargetCulture>en</TargetCulture>
|
<TargetCulture>en</TargetCulture>
|
||||||
<ApplicationVersion>1.2.2.0</ApplicationVersion>
|
<ApplicationVersion>1.2.3.0</ApplicationVersion>
|
||||||
<AutoIncrementApplicationRevision>false</AutoIncrementApplicationRevision>
|
<AutoIncrementApplicationRevision>false</AutoIncrementApplicationRevision>
|
||||||
<UpdateEnabled>true</UpdateEnabled>
|
<UpdateEnabled>true</UpdateEnabled>
|
||||||
<UpdateInterval>7</UpdateInterval>
|
<UpdateInterval>7</UpdateInterval>
|
||||||
|
|||||||
@@ -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.2.0")]
|
[assembly: AssemblyVersion("1.2.3.0")]
|
||||||
[assembly: AssemblyFileVersion("1.2.2.0")]
|
[assembly: AssemblyFileVersion("1.2.3.0")]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user