App.config и F # Interactive не работает
Как я полирую мой маленький проект, я пытаюсь сохранить все константные строки в моем файле app.config(Keys, XpathExpressions и т.д.). Когда я запускаю скомпилированный exe, это отлично работает. В Interactive Shell это не так.
Я попытался скопировать файл .config из каталога bin/Release в dvd/debug и obj/Release dirs, но Call to ConfigurationManager.AppSettings.Item("key")
всегда возвращает null.
Любые предложения по исправлению этого вопроса?
С наилучшими пожеланиями
Ответы
Ответ 1
F # Интерактивный может работать с исполняемыми файлами, которые полагаются на файлы app.config
.
Способ сделать это - иметь файл .fs
в вашем проекте, который загружает условное выражение .config
в COMPILED
так:
let GetMyConfig() =
let config =
#if COMPILED
ConfigurationManager.GetSection("MyConfig") :?> MyConfig
#else
let path = __SOURCE_DIRECTORY__ + "/app.config"
let fileMap = ConfigurationFileMap(path)
let config = ConfigurationManager.OpenMappedMachineConfiguration(fileMap)
config.GetSection("MyConfig") :?> MyConfig
#endif
тогда в файле script укажите исполняемый файл и #load
файл .fs
, чтобы:
#I "../Build/Path
#r "ConfiguredApp.exe"
#load "MyConfig.fs"
При выполнении этих трех строк вы увидите сообщение, похожее на следующее в окне FSI:
[Loading C:\Svn\trunk\Source\ConfiguredApp\MyConfig.fs]
Binding session to 'C:\Svn\Qar\trunk\Build\Path\ConfiguredApp.exe'...
Обратите внимание, что вы действительно ссылаетесь на app.config
, когда в FSI (а не на сгенерированный .exe.config
.)
Удачи...
Ответ 2
Пока FSI динамически генерирует код для вашего ввода, использование fsi.exe.config будет работать нормально.
Я создал этот файл:
<configuration>
<appSettings>
<add key="test" value="bar"/>
</appSettings>
</configuration>
И сохранил его как "fsi.exe.config" (программные файлы \fsharp-version\bin).
Затем запустился FSI:
> #r "System.configuration";;
--> Referenced 'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.configuration.dll'
> System.Configuration.ConfigurationManager.AppSettings.["test"];;
val it : string = "bar"
Он также работал в Visual Studio. (Но учтите, что вам понадобится reset сеанс для получения изменений.)
Ответ 3
Проблема заключается в том, что FSI - это другой exe, который работает за кулисами и делает некоторые сумасшедшие трюки с помощью компиляции на лету и генерации двоичных файлов. Проверьте, что сборка FSI думает, что работает. Вы можете быть удивлены тем, что найдете:)
Он выдает ошибку:
System.NotSupportedException: вызываемый элемент не поддерживается в динамическая сборка. в System.Reflection.Emit.AssemblyBuilder.get_Location()
Вам нужно посмотреть, как получить настройки app.config в динамических сборках. Это может быть болью и, возможно, не стоит того. Если он работает как скомпилированный двоичный файл, я бы тестировал те вещи, которые полагаются на настройки конфигурации вне FSI.
Удачи.
Ответ 4
Возможно, вы могли бы указать FSI в файл app.config вручную, используя метод OpenMappedExeConfiguration в ConfigurationManager.
Также вы можете попробовать загрузить свою сборку в отдельный AppDomain - вы можете предоставить любой файл в качестве файла конфигурации в AppDomain, который вы создаете, используя AppDomainSetup.
Остается фактом, что FSI не подходит для такого рода сценариев...
Ответ 5
Я думаю, что я предоставляю ниже лучшее из обоих миров из двух наиболее голосованных ответов выше (особенно для людей, пишущих скрипты fsx):
Учитывая этот файл app.config:
<configuration>
<appSettings>
<add key="foo" value="bar"/>
</appSettings>
</configuration>
Прочитайте foo
следующим образом:
let appConfigPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "app.config")
let fileMap = ExeConfigurationFileMap()
fileMap.ExeConfigFilename <- appConfigPath
let config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None)
let foo = config.AppSettings.Settings.["foo"].Value
Console.WriteLine(foo)