11

Winforms プロジェクトで構成の変更を適用するために、この質問に対する解決策を使用しています。App.configインストール可能な *.msi ファイルを作成するプロジェクトのインストーラー プロジェクトもあります。問題は、インストーラーにバンドルされている構成ファイルが元の変換されていない構成ファイルであることです。そのため、ビルドされた winforms プロジェクトの構成ファイルにすべての正しい変換が適用されていても、運用インストーラーで運用接続文字列を取得していません。

インストーラー プロジェクトにプロジェクト ビルドの出力を強制的に使用させる方法はありますか?

4

7 に答える 7

10

まず、オプションapp.configを使用して Setup Project が別のファイルを指すようにすることはできません。Primary outputしたがって、私の解決策は回避策になります。あなたの状況に役立つことを願っています。

概要:

基本的な考え方は次のとおりです。

  • app.configセットアップ プロジェクトから強制を削除します。
  • を指すファイルをapp.config手動で追加します。
  • MSBuild を使用してvdprojファイルにアクセスし、変換された app.config の実際の出力と一致するように変更します。

いくつかの欠点は次のとおりです。

  • セットアップ プロジェクトは、展開するプロジェクトがビルドされた場合にのみ更新されます。ああ...本当の欠点ではありません!
  • MSBuild 4.0 が必要です...これも回避できます。
  • FileUpdateと呼ばれるカスタム タスクが必要です。これはオープン ソースであり、インストーラーがあります。

働こう:

1) セットアップ プロジェクトに移動し、プライマリ出力オブジェクトを選択し、右クリックして [プロパティ] に移動します。そこにExclude Filter... add a filter for*.configがあり、ハードコーディングされた app.config が削除されます。

2) ソリューション エクスプローラーでセットアップ プロジェクトを右クリック -> [追加] -> [ファイル...] で終わる任意のファイルを選択します.config

3) MSBuild Community Tasks Projectをダウンロードします。msi インストーラーをお勧めします。

4) プロジェクト (csproj) をアンロードし、他の質問のコードを次のコードに置き換えます。

コード:

  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
  <Target Name="AfterCompile" Condition="exists('app.$(Configuration).config')">
    <!-- Generate transformed app config in the intermediate directory -->
    <TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
    <!-- Force build process to use the transformed configuration file from now on. -->
    <ItemGroup>
      <AppConfigWithTargetPath Remove="app.config" />
      <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
        <TargetPath>$(TargetFileName).config</TargetPath>
      </AppConfigWithTargetPath>
    </ItemGroup>
    <PropertyGroup>
      <SetupProjectPath>$(MSBuildProjectDirectory)\$(IntermediateOutputPath)$(TargetFileName).config</SetupProjectPath>
    </PropertyGroup>
    <!-- Change the following so that this Task can find your vdproj file -->
    <FileUpdate Files="$(MSBuildProjectDirectory)\..\Setup1\Setup1.vdproj"
                    Regex="(.SourcePath. = .8:).*\.config(.)"
                    ReplacementText="$1$(SetupProjectPath.Replace(`\`,`\\`))$2" />
    <FileUpdate Files="$(MSBuildProjectDirectory)\..\Setup1\Setup1.vdproj"
                    Regex="(.TargetName. = .8:).*\.config(.)"
                    ReplacementText="$1$(TargetFileName).config$2" />
  </Target>

5) vdproj ファイルを見つけられるように、前のコードを変更する必要があります。コードにコメントを入れて、変更が必要な場所を示します。

これで、メイン プロジェクトをビルドするたびに、MSBuild によって Setup プロジェクトが変更され、正しい app.config ファイルが使用されるようになります。欠点があるかもしれませんが、このソリューションは洗練され、より良くなる可能性があります。コメントを残す必要がある場合は、できるだけ早く返信しようとします。

使用したリソース

パス内の単一の「\」を二重の「\」に置き換えるには、String の Replace 関数を使用する必要があるため、MSBuild 4.0 が必要です。MSBuild で関数を使用する方法の詳細については、 MSBuild プロパティ関数を参照 してください。

この他の質問でFileUpdate タスクについて学びました。公式プロジェクトはMSBuild Community Tasks Projectです。

これらの 2 つのトピックは、私の調査結果にとって重要でした。

セットアップ プロジェクトに構成固有の app.config ファイルを含めようとしています

プロジェクトのセットアップに関する問題 - 私は太っていますか?

于 2011-08-02T07:15:06.690 に答える
9

私が見つけた別の解決策は、変換を使用せず、app.Release.config などの別の構成ファイルを使用することです。次に、この行を csproj ファイルに追加します。

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <AppConfig>App.Release.config</AppConfig>
  </PropertyGroup>

これにより、展開プロジェクトはパッケージ化時に正しい構成ファイルを使用するようになります。

于 2011-10-18T18:09:43.703 に答える
5

次の回答の最良のものを組み合わせて、外部ツールをまったく使用せずに完全に機能するソリューションを取得しました。

1. App.Config 変換をセットアップする

ソース: https://stackoverflow.com/a/5109530

要するに:

ビルド構成ごとに追加の .config ファイルを手動で追加し、未加工のプロジェクト ファイルを編集して、次のように含めます。

<Content Include="App.config" />
<Content Include="App.Debug.config" >
  <DependentUpon>App.config</DependentUpon>
</Content>
<Content Include="App.Release.config" >
  <DependentUpon>App.config</DependentUpon>
</Content>

</project>次に、プロジェクト ファイルの最後、終了タグの直前に次の XML を含めます。

<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterCompile" Condition="exists('app.$(Configuration).config')">
  <TransformXml Source="app.config" Destination="$(IntermediateOutputPath)$(TargetFileName).config" Transform="app.$(Configuration).config" />
  <ItemGroup>
    <AppConfigWithTargetPath Remove="app.config" />
    <AppConfigWithTargetPath Include="$(IntermediateOutputPath)$(TargetFileName).config">
      <TargetPath>$(TargetFileName).config</TargetPath>
    </AppConfigWithTargetPath>
  </ItemGroup>
</Target>

最後に、追加の .config ファイルを編集して、各ビルド構成のそれぞれの変換を含めます。

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <!-- transformations here-->
</configuration>

2. セットアップ プロジェクトに適切な .config を含めます。

最初に、メイン プロジェクトのビルド後のイベントにコマンドを追加して、変換された適切な .config ファイルをニュートラルな場所 (メインbin\ディレクトリなど)に移動します。

copy /y "$(TargetDir)$(TargetFileName).config" "$(ProjectDir)bin\$(TargetFileName).config"

(ソース: https://stackoverflow.com/a/26521986 )

セットアップ プロジェクトを開き、[プライマリ出力...] ノードをクリックして、プロパティ ウィンドウを表示します。そこに ExludeFilter"*.config"を追加して、デフォルトの (変換されていない) .config ファイルを除外します。

(ソース: https://stackoverflow.com/a/6908477 )

最後に、変換された .config ファイル (ビルド後のイベントから) をセットアップ プロジェクトに追加します ([追加] > [ファイル])。

終わり。

ビルド構成と対応する構成変換を自由に追加できるようになりました。セットアップ プロジェクトには、アクティブな構成に適切な .config が常に含まれます。

于 2017-06-20T07:09:14.973 に答える
4

外部ツールを使用せずに、別の方法でこれを実現しました。

ターゲット ファイルを「ニュートラル」ディレクトリ (プロジェクトの /bin フォルダーのルート) にコピーするビルド後のイベントを追加し、このファイルを .vdproj に追加しました。展開プロジェクトは、最新のビルド バージョンが何であれ、それを取得するようになりました。

ビルド後のコマンド:

copy /y "$(TargetDir)$(TargetFileName).config" "$(ProjectDir)bin\$(TargetFileName).config"

これは、外部ツールなしで必要なものに機能し、SlowCheetah 変換でうまく機能します。

于 2014-10-23T05:47:22.687 に答える
1

質問は古いですが、以下はまだそこにいる多くの人々を助けることができます.

Wix WiFile.exe を使用して、msi 内の関連ファイルを次のように置き換えます (この例では、msi をyourPackage.msiと呼びます)。

ステップ 1. コマンド プロンプトから次を実行します: WiFile.exe "yourPackage.msi" /x "app.exe.config." 上記は、「間違った」 app.exe.config ファイルを msi から抽出し、 msi と同じディレクトリに配置します

ステップ 2. 新しい (prod) 構成ファイル (抽出されたファイルと同じ名前である必要があります: app.exe.config) を msi と同じ場所に配置します。 これは、上記の手順 1 で抽出したばかりの app.exe.config を新しい (運用構成ファイル) で上書きしていることを意味します

ステップ 3. コマンド プロンプトから次を実行します: WiFile.exe "yourPackage.msi" /u "app.exe.config."

それで全部です!

上記は数秒で完了します。たとえば、バッチとして実行するなど、必要に応じてタスクを自動化できます。

上記の手順 3 を実行すると、msi に新しい構成ファイルが含まれます。これは、クライアントがセットアップを実行するときにクライアントにインストールされます。

于 2017-08-14T04:46:52.323 に答える
1

上記の解決策や記事のいずれも、展開/セットアップ プロジェクトではうまくいきませんでした。正しい解決策を見つけるために何日も費やしました。最後に、このアプローチは私にとってうまくいきました。

前提条件

cct.exeというユーティリティを使用して、ファイルを明示的に変換しました。ここからダウンロードできます http://ctt.codeplex.com/

インストール イベントをキャプチャするために、セットアップ プロジェクトでカスタム インストーラーを使用しました。

次の手順に従って、アプリ構成の変換を実現します

1) 目的の構成ファイルをプロジェクトに追加し、.csproj ファイルを次のように変更します。

<Content Include="app.uat.config">
  <DependentUpon>app.config</DependentUpon>
</Content>
<Content Include="app.training.config">
  <DependentUpon>app.config</DependentUpon>
</Content>
<Content Include="app.live.config">
  <DependentUpon>app.config</DependentUpon>
</Content> 

出力ディレクトリにコピーできるように、それらをコンテンツとして追加しました。

2)ダウンロードしたプロジェクトにcct.exeを追加します。

3)カスタム インストーラーをプロジェクトに追加します。これは次のようになります。

  [RunInstaller(true)]
  public partial class CustomInstaller : System.Configuration.Install.Installer
  {
    string currentLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    string[] transformationfiles = Directory.GetFiles(Path.GetDirectoryNam(Assembly.GetExecutingAssembly().Location), "app.*.config");

    public CustomInstaller()
    {
        InitializeComponent();
        // Attach the 'Committed' event.
        this.Committed += new InstallEventHandler(MyInstaller_Committed);
        this.AfterInstall += new InstallEventHandler(CustomInstaller_AfterInstall);

    }


    void CustomInstaller_AfterInstall(object sender, InstallEventArgs e)
    {
        try
        {

            Directory.SetCurrentDirectory(currentLocation);
            var environment = Context.Parameters["Environment"];
            var currentconfig = transformationfiles.Where(x => x.Contains(environment)).First();

            if (currentconfig != null)
            {
                FileInfo finfo = new FileInfo(currentconfig);
                if (finfo != null)
                {
                    var commands = string.Format(@"/C  ctt.exe s:yourexename.exe.config t:{0} d:yourexename.exe.config ", finfo.Name);

                    using (System.Diagnostics.Process execute = new System.Diagnostics.Process())
                    {
                        execute.StartInfo.FileName = "cmd.exe";
                        execute.StartInfo.RedirectStandardError = true;
                        execute.StartInfo.RedirectStandardInput = true;
                        execute.StartInfo.RedirectStandardOutput = true;
                        execute.StartInfo.UseShellExecute = false;
                        execute.StartInfo.CreateNoWindow = true;
                        execute.StartInfo.Arguments = commands;
                        execute.Start();
                    }

                }
            }
        }
        catch
        {
            // Do nothing... 
        }


    }

    // Event handler for 'Committed' event.
    private void MyInstaller_Committed(object sender, InstallEventArgs e)
    {
        XmlDocument doc = new XmlDocument();
        var execonfigPath = currentLocation + @"\yourexe.exe.config";
        var file = File.OpenText(execonfigPath);
        var xml = file.ReadToEnd();
        file.Close();
        doc.LoadXml(FormatXmlString(xml));
        doc.Save(execonfigPath);

        foreach (var filename in transformationfiles)
            File.Delete(filename);

    }



    private static string FormatXmlString(string xmlString)
    {
        System.Xml.Linq.XElement element = System.Xml.Linq.XElement.Parse(xmlString);
        return element.ToString();
    }

}

ここでは、2 つのイベント ハンドラーCustomInstaller_AfterInstallを使用して、正しい構成ファイルを読み込んで変換しています。MyInstaller_Committedでは、適用後にクライアント マシンで必要のない変換ファイルを削除しています。cct は単に要素を醜く整列させただけなので、変換されたファイルもインデントしています。

4) セットアップ プロジェクトを開き、プロジェクト出力コンテンツ ファイルを追加して、セットアップが app.uat.config、app.live.config などの構成ファイルをクライアント マシンにコピーできるようにします。

前のステップでは、このスニペットは利用可能なすべての構成ファイルをロードしますが、適切な変換ファイルを提供する必要があります

 string[] transformationfiles = Directory.GetFiles(Path.GetDirectoryNam

 (Assembly.GetExecutingAssembly().Location), "app.*.config");

そのために、セットアップ プロジェクトに UI ダイアログを追加して、現在の構成を取得しました。ダイアログには、ユーザーが「ライブ」「UAT」「テスト」などの環境を選択するためのオプションが表示されます。選択した環境をカスタム インストーラーに渡し、それらをフィルター処理します。

ユーザーがオプションを選択できるように UI を構成する

ここに画像の説明を入力

ここに画像の説明を入力

ダイアログの追加方法やパラメータの設定方法などを説明すると長文になるのでググってみてください。しかし、アイデアはユーザーが選択した環境を変えることです。このアプローチの利点は、どの環境でも同じセットアップ ファイルを使用できることです。

要約は次のとおりです。

構成ファイルを追加する

cct exeファイルを追加

カスタムインストーラーを追加

インストール イベントの後、exe.config に変換を適用します。

クライアントのマシンから変換ファイルを削除する

次のようにセットアップ プロジェクトを変更します。

set up should copy all config files(project output content) and cct.exe into output directory

configure UI dialog with radio buttons (Test,Live,UAT..)

pass the selected value to custom installer

MSI は常に app.config をコピーし、プロジェクトのビルド イベントと変換を気にしないため、ソリューションは長く見えるかもしれませんが、選択の余地はありません。slowcheetah は、プロジェクトのセットアップではなく、clickonce でのみ動作します

于 2014-04-22T11:18:52.910 に答える