1. 程式人生 > >.NET 將 .config 文件嵌入到程序集

.NET 將 .config 文件嵌入到程序集

cal hat oid stroke resources 識別 pre size clas

原文:.NET 將 .config 文件嵌入到程序集

版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/Iron_Ye/article/details/83979628

.NET 將 .config 文件嵌入到程序集

最近,團隊中的一位同事實現了一個小程序,供主程序調用。為了小程序分發的方便性,使用了 Costura.Fody

將其依賴的 dll 都嵌入到了 exe 中。但是,其中的 log4net.dll 又需要一個 *.config 文件才能正常工作,而 Costura.Fody 又不支持此類文件的嵌入。

我們先來復現一下問題場景,關於 Costura.Fodylog4net 的使用可以參考:

  • .NET 合並程序集(將 dll 合並到 exe 中)
  • log4net 詳解

首先,在一個 C# 控制臺程序中通過 NuGet 引用 log4netCostura.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 去探索更多的方法。

參考資料

  • How to read embedded resource text file
  • Various Build Actions in Visual Studio
  • What are the various Build Action settings in Visual Studio …

.NET 將 .config 文件嵌入到程序集