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)