简体   繁体   English

App.config 和 F# Interactive 不起作用

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

As I'm polishing my little pet project, I'm trying to store all the constant strings in my app.config file (Keys, XpathExpressions etc).当我完善我的小宠物项目时,我试图将所有常量字符串存储在我的 app.config 文件(键、XpathExpressions 等)中。 When I run the compiled exe this works great.当我运行编译的 exe 时,这很好用。 In the Interactive Shell this isn't the case.在交互式外壳中,情况并非如此。

I tried to copy the .config file from my bin/Release directory to the obj/Debug & obj/Release dirs, but the Call to ConfigurationManager.AppSettings.Item("key") always returns null.我试图将 .config 文件从我的 bin/Release 目录复制到 obj/Debug & obj/Release 目录,但是对ConfigurationManager.AppSettings.Item("key")的调用总是返回 null。

Any suggestions how to fix this?任何建议如何解决这个问题?

With best regards最诚挚的问候

F# Interactive can work with executables that rely on app.config files. F# Interactive可以处理依赖于app.config文件的可执行文件。

The way to do this is to have an .fs file in your project that loads your .config conditional on the COMPILED define so:这样做的方法是在您的项目中有一个.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

then in your script file reference the executable and #load the .fs file so:然后在你的脚本文件引用的可执行文件和#load.fs文件,以便:

#I "../Build/Path

#r "ConfiguredApp.exe"

#load "MyConfig.fs"

On executing these three lines you will see a message similar to the following in the FSI window:执行这三行时,您将在 FSI 窗口中看到类似于以下内容的消息:

[Loading C:\\Svn\\trunk\\Source\\ConfiguredApp\\MyConfig.fs]

Binding session to 'C:\\Svn\\Qar\\trunk\\Build\\Path\\ConfiguredApp.exe'...

Notice that you're actually referencing the app.config when in FSI (rather than the generated .exe.config .)请注意,您实际上是在 FSI 中引用app.config (而不是生成的.exe.config 。)

Best of luck...祝你好运...

While FSI dynamically generates code for your input, using the fsi.exe.config will work just fine.虽然 FSI 会为您的输入动态生成代码,但使用 fsi.exe.config 就可以正常工作。

I created this file:我创建了这个文件:

<configuration>
    <appSettings>
        <add key="test" value="bar"/>
    </appSettings>
</configuration>

And saved it as "fsi.exe.config" (program files\\fsharp-version\\bin).并将其保存为“fsi.exe.config”(程序文件\\fsharp-version\\bin)。

Then started FSI:然后启动 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"

It also worked from Visual Studio.它也适用于 Visual Studio。 (But note that you'll need to reset the session to pickup changes.) (但请注意,您需要将会话重置为拾取更改。)

The problem is that FSI is a different exe running behind the scenes and does some crazy tricks with on-the-fly compilation and generation of binaries.问题是 FSI 是一个在幕后运行的不同 exe,它在动态编译和生成二进制文件方面做了一些疯狂的技巧。 Check to see which assembly FSI thinks is running .检查FSI 认为哪个程序集正在运行 You might be surprised what you find :)你可能会对你的发现感到惊讶:)

It will throw an error:它会抛出一个错误:

System.NotSupportedException: The invoked member is not supported in a dynamic assembly. System.NotSupportedException: 动态程序集中不支持调用的成员。 at System.Reflection.Emit.AssemblyBuilder.get_Location()在 System.Reflection.Emit.AssemblyBuilder.get_Location()

You need to look into how to get app.config settings into dynamic assemblies.您需要研究如何将 app.config 设置放入动态程序集。 This could be a pain, and might not be worth it.这可能会很痛苦,也可能不值得。 If it works as a compiled binary, I'd test those things that rely on config settings outside of FSI.如果它作为编译的二进制文件工作,我会测试那些依赖于 FSI 之外的配置设置的东西。

Good luck.祝你好运。

I think I provide below the best of both worlds from the two most voted answers above (especially for people writing fsx scripts):我想我从上面两个投票最多的答案中提供了两全其美的答案(特别是对于编写 fsx 脚本的人):

Given this app.config file:鉴于此 app.config 文件:

<configuration>
    <appSettings>
        <add key="foo" value="bar"/>
    </appSettings>
</configuration>

Read foo this way:以这种方式阅读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)

Setting APP_CONFIG_FILE does the job "if it's early enough".设置 APP_CONFIG_FILE 可以完成“如果足够早”的工作。 It doesn't appear to be able to do it early enough in the .fsx file.它似乎无法在 .fsx 文件中尽早完成。 So it needs a reset, as per this post: Change default app.config at runtime所以它需要重置,根据这篇文章: 在运行时更改默认 app.config

In F#, it looks like this:在 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);;

Maybe you could point FSI to the app.config file manually by using the OpenMappedExeConfiguration method on ConfigurationManager.也许您可以使用 ConfigurationManager 上的OpenMappedExeConfiguration 方法手动将 FSI 指向 app.config 文件。

Also you could try loading your assembly in a separate AppDomain - you can give any file as config file to an AppDomain you create yourself using the AppDomainSetup class.您也可以尝试在单独的 AppDomain 中加载程序集 - 您可以将任何文件作为配置文件提供给您使用AppDomainSetup类自己创建的AppDomain

Th fact remains that FSI isn't well suited to this kind of scenario...事实仍然是 FSI 不太适合这种情况......

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

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