Здравствуйте ... появилась необходимость развертывать приложение с помощью ClickOnce и вот на что я при этом натолкнулся... проверку проводил под свежеустановленной виндой, + NET FW 2.0 + MS Office 2003...
проверял следующим образом: — создал двух пользователей Admin (группа Администраторы) и user (группа Опытные пользователи).. развертывал приложение то под одним то под другим и смотрел что в итоге получится
так вот.. приложение работает с БД... строки подключения к БД хранятся в config файле в зашифрованном виде в секции connectionStrings... шифруются с помощью RsaProtectedConfigurationProvider, ключ по умолчанию... в случае удачного подключения строка подключения должна сохраняться в файл, но на этом этапе возникает странная ошибка
устанавливаю я например моя программу под Admin'ом... у него строки подключения сохраняются/загружаются.. теперь.. ставлю её под user... строки подключения не сохраняются... Save() конфиг секции вылетает с исключением... если же сначала установить программу под user'ом, а потом под Admin'ом.. то у user'a — все ок, у Admin'а не сохраняется..
в лог падает следующее исключение
2007-06-07 16:57:00,798 ERROR [ - Void Save()] Ошибка при сохранении настроек комплекса
System.Configuration.ConfigurationErrorsException: An error occurred executing the configuration section handler for connectionStrings. ---> System.Configuration.ConfigurationErrorsException: Failed to encrypt the section 'connectionStrings' using provider 'RsaProtectedConfigurationProvider'. Error message from the provider: Объект уже существует.
---> System.Security.Cryptography.CryptographicException: Объект уже существует.
at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
at System.Security.Cryptography.Utils._CreateCSP(CspParameters param, Boolean randomKeyContainer, SafeProvHandle& hProv)
at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
at System.Configuration.RsaProtectedConfigurationProvider.GetCryptoServiceProvider(Boolean exportable, Boolean keyMustExist)
at System.Configuration.RsaProtectedConfigurationProvider.Encrypt(XmlNode node)
at System.Configuration.ProtectedConfigurationSection.EncryptSection(String clearXml, ProtectedConfigurationProvider provider)
at System.Configuration.Internal.InternalConfigHost.System.Configuration.Internal.IInternalConfigHost.EncryptSection(String clearTextXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection)
at System.Configuration.Internal.DelegatingConfigHost.EncryptSection(String clearTextXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection)
at System.Configuration.Internal.DelegatingConfigHost.EncryptSection(String clearTextXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection)
at System.Configuration.MgmtConfigurationRecord.GetConfigDefinitionUpdates(Boolean requireUpdates, ConfigurationSaveMode saveMode, Boolean forceSaveAll, ConfigDefinitionUpdates& definitionUpdates, ArrayList& configSourceUpdates)
--- End of inner exception stack trace ---
at System.Configuration.MgmtConfigurationRecord.GetConfigDefinitionUpdates(Boolean requireUpdates, ConfigurationSaveMode saveMode, Boolean forceSaveAll, ConfigDefinitionUpdates& definitionUpdates, ArrayList& configSourceUpdates)
--- End of inner exception stack trace ---
at System.Configuration.MgmtConfigurationRecord.GetConfigDefinitionUpdates(Boolean requireUpdates, ConfigurationSaveMode saveMode, Boolean forceSaveAll, ConfigDefinitionUpdates& definitionUpdates, ArrayList& configSourceUpdates)
at System.Configuration.MgmtConfigurationRecord.SaveAs(String filename, ConfigurationSaveMode saveMode, Boolean forceUpdateAll)
at System.Configuration.Configuration.SaveAsImpl(String filename, ConfigurationSaveMode saveMode, Boolean forceSaveAll)
at System.Configuration.Configuration.Save()
at KS.Web.SmartBudget.Classes.ComplexConfiguration.SaveConfig()
Предполагаю что RsaProtectedConfigurationProvider пытается сгенерировать пару default ключей которая уже существует.. прошу подскажите как можно обойти данную ошибку
P.S. Спасибо всем кто осилил
Судя по этому логу.. проблема была в том что RsaProtectedConfigurationProvider по умолчанию использовал useMachineContainer="true" и пытался еще раз создать существующий ключ... все попытки создать пользовательского провайдера по примерам из MSDN и интернета ... приводили к сообщением System.Configuration not found или RsaProtectedConfigurationProvider.dll not found ...
проблему удалось решить следующим образом:
<configProtectedData defaultProvider="MyProtectionProvider">
<providers>
<add name="MyProtectionProvider" type="System.Configuration.RsaProtectedConfigurationProvider"
keyContainerName="SampleKeys"
useMachineContainer="false"/>
</providers>
Здесь почему то он все сразу нашел и заработал
P.S. как выяснислось ClickOnce тут не при чем
Здравствуйте, KlimEV, Вы писали:
KEV>Здравствуйте, cm9x4, Вы писали:
C>>Судя по этому логу.. проблема была в том что RsaProtectedConfigurationProvider по умолчанию использовал useMachineContainer="true" и пытался еще раз создать существующий ключ... все попытки создать пользовательского провайдера по примерам из MSDN и интернета ... приводили к сообщением System.Configuration not found или RsaProtectedConfigurationProvider.dll not found ...
KEV>Аналогично пробовал шифрование RSA применительно к файлу config при распространении ClickOnce. Как автор решил проблему с тем, что файл после инсталляции лежит незашифрованный?
KEV>Я так и не нашел как шифровать файл на машине при инсталляции. Т.к. после установки, но до запуска приложения файл config лежит незашифрованный. Распространять зашифрованный файл нельзя, т.к. ключи существуют на машине разработчика, но на машине пользователя их нет. Использую сейчас распространение через msi-файл, перхватывая событие Custom Actions Install, в котором созданная мной dll шифрует файл config. Получается, шифрование происходит в момент установки. Но как можно отследить, что приложение установилось через технологию ClickOnce, чтобы именно в этот момент вызвать шифрование файла?
совю проблему поначалу решил созданием собственного крпитопровайдера... а потом все же решил прописанием
<configProtectedData defaultProvider="MyProtectionProvider">
<providers>
<add name="MyProtectionProvider" type="System.Configuration.RsaProtectedConfigurationProvider"
keyContainerName="MyKeys"
useMachineContainer="false"/>
</providers>
</configProtectedData>
хотя до этого эти же строки не желалил работать... полный rebuild сделали наверное
ну а проблемы шифрования конфиг файла не стояла, важно было зашифровать Секцию connectionStrings ... что в общем-то и удалось