Нераспознанный атрибут ‘configProtectionProvider’ после шифрования app.config

#c# #asp.net #winforms

#c# #asp.net #winforms

Вопрос:

Я запускаю следующий метод в начале моего приложения, передавая раздел, находящийся в разделе ApplicationSettings:

 public static void EncryptConfigSection(string sectionKey)
    {
        Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        ConfigurationSection section = config.GetSection(sectionKey);
        if (section != null)
        {
            if (!section.SectionInformation.IsProtected)
            {
                if (!section.ElementInformation.IsLocked)
                {
                    section.SectionInformation.ProtectSection("RSAProtectedConfigurationProvider");
                    section.SectionInformation.ForceSave = true;
                    config.Save(ConfigurationSaveMode.Full);
                    ConfigurationManager.RefreshSection(sectionKey);
                }
            }
        }
    }
  

Вот пример раздела в app.config:

 <applicationSettings>
  <Example.Properties.Settings>
    <setting name="Key" serializeAs="String">
      <value>Value</value>
    </setting>
  </Example.Properties.Settings>
</applicationSettings>
  

Когда я пытаюсь получить доступ к любому из параметров из раздела, я получаю следующую ошибку:

Нераспознанный атрибут ‘configProtectionProvider’

Это настольное приложение, которому необходимо зашифровать некоторые настройки при запуске, а затем расшифровать при выходе.

У кого-нибудь есть решение этой проблемы?

Ответ №1:

Я нашел это: http://andybrennan.wordpress.com/2014/06/05/unrecognized-attribute-configprotectionprovider-after-encrypting-app-config/. И это решает проблему.

Просто используйте этот метод, как написано в блоге:

 private void ResetConfigMechanism()
{
    typeof(ConfigurationManager)
        .GetField("s_initState", BindingFlags.NonPublic |
                                 BindingFlags.Static)
        .SetValue(null, 0);

    typeof(ConfigurationManager)
        .GetField("s_configSystem", BindingFlags.NonPublic |
                                    BindingFlags.Static)
        .SetValue(null, null);

    typeof(ConfigurationManager)
        .Assembly.GetTypes()
        .Where(x => x.FullName ==
                    "System.Configuration.ClientConfigPaths")
        .First()
        .GetField("s_current", BindingFlags.NonPublic |
                               BindingFlags.Static)
        .SetValue(null, null);
}
  

Вызовите его после сохранения / обновления конфигурации.

Комментарии:

1. Не большой поклонник вызова частных свойств и методов через отражение, однако это решение работает очень хорошо и было единственным, которое устранило мою проблему (сложная схема конфигурации с включаемыми файлами и файлом settings.settings в некоторых проектах). По этой причине дал ему преимущество. Я обязательно задокументировал использование в своем коде и отметил, что его следует повторно тестировать каждый раз, когда мы будем менять версию .NET Framework, чтобы убедиться, что он все еще работает, и проверить, реализовал ли Microsoft общедоступный способ сделать то же самое.

2. Я пытался заставить что-то работать из других ответов, но это единственное, что работает последовательно.

3. Я бы дал 10 звезд, если бы это было разрешено. Этот фрагмент кода спас мой день

4. спас мой день, спасибо, быстрое грязное исправление, я ненавижу это, но это работает.

Ответ №2:

Мне удалось заставить работать ответ Рика Шотта с одним важным предостережением — вы не можете использовать статическую версию ConfigurationManager.GetSection для извлечения раздела после обновления — вы должны использовать Configuration .Вместо этого получает раздел.

Полный код:

 Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSection section = config.GetSection("passwordSection") as ConfigurationSection;

if (!section.SectionInformation.IsProtected)
{
    // Encrypt the section.
    section.SectionInformation.ProtectSection("DPAPIProtection");
    section.SectionInformation.ForceSave = true;
    config.Save(ConfigurationSaveMode.Modified);

    // The passwords are now encrypted.
    // Refresh the *parent* of the section that your passwords are in.
    ConfigurationManager.RefreshSection("configuration");

    // Now use Configuration.GetManager to retrieve the new password section.
    // This doesn't throw the Configuration Exception :)
    ConfigurationSection section2 = config.GetSection("passwordSection") as ConfigurationSection;
}
  

Ответ №3:

Согласно этому сообщению в блоге, исправление заключается в вызове RefreshSection() родительского:

 RefreshSection("applicationSettings")
  

Нераспознанный атрибут configProtectionProvider

Комментарии:

1. Рик, к сожалению, это не сработало. Не уверен, почему. Я пробовал несколько разных способов. Единственное, что работает, — это если я зашифрую конфигурацию, а затем запущу приложение.

2. @GrandMasterT опоздал на 2 года, но мне удалось заставить ответ Рика работать — подробности см. В моем ответе 🙂 Кроме того, 1 Рику за то, что он направил меня в нужное место!

Ответ №4:

Я не смог зашифровать / расшифровать файл конфигурации во время работы приложения и продолжить чтение значений.

Хотя это не то, что я хотел, решение проблемы состояло в том, чтобы сначала зашифровать / расшифровать .config перед запуском приложения.

Вот еще один подход, который я не делал, но показался интересным: шифрование паролей в файле .NET app.config

Ответ №5:

Этот пост просто спас мой день и на всякий случай, если кому-то понадобится исправление в vb и 2017

     Private Sub ResetConfigMechanism()
        GetType(ConfigurationManager).GetField("s_initState", BindingFlags.NonPublic Or BindingFlags.Static).SetValue(Nothing, 0)
        GetType(ConfigurationManager).GetField("s_configSystem", BindingFlags.NonPublic Or BindingFlags.Static).SetValue(Nothing, Nothing)
        GetType(ConfigurationManager).Assembly.GetTypes().Where(Function(x) x.FullName = "System.Configuration.ClientConfigPaths").First().GetField("s_current", BindingFlags.NonPublic Or BindingFlags.Static).SetValue(Nothing, Nothing)
    End Sub