如何解决需要完全控制/ OwnerRights的LocalFileSettingsProvider

rea*_*idt 5 .net c# settings fileshare roaming-profile

在我的.NET客户端应用程序中,我使用Scope = User和Roaming = True的默认设置提供程序.这在大多数环境中都可以正常工作,无论客户端还是终端服务器,除了具有Citrix终端服务器场的客户.每当Properties. Settings.Default.Save()调用时,抛出以下异常:

System.UnauthorizedAccessException: Attempted to perform an unauthorized operation.
   at System.Security.AccessControl.Win32.SetSecurityInfo(ResourceType type, String name, SafeHandle handle, SecurityInfos securityInformation, SecurityIdentifier owner, SecurityIdentifier group, GenericAcl sacl, GenericAcl dacl)
   at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, SafeHandle handle, AccessControlSections includeSections, Object exceptionContext)
   at System.Security.AccessControl.NativeObjectSecurity.Persist(String name, AccessControlSections includeSections, Object exceptionContext)
   at System.Security.AccessControl.FileSystemSecurity.Persist(String fullPath)
   at System.Configuration.Internal.WriteFileContext.DuplicateTemplateAttributes (String source, String destination)
   at System.Configuration.Internal.WriteFileContext.DuplicateFileAttributes(String source, String destination)
   at System.Configuration.Internal.WriteFileContext.Complete(String filename, Boolean success)
   at System.Configuration.Internal.InternalConfigHost.StaticWriteCompleted(String streamName, Boolean success, Object writeContext, Boolean assertPermissions)
   at System.Configuration.Internal.DelegatingConfigHost.WriteCompleted(String streamName, Boolean success, Object writeContext, Boolean assertPermissions)
   at System.Configuration.ClientSettingsStore.ClientSettingsConfigurationHost.WriteCompleted(String streamName, Boolean success, Object writeContext)
   at System.Configuration.UpdateConfigHost.WriteCompleted(String streamName, Boolean success, Object writeContext)
   at System.Configuration.MgmtConfigurationRecord.SaveAs(String filename, ConfigurationSaveMode saveMode, Boolean forceUpdateAll)
   at System.Configuration.ClientSettingsStore.WriteSettings(String sectionName, Boolean isRoaming, IDictionary newSettings)
   at System.Configuration.LocalFileSettingsProvider.SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection values)
   at System.Configuration.SettingsBase.SaveCore()
   at System.Configuration.SettingsBase.Save()
Run Code Online (Sandbox Code Playgroud)

这个例外的原因:

  • System.Configuration.Internal.WriteFileContext...newcfg在用户的漫游配置文件中写入用户设置的新副本().然后,DuplicateTemplateAttributes尝试修改此文件的ACL并将所有权显式设置为当前用户.
  • 对于此客户,此操作失败,因为漫游配置文件存储在文件共享中,并且用户仅具有" 读取"和" 更改"权限,但不具有" 完全控制"权限.它们可能在NTFS中具有完全控制权(因为默认情况下,您是所有文件的"所有者",并且作为所有者,无论您是否明确设置了"完全控制",您都可以对文件执行任何操作),但似乎喜欢它在SMB共享级别上被阻止.

这种行为对我没有任何意义:鉴于LocalFileSystemProvider 总是使用当前用户的私有配置文件夹(本地或漫游),我们可以安全地假设用户仍然是所有者.

由于WriteFileContext捕获异常,删除临时.newcfg文件,然后重新抛出,没有办法简单地捕获我的代码中的异常并重命名该文件或以某种方式获取其内容,因为它在抛出异常时已被删除.

除了实现我自己的设置提供程序之外,我找不到任何解决此问题的简单方法.为此,似乎我甚至不得不重建序列化部分之类的东西,因为用于此的所有System.Configuration内容都是内部的.当然,我不想打破当前使用的设置,所以它看起来像一个荒谬的代码量只是重建一切,因为它只是"一行注释掉"(设置文件的所有者).

任何想法我还能尝试什么?

客户无法更改其文件共享权限中的任何内容......

toa*_*akz 1

我在 Citrix 上遇到了类似的问题 - AppData 被重定向到“更改和读取”网络共享(不是“完全控制” - 它适用于“完全控制”)。首次运行时,我们的应用程序将在第一次 Save() 调用时创建 user.config,但在任何后续 Save() 调用时抛出 UnauthorizedAccessException。

答案似乎是在调用 Save() 之前删除 user.config 文件(如果存在)。

我们目前正在与客户进行测试 - 当我得到具体结果时我会更新我的答案。

更新:在调用 Save() 之前,您需要“触摸”Settings.Default 中的每个设置,因为临时文件实际上已与现有 user.config 合并。通过在调用 Save() 之前调用以下方法,每次都会正确地重新创建 user.config(不会抛出 UnauthorizedAccessException)。

public static void ClearUserConfigFile()
{
    //Touch each setting
    foreach (SettingsProperty property in Settings.Default.Properties)
    {
        if (property.DefaultValue != Settings.Default[property.Name])
            Settings.Default[property.Name] = Settings.Default[property.Name];
    }

    //Delete the user.config file
    var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);
    var userConfigPath = config.FilePath;
    try
    {
        if (File.Exists(userConfigPath) == true)
            File.Delete(userConfigPath);
    }
    catch (Exception ex)
    {
        _log.ErrorFormat("Exception thrown while deleting user.config : {0}", ex.ToString());
    }
}
Run Code Online (Sandbox Code Playgroud)