繁体   English   中英

App.config 和 F# Interactive 不起作用

[英]App.config and F# Interactive not working

当我完善我的小宠物项目时,我试图将所有常量字符串存储在我的 app.config 文件(键、XpathExpressions 等)中。 当我运行编译的 exe 时,这很好用。 在交互式外壳中,情况并非如此。

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

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

最诚挚的问候

F# Interactive可以处理依赖于app.config文件的可执行文件。

这样做的方法是在您的项目中有一个.fs文件,该文件以COMPILED定义为条件加载您的.config

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 。)

祝你好运...

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

问题是 FSI 是一个在幕后运行的不同 exe,它在动态编译和生成二进制文件方面做了一些疯狂的技巧。 检查FSI 认为哪个程序集正在运行 你可能会对你的发现感到惊讶:)

它会抛出一个错误:

System.NotSupportedException: 动态程序集中不支持调用的成员。 在 System.Reflection.Emit.AssemblyBuilder.get_Location()

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

祝你好运。

我想我从上面两个投票最多的答案中提供了两全其美的答案(特别是对于编写 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)

设置 APP_CONFIG_FILE 可以完成“如果足够早”的工作。 它似乎无法在 .fsx 文件中尽早完成。 所以它需要重置,根据这篇文章: 在运行时更改默认 app.config

在 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);;

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

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

事实仍然是 FSI 不太适合这种情况......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM