在我打磨我的小项目时,我试图将所有的常量字符串(如Keys、XpathExpressions等)存储在我的app.config文件中。当我运行已编译的exe文件时,这非常有效。但是在交互式Shell中不是这样。
我尝试将.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中也可以工作。 (但请注意,您需要重置会话以获取更改。)
C:\Program Files (x86)\Microsoft SDKs\F#\4.0\Framework\v4.0
下。 - Răzvan Flavius Panda你需要了解如何将app.config设置传递到动态程序集中。这可能会很麻烦,而且可能不值得。如果它作为已编译的二进制文件工作,我会测试那些依赖于配置设置的东西,而不是在FSI外部。System.NotSupportedException: The invoked member is not supported in a dynamic assembly. at System.Reflection.Emit.AssemblyBuilder.get_Location()
也许你可以通过使用ConfigurationManager上的OpenMappedExeConfiguration方法手动将FSI指向app.config文件。
另外,您可以尝试在单独的AppDomain中加载程序集-您可以使用AppDomainSetup类创建自己的AppDomain,并将任何文件作为配置文件提供给它。
事实仍然是,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);;