簡體   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