.NET 將 .config 檔案嵌入到程式集
.NET 將 .config 檔案嵌入到程式集
最近,團隊中的一位同事實現了一個小程式,供主程式呼叫。為了小程式分發的方便性,使用了 Costura.Fody
將其依賴的 dll
都嵌入到了 exe
中。但是,其中的 log4net.dll
又需要一個 *.config
檔案才能正常工作,而 Costura.Fody
又不支援此類檔案的嵌入。
我們先來複現一下問題場景,關於 Costura.Fody
和 log4net
的使用可以參考:
首先,在一個 C#
控制檯程式中通過 NuGet
log4net
和 Costura.Fody
兩個元件,然後在程式的 App.config
檔案中新增如下配置:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net >
<root>
<level value="WARN" />
<appender-ref ref="LogFileAppender" />
</root>
<logger name="mylogger">
<level value="ALL"/>
</logger>
<appender name="LogFileAppender" type="log4net.Appender.FileAppender" >
<param name="File" value="log-file.txt" />
<param name="AppendToFile" value="true" />
<layout type="log4net.Layout.PatternLayout"/>
</appender>
</log4net>
</configuration>
這些配置用於指定 log4net
如何工作,需要在程式的入口處載入這些配置資訊:
static void Main(string[] args)
{
// 從預設的配置檔案(App.config)中讀取配置資訊
log4net.Config.XmlConfigurator.Configure();
var logger = LogManager.GetLogger("mylogger");
logger.Info("Starting...");
Console.ReadLine();
}
然後,為 Costura.Fody
新增一個 FodyWeavers.xml
檔案,檔案內容如下:
<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
<Costura/>
</Weavers>
最後,編譯此專案。你會發現 log4net.dll
並未出現在生成目錄中,而是被合併到了 MyConsoleApp.exe
中。同時,生成目錄中還有一個 MyConsoleApp.exe.config
檔案(App.config
)生成的。如果刪除該檔案,MyConsoleApp.exe
中的 log4net
不能正常工作。
因此,如果要實現 MyConsoleApp.exe
單檔案分發,就要將 App.config
嵌入到該 exe
中,並且 log4net
要能識別嵌入的檔案。
Embedded Resource
好在 Visual Studio
支援將專案中的某個檔案的 Build Action
設定為 Embedded Resource(嵌入資源)
,這樣一來,檔案將作為資源被嵌入到程式集中。
並且,可以在執行時通過 Assembly.GetManifestResourceStream()
方法取檔案內容:
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "MyCompany.MyProduct.MyFile.txt";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
using (StreamReader reader = new StreamReader(stream))
{
string result = reader.ReadToEnd();
}
這只是其中一種將檔案作為資源嵌入到程式集的方法,欲瞭解更多方法,可參考 Various Build Actions in Visual Studio 。
Configure(Stream configStream)
查資料發現,log4net
支援從 Stream
中載入配置檔案:
log4net.Config.XmlConfigurator.Configure(Stream configStream);
那麼,結合 Embedded Resource
,問題就非常簡單了:
static void Main(string[] args)
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = "MyConsoleApp.App.config";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
// 從 Stream 中讀取 log4net 的配置資訊
log4net.Config.XmlConfigurator.Configure(stream);
}
var logger = LogManager.GetLogger("mylogger");
logger.Info("Starting...");
Console.ReadLine();
}
再次編譯專案,MyConsoleApp.exe.config
也從生成目錄中消失了,單獨的一個 MyConsoleApp.exe
也能正常運行了。
總結
本文只是以 *.config
檔案為例來說明如何將檔案作為資源嵌入到程式集中,其它格式的檔案也是支援的,並且還有其它的嵌入方式,感興趣的可以通過 Build Action
去探索更多的方法。