Сообщений 1 Оценка 585 [+0/-1] Оценить |
Одна из клевых новых фишек .NET 2.0/VS 2005 – простое в использовании, расширяемое API для управления настройками приложений и их пользователей, т.е. данными, которые должны сохраняться при работе клиентского приложения. Информация на эту тему есть в MSDN и моих предыдущих сообщениях.
Несмотря на то, что новая фича достаточно прозрачна в использовании, мы часто получаем вопросы от пользователей, реализующих собственные сценарии ее использования - почему <это> работает так и как сделать, чтобы <то> работало немного по-другому.
Есть два основных типа параметров, которые используются приложениями:
Application scoped настройки предназначены для использования в первом сценарии, а User scoped – во втором. Этими соображениями также обусловлено и поведение SettingsProvider по-умолчанию – настройки приложения хранятся в файле app.exe.config рядом с исполняемым файлом, а настройки пользователя – в файле user.config в папке с данными этого пользователя. К app.exe.config файлам вообще может не быть доступа на запись во время работы приложения, например, если приложение установлено в c:\Program Files\ ..., куда имеют доступ на запись только привелигированные пользователи. Даже если такой доступ есть – обычно это не очень хорошая идея, изменять настройки, затрагивающие всех остальных пользователей приложения.
Как уже было упомянуто, SettingsProvider по-умолчанию для клиентских приложений (LocalFileSettingsProvider) сохраняет настройки приложения в конфигурационных файлах. В .NET 1.0 и 1.1 было два уровня файлов конфигурации - machine.config и app.exe.config (где ‘app.exe’ – имя файла приложения). В .NET 2.0 мы добавили еще два уровня для хранения настроек, специфичных для пользователя – в папке перемещаемого профиля пользователя и в папке с локальным профилем пользователя. Для XP это будет что-то типа 'c:\Documents and Settings\<username>\Application Data' и 'c:\Documents and Settings\<username>\Local Settings\Application Data' соответственно. Эти каталоги – рекомендованное (а для Windows Logo – требуемое) место для хранения пользовательской информации и большинство приложений (типа Outlook и Visual Studio) помещают пользовательские данные именно здесь.
Точный путь к файлу user.config будет типа такого:
<Profile Directory>\<Company Name>\<App Name>_<Evidence Type>_<Evidence Hash>\<Version>\user.config |
где:
Собственно имя файла всегда просто 'user.config'.
Для получения данного пути програмно используйте Configuration Management API (потребуется ссылка на System.Configuration.dll). Например, так можно получить путь к локальному user.config:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
Console.WriteLine("Local user config path: {0}", config.FilePath);
|
Алгоритм конструирования пути должен обеспечить некоторые строгие требования в плане защиты, изоляции и надежности. Хотя мы постарались сделать этот путь, насколько это возможно, легко воспринимаемым, используя дружественные, определяемые самим приложением строки, не возможно было оставить его совсем уж элементарным, не столкнувшись с коллизиями с другими приложениями, спуфингом и т.д.
LocalFileSettingsProvider не предусматривает способа для изменения пути к файлам настроек. Обратите внимание, что собственно провайдер и не определяет путь к файлу настроек в первом случае – это система конфигурации. Если вам нужно хранить настройки, по каким-то соображениям, в другом месте, рекомендованный путь состоит в написании своего SettingsProvider. Его довольно просто реализовать, примеры можно найти в .NET 2.0 SDK. Имейте однако ввиду, что вы можете столкнуться с упомянутыми выше проблемами изоляции.
Приведенный выше алгоритм составления пути не используется в случае Clickonce. Вместо этого, локальный файл user.config находится в каталоге с данными Clickonce (при этом часть <Version> в путь также включается). Перемещаемый user.config в случае Clickonce-приложений не применяется.
Для сериализации настроек ApplicationSettingsBase может использовать два основных механизма:
Обычно срабатывает один из этих механизмов, однако встречаются типы, для которых эти способы не работают. В этом случае у вас есть следующие варианты:
Система конфигурации является иерархической и имеет следующий порядок: машина (machine) -> приложение (application) -> перемещаемый пользователь (roaming user) -> локальный пользователь (local user). Когда вы запрашиваете configuration section на любом уровне, вы получаете слитое представление этой секции с данного уровня и всех уровней ниже (уровень machine – самый нижний, а local user – наивысший). Обработчик секции определяет, как производить слияние, и приоритет настройки, скажем настройка из local user config оказывается приоритетнее, чем из application config.
Таким образом, пользовательские настройки, используемые по-умолчанию, вы можете спутать со значениями из app.config. Когда настройки будут сохранены в user.config, новые значения заменят параметры по-умолчанию. Обратите внимание, что значения по умолчанию могут также быть определены посредством DefaultSettingValueAttribute. Провайдер будет использовать эти значения, если никакие другие значения не определены ни на одном уровне конфигурации.
Есть несколько причин, по которым путь к user.config сделан чуствительным к номеру версии:
Однако мы обеспечили возможность простого переноса настроек предыдущей версии приложения. Просто вызовите ApplicationSettingsBase.Upgrade() и настройки предыдущей версии, которые соответствуют текущей версии класса настроек, будут сохранены в текущей версии user.config. Существует также возможность перегрузки этой функциональности в вашем классе настроек либо в реализации вашего провайдера.
Хороший вопрос. В Clickonce, когда инсталлируется новая версия приложения, ApplicationSettingsBase обнаруживает это и автоматически обновляет настройки. Если Clickonce не используется, вы должны вызвать Upgrade() самостоятельно. Вот один из вариантов, как можно определить, когда нужно вызвать Upgrade():
Заведите в параметрах настройки логическую переменную CallUpgrade и установите для неё значение по-умолчанию в true. При запуске приложения сделайте что-то типа этого:
if (Properties.Settings.Value.CallUpgrade) { Properties.Settings.Value.Upgrade(); Properties.Settings.Value.CallUpgrade = false; } |
Такой вариант гарантирует, что Upgrade() будет вызвана только при первом запуске новой версии.
Да, такой способ есть. Например, класс настроек, генерируемый дизайнером VS2005 помечен как internal класс сборки, в которой он определен. Что если необходимо обратиться к некоторым настройкам из другой сборки, скажем из dll, загруженной вашим приложением? Settings API обеспечивает полезный механизм для этого через SettingsGroupNameAttribute. Обычно провайдер настроек использует полное имя вашего класса настроек, как ключ, чтобы изолировать ваши параметры настроек от тех, что используются в других классах. Атрибут SettingsGroupNameAttribute позволяет обращаться к настройкам используя различные ключи или “имена групп”. Так, для доступа к настройкам из класса настроек приложения, все dll должны определить свой собственный класс настроек со свойствами, соответствующими классу настроек приложения, и применить SettingsGroupNameAttribute, назначая имя другого класса как имя группы. Маленькое предупреждение: если вы хотите использовать это в VS, удостоверьтесь, что вы применяете этот атрибут к пользовательской, а не к дизайнерской части partial-класса, т.к. иначе все изменения будут перезаписаны settings-дизайнером.
Это не является брешью в защите по двум причинам:
Нисколько. Проделанная нами работа гарантирует, что вы можете безопасно обратиться к вашим настройкам в режиме с частичным доверием. Фактически это будет выглядеть также как чтение и запись из вашего приложения. Единственное отличие – вы не сможете записать неограниченное количество данных, по понятным причинам. Число байт, которое вы можете записать через Settings API (LocalFileSettingsProvider) при частичном доверии ограничено административно при помощи класса IsolatedStoragePermission. Т.е. собственно также, как и для изолированных хранилищ (Isolated Storage) вообще.
Есть фундаментальное отличие между Settings API и Configuration API. Первое обеспечивает объектную модель для управления параметрами приложения. Эта модель использует схему сохранения посредством провайдеров, так что собственно сохранение здесь совершенно абстрактное. То, где хранятся настройки, вопрос реализации провайдера – он может хранить их в raw-файлах, SQL сервере, реестре или вызывать удаленый web-сервис. Провайдер, поставляемый по-умолчанию использует config-файлы, т.к. это самое очевидное хранилище для настроек клиентских приложений. Таким образом, Configuration API – это API более низкого уровня, позволяющее обновлять конфигурационные секции в config-файлах. В некотором смысле Settings API сидит на вершине Configuration API.
Так что если вам нужно работать с настройками приложения и пользовательскими предпочтениями, вам нужно Settings API. Если же вам необходимо реализовать конфигурационные разделы или обращаться к разделам конфигурации напрямую – используйте Configuration API.
Собственно Settings API не имеет никаких ограничений – можно использовать его в любых видах приложений – клиентстких, web, VSTO (Visual Studio Tools for Office Developer), консольных, WPF (Windows Presentation Foundation) и т.д. Провайдер по-умолчанию, LocalFileSettingsProvider, использует config-файлы для хранения настроек, что накладывает определенные ограничения. Например, ASP.NET приложения не имеют user.config файлов, так что вы не сможете сохранять пользовательские настройки используя этот провайдер. Конечно, вы можете использовать Profiles ASP.NET 2.0 для хранения пользовательских настроек. User.config файлы также не поддерживаются для VSTO-приложений (т.е. везде, где основным является native-приложение, например Outlook, Word или IE). В этом случае вы должны будете написать ваш собственный settings-провайдер (что впрочем весьма просто, и существуют хорошие примеры и документация в MSDN на эту тему) для чтения/записи пользовательских настроек. Для основных же типов managed клиентских приложений – консольных, Windows Forms и WPF, LocalFileSettingsProvider полностью поддерживается.
Сообщений 1 Оценка 585 [+0/-1] Оценить |