导致 Clickonce 安装失败的文件关联
File association causing Clickonce install to fail
我有一个使用 ClickOnce 部署的 WPF 应用程序。它有一个自定义文件关联集,如果打开该文件类型,它可以打开并在应用程序中打开。这一直很好用,然后在更新期间用户突然开始收到“应用程序无法启动”错误。
查看错误详细信息我可以看到:
ERROR DETAILS
Following errors were detected during this operation.
* [12/8/2020 3:34:54 PM] System.UnauthorizedAccessException
- Attempted to perform an unauthorized operation.
- Source: mscorlib
- Stack trace:
at Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str)
at Microsoft.Win32.RegistryKey.SetValue(String name, Object value, RegistryValueKind valueKind)
at System.Deployment.Application.ShellExposure.AddFileAssociation(FileAssociation fileAssociation, DefinitionIdentity subId, Uri deploymentProviderUri)
at System.Deployment.Application.ShellExposure.AddShellExtensions(DefinitionIdentity subId, Uri deploymentProviderUri, AssemblyManifest appManifest)
at System.Deployment.Application.ShellExposure.UpdateShellExtensions(SubscriptionState subState, ShellExposureInformation& shellExposureInformation)
at System.Deployment.Application.ShellExposure.UpdateSubscriptionShellExposure(SubscriptionState subState)
at System.Deployment.Application.SubscriptionStore.CommitApplication(SubscriptionState& subState, CommitApplicationParams commitParams)
at System.Deployment.Application.ApplicationActivator.InstallApplication(SubscriptionState& subState, ActivationDescription actDesc)
at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivation(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl, Uri& deploymentUri)
at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivationWithRetry(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivationWithRetry(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
at System.Deployment.Application.ApplicationActivator.ActivateDeploymentWorker(Object state)
我确定这是文件关联,因为这是唯一通过 ClickOnce AFIK 触及注册表的东西。删除它后,问题就消失了,但现在该程序没有文件扩展名。我试过使用提升的权限安装,但这也没有解决问题。重新添加扩展程序导致问题 return。我们在此更新中没有触及任何底层文件关联或启动逻辑,那么到底是什么导致了这个问题?
有没有人遇到过使用 ClickOnce 和文件关联的情况?
编辑:使用 VS2017 的发布->选项创建关联(将信息放入 .csproj 文件)。
<ItemGroup>
<FileAssociation Include=".simsp">
<Visible>False</Visible>
<Description>My Description</Description>
<Progid>MyProgram.Proposal</Progid>
<DefaultIcon>Proposal.ico</DefaultIcon>
</FileAssociation>
</ItemGroup>
此外,卸载并删除与该应用程序相关的 AppData 文件后,该应用程序安装在一台机器上没问题,但在同一用户帐户下的另一台机器上却不行(我们使用文件同步来复制桌面)。这令人困惑,因为我不确定如果这是位于用户路径中的 AppData 文件中的问题,为什么安装会在注册表项期间失败。
编辑 3:问题似乎是随机发生的,但我们注意到它是在打开文件时发生的,导致 ClickOnce 应用程序打开并更新。到目前为止,对于使用文件同步、具有多个工作站的复制桌面的用户来说,这个问题似乎是孤立的。
解决此问题的最佳做法?这可能只是 ClickOnce 的限制。
- Attempted to perform an unauthorized operation.
这个错误告诉我们 - 操作被某些保护规则阻止,可以是:
- UAC
- 用户的计算机安全策略
- 用户的域安全策略
因此,您可以通过将 ClickOnce 清单设置为仅 UAC 来解决。
我创建了 ClickOnce 清单,它与应用程序至少有一个文件关联,并且工作正常。 UAC 要求用户执行安装或更新应用程序,并且一切正常。但是所有用户都没有任何文件同步到另一台计算机。如果他们需要我的应用程序 - 他们会在另一台计算机上安装它,然后根据需要进行更新。
在 .proj 文件中,我有两个 ClicOnce 清单生成的常规部分:
<ItemGroup>
<FileAssociation Include=".appex">
<Visible>False</Visible>
<Description>Exception info file</Description>
<Progid>My.AppClient</Progid>
<DefaultIcon>Images\Exception.ico</DefaultIcon>
</FileAssociation>
</ItemGroup>
和先决条件部分:
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.7">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.7 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.SqlServer.SQLSysClrTypes.12.0.x64">
<Visible>False</Visible>
<ProductName>System types Microsoft® CLR for SQL Server® 2014 %28x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
因此,让我们考虑一下来自您 'Edit 3' 的用户。当您与其他用户共享您的应用程序时使用 ClickOnce,但您的应用程序只为一个用户安装,而不是为计算机上的所有用户安装。为此,所有新安装或 ClickOnce 对应用程序的任何更新都会在 AppData 目录中创建新文件夹:
- 安装新版本的应用程序
- 将回滚操作保存到以前的版本
- 应用程序只能 运行 那个安装它的用户。所以,文件绑定也只针对这个用户(因为应用程序文件到用户配置文件文件夹)
此外,还有创建注册表设置以从新位置打开您的应用程序。这种组合(注册表设置和带有文件的应用程序文件夹)不适用于拥有大量工作站并在工作站之间同步数据的用户。或者您需要正确同步注册表与应用程序文件夹(所有这些)。
但是!在您的应用程序清单中可能包含先决条件(如我在此处所示)和外部包,或者您可以将其添加到您的应用程序的新版本中。当用户在一台计算机上更新或安装您的应用程序,而不是 运行 在另一台没有此外部链接的计算机上更新应用程序(已正确同步)时,您认为会发生什么情况?应用程序将崩溃。
因此,在我看来,您的解决方案将是:
使用WIX项目创建包,可以为一台计算机上的所有用户安装。并尽量不要将文件存储在用户配置文件文件夹中,如果没有正确复制到新计算机,可能会破坏应用程序。或者,如果未正确复制,则由您的应用重写。您可以在启动时检查任何更新,或注册更新服务,以在后台安装新版本的应用程序。
将 ClickOnce 与同步配置文件规则结合使用,以不通过策略复制应用程序文件。用户一旦在计算机上安装了您的应用程序,用户注销后配置文件不会被删除。您的应用程序的文件不得同步。并且您尝试在应用程序启动时使用 evaluated privilegies 注册文件扩展名。在另一台计算机上,用户 运行 全新安装,如果他们需要您的应用程序,或更新(如果已安装)。根据我的经验,我将所有应用程序设置存储在数据库中。在我的应用程序连接到的数据库服务器名称和数据库名称的用户注册表设置中。
在应用程序启动时,您可以 运行 来自另一个用户 like this 的代码。但是,ClickOnce 为当前用户安装,此解决方案将无法正常工作。
查看 Stacktrace,我在顶部看到了注册表命名空间。因此,除了 Maxim 的回答之外,我会说它发生在 clickonce 尝试设置注册表项的值时。您还可以在 regdit 中设置权限。右键单击一个键,select 权限,并确保为用户 运行 应用程序设置读写。
由于您已经找出所涉及的注册表项,您可能有很好的机会通过向用户授予对这些项的写入权限来解决它。
我有一个使用 ClickOnce 部署的 WPF 应用程序。它有一个自定义文件关联集,如果打开该文件类型,它可以打开并在应用程序中打开。这一直很好用,然后在更新期间用户突然开始收到“应用程序无法启动”错误。
查看错误详细信息我可以看到:
ERROR DETAILS
Following errors were detected during this operation.
* [12/8/2020 3:34:54 PM] System.UnauthorizedAccessException
- Attempted to perform an unauthorized operation.
- Source: mscorlib
- Stack trace:
at Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str)
at Microsoft.Win32.RegistryKey.SetValue(String name, Object value, RegistryValueKind valueKind)
at System.Deployment.Application.ShellExposure.AddFileAssociation(FileAssociation fileAssociation, DefinitionIdentity subId, Uri deploymentProviderUri)
at System.Deployment.Application.ShellExposure.AddShellExtensions(DefinitionIdentity subId, Uri deploymentProviderUri, AssemblyManifest appManifest)
at System.Deployment.Application.ShellExposure.UpdateShellExtensions(SubscriptionState subState, ShellExposureInformation& shellExposureInformation)
at System.Deployment.Application.ShellExposure.UpdateSubscriptionShellExposure(SubscriptionState subState)
at System.Deployment.Application.SubscriptionStore.CommitApplication(SubscriptionState& subState, CommitApplicationParams commitParams)
at System.Deployment.Application.ApplicationActivator.InstallApplication(SubscriptionState& subState, ActivationDescription actDesc)
at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivation(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl, Uri& deploymentUri)
at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivationWithRetry(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Deployment.Application.ApplicationActivator.PerformDeploymentActivationWithRetry(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl)
at System.Deployment.Application.ApplicationActivator.ActivateDeploymentWorker(Object state)
我确定这是文件关联,因为这是唯一通过 ClickOnce AFIK 触及注册表的东西。删除它后,问题就消失了,但现在该程序没有文件扩展名。我试过使用提升的权限安装,但这也没有解决问题。重新添加扩展程序导致问题 return。我们在此更新中没有触及任何底层文件关联或启动逻辑,那么到底是什么导致了这个问题?
有没有人遇到过使用 ClickOnce 和文件关联的情况?
编辑:使用 VS2017 的发布->选项创建关联(将信息放入 .csproj 文件)。
<ItemGroup>
<FileAssociation Include=".simsp">
<Visible>False</Visible>
<Description>My Description</Description>
<Progid>MyProgram.Proposal</Progid>
<DefaultIcon>Proposal.ico</DefaultIcon>
</FileAssociation>
</ItemGroup>
此外,卸载并删除与该应用程序相关的 AppData 文件后,该应用程序安装在一台机器上没问题,但在同一用户帐户下的另一台机器上却不行(我们使用文件同步来复制桌面)。这令人困惑,因为我不确定如果这是位于用户路径中的 AppData 文件中的问题,为什么安装会在注册表项期间失败。
编辑 3:问题似乎是随机发生的,但我们注意到它是在打开文件时发生的,导致 ClickOnce 应用程序打开并更新。到目前为止,对于使用文件同步、具有多个工作站的复制桌面的用户来说,这个问题似乎是孤立的。
解决此问题的最佳做法?这可能只是 ClickOnce 的限制。
- Attempted to perform an unauthorized operation.
这个错误告诉我们 - 操作被某些保护规则阻止,可以是:
- UAC
- 用户的计算机安全策略
- 用户的域安全策略
因此,您可以通过将 ClickOnce 清单设置为仅 UAC 来解决。 我创建了 ClickOnce 清单,它与应用程序至少有一个文件关联,并且工作正常。 UAC 要求用户执行安装或更新应用程序,并且一切正常。但是所有用户都没有任何文件同步到另一台计算机。如果他们需要我的应用程序 - 他们会在另一台计算机上安装它,然后根据需要进行更新。
在 .proj 文件中,我有两个 ClicOnce 清单生成的常规部分:
<ItemGroup>
<FileAssociation Include=".appex">
<Visible>False</Visible>
<Description>Exception info file</Description>
<Progid>My.AppClient</Progid>
<DefaultIcon>Images\Exception.ico</DefaultIcon>
</FileAssociation>
</ItemGroup>
和先决条件部分:
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.7">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.7 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.SqlServer.SQLSysClrTypes.12.0.x64">
<Visible>False</Visible>
<ProductName>System types Microsoft® CLR for SQL Server® 2014 %28x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
因此,让我们考虑一下来自您 'Edit 3' 的用户。当您与其他用户共享您的应用程序时使用 ClickOnce,但您的应用程序只为一个用户安装,而不是为计算机上的所有用户安装。为此,所有新安装或 ClickOnce 对应用程序的任何更新都会在 AppData 目录中创建新文件夹:
- 安装新版本的应用程序
- 将回滚操作保存到以前的版本
- 应用程序只能 运行 那个安装它的用户。所以,文件绑定也只针对这个用户(因为应用程序文件到用户配置文件文件夹)
此外,还有创建注册表设置以从新位置打开您的应用程序。这种组合(注册表设置和带有文件的应用程序文件夹)不适用于拥有大量工作站并在工作站之间同步数据的用户。或者您需要正确同步注册表与应用程序文件夹(所有这些)。
但是!在您的应用程序清单中可能包含先决条件(如我在此处所示)和外部包,或者您可以将其添加到您的应用程序的新版本中。当用户在一台计算机上更新或安装您的应用程序,而不是 运行 在另一台没有此外部链接的计算机上更新应用程序(已正确同步)时,您认为会发生什么情况?应用程序将崩溃。
因此,在我看来,您的解决方案将是:
使用WIX项目创建包,可以为一台计算机上的所有用户安装。并尽量不要将文件存储在用户配置文件文件夹中,如果没有正确复制到新计算机,可能会破坏应用程序。或者,如果未正确复制,则由您的应用重写。您可以在启动时检查任何更新,或注册更新服务,以在后台安装新版本的应用程序。
将 ClickOnce 与同步配置文件规则结合使用,以不通过策略复制应用程序文件。用户一旦在计算机上安装了您的应用程序,用户注销后配置文件不会被删除。您的应用程序的文件不得同步。并且您尝试在应用程序启动时使用 evaluated privilegies 注册文件扩展名。在另一台计算机上,用户 运行 全新安装,如果他们需要您的应用程序,或更新(如果已安装)。根据我的经验,我将所有应用程序设置存储在数据库中。在我的应用程序连接到的数据库服务器名称和数据库名称的用户注册表设置中。
在应用程序启动时,您可以 运行 来自另一个用户 like this 的代码。但是,ClickOnce 为当前用户安装,此解决方案将无法正常工作。
查看 Stacktrace,我在顶部看到了注册表命名空间。因此,除了 Maxim 的回答之外,我会说它发生在 clickonce 尝试设置注册表项的值时。您还可以在 regdit 中设置权限。右键单击一个键,select 权限,并确保为用户 运行 应用程序设置读写。
由于您已经找出所涉及的注册表项,您可能有很好的机会通过向用户授予对这些项的写入权限来解决它。