トップ 履歴 一覧 カテゴリ ソース 検索 ヘルプ RSS ログイン

MSBuild/ConfigMerge

INDEX

MSBuild で、config をマージする

ConfigMerge

クラスライブラリ(DLL)で、設定などを行ったときに、app.config に設定され、内容が参照される。実際に実行時には、アプリケーション(EXE)の config が参照されるため、アセンブリ名の config ファイルに内容が入っている必要がある。

なので、ビルド時に、クラスライブラリの設定(ClassLibrary.dll.config)の内容を、アプリケーションの設定(Application.exe.config)の内容にマージするようにビルドタスクを設定する。

Visual Studio のGUIでは設定出来ないので、直接プロジェクトファイルを編集する。

  MSBuildTask

config ファイル、つまり、XMLファイルを読み込んでマージするタスク。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  <UsingTask TaskName="ConfigMerge" TaskFactory="CodeTaskFactory"  AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll" >
    <ParameterGroup>
      <!-- SauceConfig: マージする DLL の config ファイル -->
      <SauceConfig ParameterType="System.String" Required="true" />
      <!-- MergedConfig: マージされる EXE の config ファイル -->
      <MergedConfig ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <!-- app.config をマージする MSBuildTask -->
      <Reference Include="System" />
      <Reference Include="System.Xml" />
      <Using Namespace="System" />
      <Using Namespace="System.IO" />
      <Using Namespace="System.Xml" />
      <Code Type="Fragment" Language="cs"><![CDATA[
Log.LogMessage(MessageImportance.High, "SauceConfig=" + SauceConfig);
Log.LogMessage(MessageImportance.High, "MergedConfig=" + MergedConfig);
            if (File.Exists(SauceConfig) && File.Exists(MergedConfig))
            {
                XmlDocument sDoc = new XmlDocument();
                sDoc.Load(SauceConfig);
                XmlDocument mDoc = new XmlDocument();
                mDoc.Load(MergedConfig);
                _Success = MergeXmlElement(mDoc, sDoc);
                mDoc.Save(MergedConfig);
            }
            return _Success;
        }

        private bool MergeXmlElement(XmlNode mergeNode, XmlNode sauceNode)
        {
            bool _Success = true;
            if (mergeNode == null || sauceNode == null) return false;

            foreach (XmlNode scn in sauceNode.ChildNodes)
            {
                if (scn.NodeType != XmlNodeType.Element) continue; // 要素以外は無視

                bool needAdd = true; // 見つからないときは追加する
                foreach (XmlNode mcn in mergeNode.ChildNodes)
                {
                    if (mcn.NodeType != XmlNodeType.Element) continue; // 要素以外は無視
                    if (!string.Equals(mcn.Name, scn.Name)) continue; // 同じ要素以外はスキップ
                    if (string.Equals(scn.OuterXml, mcn.OuterXml)) return true; // 同じXMLの内容なら終わり

                    XmlNode sAttr = scn.Attributes["name"];
                    if (sAttr == null) sAttr = scn.Attributes["key"];
                    XmlNode mAttr = mcn.Attributes["name"];
                    if (mAttr == null) mAttr = mcn.Attributes["key"];

                    if (sAttr == null || mAttr == null)
                    {
                        // name/key 属性なし
                        if (mcn.HasChildNodes)
                        {
                            if (!MergeXmlElement(mcn, scn)) _Success = false;
                        }
                        else
                        {
                            mergeNode.ReplaceChild(mergeNode.OwnerDocument.ImportNode(scn, true), mcn);
                        }
                        needAdd = false;
                        break;
                    }
                    else if (!string.Equals(mAttr.Name, sAttr.Name))
                    {
                        // name/key 属性なし(属性名違い)
                    }
                    else if (!string.Equals(mAttr.Value, sAttr.Value))
                    {
                        // name/key 属性あり(属性値違い)
                    }
                    else
                    {
                        // name/key 属性あり(同じキー項目)
                        if (mcn.HasChildNodes)
                        {
                            if (!MergeXmlElement(mcn, scn)) _Success = false;
                        }
                        else
                        {
                            mergeNode.ReplaceChild(mergeNode.OwnerDocument.ImportNode(scn, true), mcn);
                        }
                        needAdd = false;
                        break;
                    }
                } /* foreach (XmlNode node in mergeNode.ChildNodes) */
                if (needAdd)
                {
                    mergeNode.AppendChild(mergeNode.OwnerDocument.ImportNode(scn, true));
                }
            } /* foreach (XmlNode node in sauceNode.ChildNodes) */
      ]]></Code>
    </Task>
  </UsingTask>

  Target

上記の MSBuildTask を呼び出して、config ファイルをマージするようにする。

1
2
3
4
  <Target Name="AfterBuild" Condition="exists('$(TargetDir)$(TargetName).config')">
    <!-- CommonLibrary is Reference DLL project. -->
    <ConfigMerge MergedConfig="$(TargetDir)$(TargetName).config" SauceConfig="$(SolutionDir)CommonLibrary\$(OutDir)CommonLibrary.dll.config" />
  </Target>

最終更新時間:2016年12月04日 16時04分57秒 指摘や意見などあればSandBoxのBBSへ。