App.config和F#Interactive无法正常工作

时间:2009-03-14 08:12:18

标签: .net f#

当我正在抛光我的小宠物项目时,我正在尝试将所有常量字符串存储在我的app.config文件中(Keys,XpathExpressions等)。当我运行编译的exe时,这很有效。在Interactive Shell中并非如此。

我尝试将.config文件从bin / Release目录复制到obj / Debug& obj / Release dirs,但对ConfigurationManager.AppSettings.Item("key")的调用始终返回null。

有任何建议如何解决这个问题?

最诚挚的问候

6 个答案:

答案 0 :(得分:13)

F#Interactive 可以使用依赖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

然后在您的脚本文件中引用可执行文件和#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'...

请注意,您实际上是在FSI时引用app.config(而不是生成的.exe.config。)

祝您好运......

答案 1 :(得分:12)

虽然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。 (但请注意,您需要将会话重置为拾取更改。)

答案 2 :(得分:1)

问题在于FSI是一个在幕后运行的不同的exe,并且通过即时编译和生成二进制文件做了一些疯狂的技巧。检查哪个assembly FSI thinks is running。您可能会对您所发现的内容感到惊讶:)

会抛出错误:

  

System.NotSupportedException:The   a不支持调用的成员   动态装配。在   System.Reflection.Emit.AssemblyBuilder.get_Location()

您需要了解如何将app.config设置转换为动态程序集。这可能是一种痛苦,可能不值得。如果它作为编译二进制文件工作,我会测试那些依赖于FSI之外的配置设置的东西。

祝你好运。

答案 3 :(得分:0)

也许您可以使用ConfigurationManager上的OpenMappedExeConfiguration method手动将FSI指向app.config文件。

您也可以尝试在单独的AppDomain中加载程序集 - 您可以将任何文件作为配置文件提供给您使用AppDomainSetup类自己创建的AppDomain。

事实上,FSI并不适合这种情况......

答案 4 :(得分:0)

我认为我从以上两个投票最多的答案中提供了两个世界中最好的(特别是对于编写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)

答案 5 :(得分:0)

设置APP_CONFIG_FILE会“如果足够早”执行该工作。它似乎无法在.fsx文件中及早进行。因此需要重置,如这篇文章所述: Change default app.config at runtime

在F#中,它看起来像这样:

open System
open System.Configuration
open System.IO
open System.Reflection

let appConfigPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "App.config")
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", appConfigPath)
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()
    |> Array.find (fun x -> x.FullName = "System.Configuration.ClientConfigPaths"))
    .GetField("s_current", BindingFlags.NonPublic ||| BindingFlags.Static).SetValue(null, null);;