diff --git a/.github/secret_scanning.yml b/.github/secret_scanning.yml new file mode 100644 index 000000000..780663a5c --- /dev/null +++ b/.github/secret_scanning.yml @@ -0,0 +1,49 @@ +# -------------------------------------------------- +# Secret scanning のアラートから除外するパス +# +# ここに書いたパスは「アラートを出さない」だけである。 +# **Push protection には効かない。** Push protection は除外設定を見ず、 +# 検知したら push を止める(通したい場合はバイパスする)。 +# +# したがって本ファイルの目的は、 +# **テスト専用の資材で Security タブが埋まり、本物が見えなくなるのを防ぐこと**にある。 +# +# 参考: https://docs.github.com/code-security/secret-scanning/using-advanced-secret-scanning-and-push-protection-features/excluding-folders-and-files-from-secret-scanning +# -------------------------------------------------- +paths-ignore: + + # -------------------------------------------------- + # 暗号・署名テスト用の証明書と秘密鍵(19 件) + # + # Public.Security(JWT / JWS / JWE / 鍵交換 / X.509)のテストと、 + # サンプルの SSL/TLS・クライアント証明書認証で使う。 + # **すべてテスト専用の自己署名で、実運用の証明書は含まない。** + # + # 実体は次で参照される。 + # Frameworks/Tests/EncAndDecUtil, EncAndDecUtilCUI + # Frameworks/Tests/TestCode + # Samples/WS_sample ほか + # -------------------------------------------------- + - "root/files/resource/X509/**" + + # -------------------------------------------------- + # ClickOnce の署名用(テンポラリ キー) + # + # WSClientWinCone_sample.csproj が拇印で証明書ストアを検索するため、 + # 当該証明書が無い環境ではビルドできない(BUILDING.md 4 節)。 + # 検証 3 本では MSB3482 / MSB3325 / MSB3321 を既知として除外している。 + # -------------------------------------------------- + - "root/programs/CS/Samples/WS_sample/WSClient_sample/WSClientWinCone_sample/WSClientWinCone_sample_TemporaryKey.pfx" + +# -------------------------------------------------- +# ここに足していないもの、と その理由 +# +# ・テスト・サンプルの接続文字列(Password= を含む app.config / appsettings.json、49 件) +# Non-provider patterns(汎用のパスワードらしき文字列)を**無効のまま**にしていれば +# 検知されない。既定は無効。 +# 広く paths-ignore に足すと、本物を取りこぼす側のリスクが上がるため入れない。 +# +# ・Frameworks/Tests/** や Samples/** をまとめて除外すること +# 範囲が広すぎる。**本物のキーを誤って置いたときに気付けなくなる。** +# 除外は「中身が分かっているファイル」に限る。 +# -------------------------------------------------- diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml new file mode 100644 index 000000000..07fe844e0 --- /dev/null +++ b/.github/workflows/build-windows.yml @@ -0,0 +1,279 @@ +# 受けブランチ(deps)に入った変更を windows-latest で検証する。 +# +# <位置づけ> +# リリース時の検証 3 本(RELEASE.md 3 節)を、そのまま順に実行する。 +# 1_BuildAll.ps1 全ビルド +# 2_RunAllTests.ps1 単体テスト +# 3_SmokeTest.ps1 サンプルの疎通 +# 「何をビルドするか」の正はバッチ側、「合否の判定」の正は各 .ps1 にある。 +# ここには判定を書かない(書くと二重管理になる)。 +# 順序も入れ替えない(1 のクリーンとアセンブリ配置が 2・3 の前提になる)。 +# +# <対象外> +# ・GUI アプリケーション(WinForms / WPF / 各ツールの画面)… RELEASE.md 4 節の手作業 +# ・SQL Server 以外の DBMS への接続 … 自動テストは /Dap SQL のみを使う +# (TestSQLUtility は 4 DBMS の SQL 生成を検証するが、接続はしない) +# +# <署名エラーを除外している理由> +# WSClientWinCone_sample.csproj は ClickOnce の署名が有効で、証明書を拇印で指定し、 +# 同梱の .pfx はパスワード保護されている。実行のたびに作り直される CI では用意できない。 +# +# ローカルと CI で出るコードが違うことに注意する。 +# ローカル : MSB3482(マニフェストの署名で失敗) +# … .pfx が既にキー コンテナへ取り込まれており、最後の署名まで進むため +# CI : MSB3325 / MSB3321(キー ファイルの取り込みで失敗) +# … ResolveKeySource が .pfx を取り込めず、署名に到達しないため +# +# このため 3 つのコードを対象にし、さらに当該プロジェクトに限定する。 +# 除外した内容はログに一覧されるので、握り潰しにはならない。 + +name: Build on Windows + +on: + push: + branches: [deps] + # master 宛の PR ではリリースの関所として動かす。 + # + # ・master へのマージは develop からのリリース時だけで、往復しない。 + # 1 回あたり 10 分前後の待ちは受け入れられる。 + # ・RELEASE.md フェーズ 1 の「検証 3 本」を機械的に担保する。 + # + # develop は対象にしない。deps ⇔ develop ⇔ feature と往復が多く、 + # 毎回のマージが CI 待ちになる。deps 由来の変更は deps で検証済みでもある。 + pull_request: + branches: [master] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: windows-latest + # ローカルの実測はビルド 5.8 分+テスト 1.3 分。DB の導入と初期化を足して余裕を持たせる。 + timeout-minutes: 120 + + env: + # ankane/setup-sqlserver が設定する既定のパスワード。 + INITIAL_SA_PASSWORD: 'YourStrong!Passw0rd' + # テストとサンプルの構成ファイルに直書きされている値。 + # Data Source=localhost;Initial Catalog=Northwind;User ID=sa;Password=seigi@123;Encrypt=false; + # 構成側を CI 用に書き換えると「実際に使われる設定」と乖離するため、DB 側を合わせる。 + SA_PASSWORD: 'seigi@123' + # LocalServicesOnDocker の docker-compose.yml が指定する照合順序と同じ。 + COLLATION: 'Japanese_CI_AS' + + steps: + - name: Checkout + uses: actions/checkout@v7 + + # 1_BuildAll.ps1 は git を使わないため、既定の浅い clone のままでよい。 + # 2_RunAllTests.ps1 は git show HEAD: で期待値を取るが、これも浅い clone で足りる。 + - name: Build all + shell: pwsh + working-directory: root/programs + run: .\1_BuildAll.ps1 -OutputDir "${{ runner.temp }}\BuildLogs" -IgnoreErrors 'error MSB(3482|3325|3321):.*WSClientWinCone_sample\.csproj' + + # ------------------------------------------------------------------ + # 単体テストのための SQL Server + # ------------------------------------------------------------------ + # LocalServicesOnDocker の docker-compose はそのままでは使えない。 + # sqlserver サービスが Linux イメージ(mcr.microsoft.com/mssql/server)で、 + # windows-latest は Linux コンテナを動かせないため(多段のネストができない)。 + # 代わりに runner へ直接 SQL Server を入れ、同リポジトリの instnwnd.sql だけを使う。 + # + # 第三者のアクションなのでコミットで固定する(v1 はタグではなくブランチ)。 + - name: Install SQL Server + uses: ankane/setup-sqlserver@82b78e23506d0c8acfb64e05728ac450ff8a98c6 # v1 + with: + accept-eula: true + sqlserver-version: 2022 + + - name: Set up Northwind + shell: pwsh + env: + # LocalServicesOnDocker のコミットに固定する。 + # 中身は Microsoft 公式の Northwind DDL(約 1 MB)。 + NORTHWIND_URL: https://raw.githubusercontent.com/NetDevInfraWGinOSSConsortium/LocalServicesOnDocker/90763cd5f2aa681b1172d9277a2b133514fdaebe/sqlserver/init/instnwnd.sql + run: | + $ErrorActionPreference = 'Stop' + + # sqlcmd 18 以降は既定で暗号化するため -C(サーバー証明書を信頼)が要る。 + # 旧版は -C を解釈しないので、使えるかどうかを一度だけ判定する。 + $cflag = @() + & sqlcmd -S localhost -U sa -P $env:INITIAL_SA_PASSWORD -C -Q "SELECT 1" *> $null + if ($LASTEXITCODE -eq 0) { $cflag = @('-C') } + + function Invoke-Sql + { + param([string]$Password, [string]$Database, [string]$Query, [string]$File, [switch]$Raw) + + $a = @('-S', 'localhost', '-U', 'sa', '-P', $Password, '-b') + $cflag + if ($Database) { $a += @('-d', $Database) } + if ($Raw) { $a += @('-h', '-1', '-W') } + if ($Query) { $a += @('-Q', $Query) } + if ($File) { $a += @('-i', $File) } + & sqlcmd @a + } + + # 構成ファイルに合わせてパスワードを変更する。 + Write-Host "sa のパスワードを構成ファイルに合わせます。" + Invoke-Sql -Password $env:INITIAL_SA_PASSWORD -Query "ALTER LOGIN sa WITH PASSWORD = '$($env:SA_PASSWORD)'" + if ($LASTEXITCODE -ne 0) { throw "sa のパスワードを変更できませんでした。" } + + $sql = Join-Path $env:RUNNER_TEMP 'instnwnd.sql' + Invoke-WebRequest -Uri $env:NORTHWIND_URL -OutFile $sql + Write-Host ("instnwnd.sql を取得しました({0:N0} バイト)。" -f (Get-Item $sql).Length) + + # instnwnd.sql は DB を作らない(対象 DB の中で実行する)ため、先に CREATE する。 + # 照合順序は DB 既定として与える。Northwind の列は COLLATE 句を持たないので、 + # 各列がこれを継承する。 + # + # 起動直後は一部のバッチが失敗して不完全なロードになることがあるため + # (表だけできてデータが入らない等)、Shippers が 3 行あるかで検証して再試行する。 + # 判定方法は LocalServicesOnDocker の start-up.sh に合わせている。 + $loaded = $false + + foreach ($attempt in 1..3) + { + Write-Host "Northwind をロードします($attempt 回目)。" + + # ヒアストリングは使わない。YAML のブロック スカラーはインデントを + # 剥がすため、終端の "@ を行頭に置く必要があり、桁が衝突する。 + $drop = "IF DB_ID('Northwind') IS NOT NULL BEGIN ALTER DATABASE Northwind SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE Northwind; END;" + $create = "CREATE DATABASE Northwind COLLATE $($env:COLLATION);" + + Invoke-Sql -Password $env:SA_PASSWORD -Query "$drop $create" + Invoke-Sql -Password $env:SA_PASSWORD -Database Northwind -File $sql *> $null + + $n = (Invoke-Sql -Password $env:SA_PASSWORD -Database Northwind -Raw ` + -Query "SET NOCOUNT ON; SELECT COUNT(*) FROM dbo.Shippers") -join '' + if ($n.Trim() -eq '3') { $loaded = $true; break } + + Write-Host " ロードが不完全です。再試行します。" + } + + if (-not $loaded) { throw "Northwind のロードが完了しませんでした。" } + + # Northwind 標準には無い表。3_SmokeTest.ps1 の RerunnableBatch 系が使う。 + # (Orders 830 件を読んで Orders2 へ INSERT する。空にするのはスクリプト側の役目) + # + # 3_SmokeTest.ps1 も無ければ作るため、ここは無くても通る。 + # それでも流しておくのは、DB の準備をこのステップに閉じるため + # (疎通確認より前に、表が揃っていることを確かめられる)。 + # なお sqlcmd は GO をそのまま解釈できる。SqlClient で流すスクリプト側は + # 自前で分割している。 + $orders2 = 'root/programs/CS/Samples/Bat_sample/RerunnableBatch_sample/CREATE ORDERS2.sql' + Invoke-Sql -Password $env:SA_PASSWORD -Database Northwind -File $orders2 *> $null + + # 初期状態の確認(RELEASE.md 2 節と同じ観点)。 + $orders = (Invoke-Sql -Password $env:SA_PASSWORD -Database Northwind -Raw ` + -Query "SET NOCOUNT ON; SELECT COUNT(*) FROM dbo.Orders") -join '' + Write-Host ("Northwind 準備完了 : Shippers=3 Orders={0}" -f $orders.Trim()) + + # ------------------------------------------------------------------ + # テストが前提とする環境(C:\root と日本語ロケール) + # ------------------------------------------------------------------ + - name: Set up C:\root and locale + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + + # 構成ファイルが C:\root\files\... を絶対パスで参照している。 + # TestCode/App.config FxXMLMSGDefinition / FxXMLSPDefinition + # SimpleBatch/app.config SqlTextFilePath + # 無いと GetMessage が空を返し、SimpleBatch は + # resource file [...] was not found + # で失敗する。コピーではなくジャンクションにして、実体を 1 つに保つ。 + if (-not (Test-Path 'C:\root')) + { + New-Item -ItemType Junction -Path 'C:\root' ` + -Target (Join-Path $env:GITHUB_WORKSPACE 'root') | Out-Null + } + + foreach ($p in @('C:\root\files\resource\Sql', + 'C:\root\files\resource\Xml\MSGDefinition.xml', + 'C:\root\files\resource\Xml\SPDefinition.xml')) + { + if (-not (Test-Path $p)) { throw "$p が見つかりません。" } + } + Write-Host "C:\root を配置しました。" + + # 期待値は日本語環境で生成されている。runner の既定は en-US で、 + # 「書式」と「言語」の両方がずれる。両方を合わせる必要がある。 + # + # <CurrentCulture(書式)> + # 期待 : 0:00:00 実測 : 4/24/1977 12:00:00 AM + # CompareResult.ps1 の は \d{4}/\d{1,2}/\d{1,2} で、 + # 1977/4/24 の形にしか一致しない。 + # + # <CurrentUICulture(言語)> + # ここでは直せない。試して駄目だったものは BUILDING.md 9 節に記録した。 + # Install-Language … ハング(run 30976630947) + # Set-WinUILanguageOverride … 言語パックの導入が前提 + # PreferredUILanguages を直書き … 未インストールの言語は無視される + # 言語に依存する 2 か所は、リポジトリ側で処理している。 + # GetMessage … TestCode の構成に FxBusinessMessageCulture=ja-JP を指定 + # OS のメッセージ … CompareResult.ps1 で に正規化 + Set-Culture ja-JP + + # Set-Culture はレジストリを書き換えるだけで、現在のセッションには反映されない。 + # 効いたかどうかを子プロセスで確認する(UICulture は en-US のままが正常)。 + $c = & powershell -NoProfile -Command "(Get-Culture).Name + ' / ' + (Get-UICulture).Name" + Write-Host ("新しいプロセスの Culture / UICulture : {0}" -f $c) + + - name: Run all tests + shell: pwsh + working-directory: root/programs + run: .\2_RunAllTests.ps1 -OutputDir "${{ runner.temp }}\TestResults" + + # ------------------------------------------------------------------ + # 疎通(3_SmokeTest.ps1) + # ------------------------------------------------------------------ + # 3_SmokeTest.ps1 はサービスの開始を自分では行わない。システムの状態を変える + # 操作だからで、足りない場合は対処方法を示して NG にする(AGENTS.md の線引き)。 + # runner は使い捨てで、この判断が当てはまらないため、ここで開始する。 + - name: Start aspnet_state + shell: pwsh + run: | + Start-Service aspnet_state + Write-Host ("aspnet_state : {0}" -f (Get-Service aspnet_state).Status) + + # IIS Express は windows-latest(win25-vs2026)に同梱されている。 + # C:\Program Files\IIS Express\iisexpress.exe v10.0.26013.1000 + # 3_SmokeTest.ps1 が見るのも %ProgramFiles% 側なので、そのまま使える。 + - name: Smoke test + shell: pwsh + working-directory: root/programs + run: .\3_SmokeTest.ps1 -OutputDir "${{ runner.temp }}\SmokeTest" + + # 失敗時こそ中身を見たいので、常に採取する。 + - name: Upload build logs + if: always() + uses: actions/upload-artifact@v7 + with: + name: build-logs + path: ${{ runner.temp }}\BuildLogs + if-no-files-found: warn + + # 期待値(HEAD 版)・ビルド ログ・再生成された実測値をまとめて採取する。 + # 差分が出たときは、この 2 つを突き合わせて原因を切り分ける。 + - name: Upload test results + if: always() + uses: actions/upload-artifact@v7 + with: + name: test-results + path: | + ${{ runner.temp }}\TestResults + root/programs/CS/Frameworks/Tests/**/Result*.txt + if-no-files-found: warn + + # 疎通は期待結果ファイルを持たないため、判定は各対象の標準出力に残る。 + # Web 系は IIS Express の起動ログもここに入る。 + - name: Upload smoke test logs + if: always() + uses: actions/upload-artifact@v7 + with: + name: smoke-logs + path: ${{ runner.temp }}\SmokeTest + if-no-files-found: warn diff --git a/.github/workflows/dependabot-retarget.yml b/.github/workflows/dependabot-retarget.yml new file mode 100644 index 000000000..2f5646232 --- /dev/null +++ b/.github/workflows/dependabot-retarget.yml @@ -0,0 +1,45 @@ +# Dependabot が作成した PR のベース ブランチを deps へ振り替える。 +# +# <なぜ必要か> +# Dependabot のセキュリティ アップデートは、既定ブランチ(develop)にしか +# PR を出さない。dependabot.yml の target-branch はバージョン更新にしか +# 効かないため、受けブランチへ向けるにはこの方法しかない。 +# +# <なぜ pull_request_target か> +# Dependabot が起こしたイベントでは GITHUB_TOKEN が既定で read-only になり、 +# base の書き換えができない。pull_request_target は read-write にできる。 +# +# <安全性> +# pull_request_target は「ベース ブランチ側の定義」を書き込み権限付きで動かす。 +# ここで PR のコードを checkout して実行すると、PR に任意のコードを書ける相手へ +# 権限を渡すことになる(pwn request)。 +# 本ワークフローは checkout を行わず、gh コマンドだけを実行する。 +# 権限も pull-requests: write の 1 つだけに絞る。 + +name: Retarget Dependabot PRs to deps + +on: + pull_request_target: + types: [opened] + +permissions: + pull-requests: write + +jobs: + retarget: + # develop 宛の Dependabot の PR だけを対象にする。 + # base の判定を入れているのは、既に deps 宛のものを再度書き換えないため。 + if: >- + github.actor == 'dependabot[bot]' && + github.event.pull_request.base.ref == 'develop' + runs-on: ubuntu-latest + + steps: + - name: Change base branch to deps + # 値は env 経由で渡す。run: に ${{ }} を直接書くと、 + # 値の内容がシェルのコマンドとして解釈される余地が残る。 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REPO: ${{ github.repository }} + run: gh pr edit "$PR_NUMBER" --repo "$REPO" --base deps diff --git a/.gitignore b/.gitignore index 219172306..e8c067635 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -## Ignore Visual Studio temporary files, build results, and +## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore @@ -285,4 +285,59 @@ __pycache__/ *.btp.cs *.btm.cs *.odx.cs -*.xsd.cs \ No newline at end of file +*.xsd.cs + +# -------------------------------------------------- +# Open棟梁 build outputs +# ビルド bat / csproj の OutputPath が出力するディレクトリ。 +# ※ 既存の "!**/packages/build/" と衝突しないよう、 +# あえて汎用の "Build/" ではなくパスを固定している +# (core.ignoreCase=true の環境では Build/ が build/ にも一致するため)。 +# -------------------------------------------------- +/root/programs/*/Frameworks/Infrastructure/Build/ +/root/programs/*/Frameworks/Infrastructure/Build_net48/ +/root/programs/*/Frameworks/Infrastructure/Build_netcore100/ +/root/programs/*/Frameworks/Infrastructure/*/RichClient/Build_net48/ +/root/programs/*/Frameworks/Infrastructure/ServiceInterface/*/dll/ +/root/programs/*/Samples/WS_sample/Build/ +/root/programs/*/Samples4NetCore/Legacy/WS_sample/Build/ + +# -------------------------------------------------- +# Open棟梁 test certificates (copies) +# copy_cert.bat と 2_RunAllTests.ps1 が +# root/files/resource/X509/ から複製する作業用のコピー。 +# 正本はそちらにあるため、複製側は追跡しない。 +# ※ 対になる .pfx は上の汎用の "*.pfx" で既に無視される。 +# .cer は正本 (root/files/resource/X509/*.cer) を追跡し続ける必要があるため、 +# 汎用パターンにはせず、複製先のフォルダに限定する。 +# -------------------------------------------------- +/root/programs/*/Frameworks/Tests/EncAndDecUtilCUI/*.cer + +# -------------------------------------------------- +# DeployZipPackWithHTTP のサンプル(配布物) +# FormAppRootWeb は FormAppRoot から生成する。 +# /ZIPGEN で ZIP を作り、/MFTGEN でマニュフェストを作る。 +# **元を直したら作り直しが要る。** 追跡すると作り直し漏れで +# MD5 が合わなくなり、配布が失敗する。生成手順は同フォルダの README.md。 +# -------------------------------------------------- +/root/programs/*/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRootWeb/ +/root/programs/*/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRootWeb2/ + +# -------------------------------------------------- +# NuGet パッケージング(#531) +# in\ … Build_* からの複製(_NuGetPack.bat の xcopy) +# out\ … 生成した .nupkg / .snupkg +# いずれも毎回作り直すため追跡しない。 +# ※ 各フォルダの説明用 .txt と _NuGetPush.bat は追跡し続ける必要があるため、 +# フォルダごとではなく、生成物の種類で除外する。 +# ※ .nupkg は上の汎用パターンで既に無視される。.snupkg は形式が +# 後から使われるようになったため、指定が漏れていた。 +# -------------------------------------------------- +/root/programs/*/NuGet/in/*/*.dll +/root/programs/*/NuGet/in/*/*.pdb +/root/programs/*/NuGet/in/*/*.xml +/root/programs/*/NuGet/in/*/*.XML +/root/programs/*/NuGet/in/*/*.config +/root/programs/*/NuGet/in/*/*.json +/root/programs/*/NuGet/in/*/*/ +*.snupkg diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..171d94214 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,150 @@ +# プロジェクト ポリシー +アプリケーション・フレームワーク + +https://github.com/OpenTouryoProject/OpenTouryo/ + +と、ソレを使用したサンプル・アプリケーションの開発エージェント用。 + +環境のセットアップとビルド手順は [root/Readme.ja.md](root/Readme.ja.md) を参照。 +本書は、その上で**エージェントが守るべきこと**と、**どの文書を見るか**を示す。 + +**プロジェクト共通の投稿規約は [Contributing.ja.md](Contributing.ja.md) に従う。** +コメント量の目安、クロスコンパイルと下位互換の方針、ブランチ運用(git-flow)、 +"プルリクエスト" の粒度は、人もエージェントも同じ規約による。 +本書は、そこに書かれていない**エージェント固有の制約**を扱う。 + +> **手順を思い出したいだけなら [`CHEATSHEET.md`](root/programs/CHEATSHEET.md) を見る。** +> 検証・リリース・VB ビルド・ツール・規約の要点と、よく踏む落とし穴を 1 枚にまとめてある。 +> **理由や判断が要ることは書いていない**ので、迷ったらそこからリンク先へ辿ること。 + +### Git 操作は行わない(状態を変える操作をしない) + +**成果物の検収は人が行う。** エージェントは作業結果をワーキング ツリーに残すところまでを担当し、 +Git 操作は人が手動で行う。 + +したがって、指示がない限り次を実行してはならない。 + +- `git add` / `commit` / `push`(検収前・未レビューの変更を確定・送信しない) +- `git checkout` / `switch` / `branch` / `reset` / `restore` / `stash`(人の作業状態や未保存の作業を壊す) + +**参照系は制限しない。** 何を変更したかを正確に報告するために必要なため、次は自由に実行してよい。 + +- `git status` / `diff`(`--cached` 含む)/ `log` / `show` / `ls-files` / `check-ignore` / `blame` + +作業が完了したら**何を変更したかを報告するに留める**。コミットの要否とタイミングは人が判断する。 + + + +### GitHub 操作は gh で行う + +Issue の調査・起票・コメントは、**`gh` コマンドで実行してよい**(ブラウザ操作を人に依頼しない)。 +上記の「Git 操作は行わない」はワーキング ツリーとコミット履歴に対する制約であり、 +GitHub 側のやり取りは対象外。 + +``` +gh issue view <番号> --repo OpenTouryoProject/OpenTouryo +gh issue list --repo OpenTouryoProject/OpenTouryo +gh issue comment <番号> --repo OpenTouryoProject/OpenTouryo --body-file +gh issue create --repo OpenTouryoProject/OpenTouryo --title --body-file <path> +``` + +ただし**公開リポジトリへの投稿は取り消しにくい**ため、次を守ること。 + +- **投稿前に文面を提示し、承認を得てから実行する。** 承認なしに投稿しない +- 本文は一時ファイルに書き、`--body-file` で渡す(改行・記号の欠落を避ける) +- 投稿後は URL を報告する + +**このリポジトリでは `OsscJpDevInfra` アカウントを使用する。** +`gh auth status` に複数のアカウントが登録されていることがあるため、 +投稿前にアクティブなアカウントを確認すること。異なる場合は `gh auth switch` で切り替える。 + +``` +gh auth status # アクティブなアカウントの確認 +gh auth switch --user OsscJpDevInfra # 異なる場合は切り替え +``` + +**Issue のクローズ・ラベル変更・アサイン、PR の作成やマージは人が行う。** +これらは成果物の検収と同じ扱いとし、エージェントは提案に留める。 + +### コーディング規約は CODING.md、領域ごとの事情は ANALYSIS.md に従う + +**規約は全領域に共通、分析は領域ごと**に分かれている。 + +| 内容 | 読む文書 | +|---|---| +| **コーディング規約(全領域共通)** | [`CODING.md`](root/programs/CODING.md) | +| `root/programs/CS/Frameworks/` の分析 | [`Frameworks/ANALYSIS.md`](root/programs/CS/Frameworks/ANALYSIS.md) | +| `root/programs/CS/Samples/` の分析 | [`Samples/ANALYSIS.md`](root/programs/CS/Samples/ANALYSIS.md) | +| `root/programs/CS/Samples4NetCore/` の分析 | [`Samples4NetCore/ANALYSIS.md`](root/programs/CS/Samples4NetCore/ANALYSIS.md) | + +**コードを変更する前に、[`CODING.md`](root/programs/CODING.md) と、 +作業対象を所管する `ANALYSIS.md` の両方を読むこと。** + +`CODING.md` には、ファイル ヘッダの書式と**更新者名**、新規ファイルにおける +Copyright ブロックの扱い、`ArgumentException` 系の引数の順、`.bat` / `.ps1` の +文字コードなど、**エージェントが見落としやすい指定**が含まれる。 + +各 `ANALYSIS.md` は、その領域におけるアーキテクチャ・ビルド手順・条件コンパイル・ +既知の落とし穴の**一次情報**である。末尾の +「エージェント向け作業チェックリスト」には着手前に目を通すこと。 + +規約の実体はこのファイル(AGENTS.md)には書かない。二重管理になり、 +どちらが正なのか分からなくなる。 + +### ビルド・テスト・リリースの検証は、専用の文書に従う + +変更を加えたあとの**検証**は、次の文書が一次情報である。 + +| 目的 | 読む文書 | +|---|---| +| **手順だけを引く(早見)** | [`CHEATSHEET.md`](root/programs/CHEATSHEET.md) | +| リリース時の作業全体 | [`RELEASE.md`](root/programs/RELEASE.md) | +| 全ビルドの実行と判定 | [`BUILDING.md`](root/programs/BUILDING.md) | +| 単体テストの実行と判定 | [`TESTING.md`](root/programs/TESTING.md) | +| サンプルの疎通確認 | [`SMOKETEST.md`](root/programs/SMOKETEST.md) | + +検証は次の 3 本で、いずれも終了コードで合否が分かる。**この順で実行すること。** + +```powershell +cd root\programs +.\1_BuildAll.ps1 # 全ビルド +.\2_RunAllTests.ps1 # 単体テスト +.\3_SmokeTest.ps1 # サンプルの疎通 +``` + +`2_RunAllTests.ps1` はワーキング ツリーの `Result*.txt` を書き換える(従来のバッチ運用と同じ)。 +**コミットの要否は人が判断する**ため、エージェントは差分を報告するに留める。 + +**`.ps1` は Windows PowerShell 5.1 と PowerShell 7 の両方で動くこと。** +エージェントの実行環境は 7 だが、利用者は 5.1(`powershell.exe`)で実行するため、 +7 だけで確認すると 5.1 で落ちる。**変更したら 5.1 でも実行して確かめること。** + +規約の実体は +[`Frameworks/ANALYSIS.md`](root/programs/CS/Frameworks/ANALYSIS.md) の +**8.5 節「ps1 ファイルの文字コードと、PowerShell 5.1 / 7 の両対応」**にある。 + +前提となるサービスや DB の状態が足りない場合は、**勝手に変えず、対処方法とともに報告する。** + +### 付属ツールを CLI で使うときは、各ツールの README に従う + +エージェントから実行できる(非対話の)ツールには README を置く。 + +| ツール | 読む文書 | +|---|---| +| `DaoGen_Tool`(D層自動生成ツール/墨壺) | [`README.md`](root/programs/CS/Frameworks/Tools/DaoGen_Tool/README.md) | +| `DeployZipPackWithHTTP`(ZIP パッケージの HTTP 配布) | [`README.md`](root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/README.md) | + +**引数の一覧は README に書かない。** ツールの `/HELP` が一次情報であり、 +書き写すと二重管理になる。README には README にしか書けないこと +(実行ファイルの場所、ヘルプの出し方、踏みやすい罠、前提)を置く。 + +- **引数を組み立てる前に、まず `/HELP` を実行する** +- 終了コードだけで判断せず、**生成物の存在も確認する** + (パス区切りを誤ると、成功(`0`)を返しつつ別の場所に出力される) + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..43c994c2d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e6875c306..2927c5cd1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,86 +1,92 @@ # How to contribute -Click [here](Contributing.ja.md) for Japanese version of this file. +Click [here](Contributing.ja.md) for the Japanese version of this file. ## Programming Rules and Conventions ### Comment - - The amount of comments aim about 1/3(33%) of the amount of code. - It has set a higher ratio comment in consideration of the maintenance. - Redundant comment is unnecessary. Amount of redundant comment at the present time was about 43%. + - Aim at about 1/3 (33%) of the amount of code for the amount of comments. + - A higher comment ratio is set in consideration of the maintenance. + - Redundant comments are unnecessary. The amount of (redundant) comments at the present time was about 43%. - - Change history will continue only history of the header. - Descriptions such as start and end point of the fixes are not required. + - Change history will continue only as the history of the header, even after the introduction of Git. Descriptions such as the start and end point of the fixes are not required. ### Coding - - Writing of duplicate code and information has been prohibited in this project. - This is "Once and Only Once" or "Don't repeat yourself". + - Writing duplicate code and information is prohibited in this project. + This is "Once and Only Once" or "Don't repeat yourself". - - Please keep in mind that it is limited to the statement - that can be used in run-time which was specified in the project file. + - This project is cross-compiled for C#, VB, .NET Framework (net48) and .NET Core (net10.0). + However, the VB version is provided only for .NET Framework (net48). - For example, Contained the support of VS 2010 and .NET 3.5 previously - (The current support is from VS 2015 and .NET 4.6 to latest version). - e.g. , such as async/await keyword that can not be used in VS 2010 and .NET 3.5 has not been used in this project. + - Backward compatibility is highly maintained, and breaking changes are kept to a minimum. + - When supporting both a new and an old runtime, the implementation is aligned with the old one (e.g. async/await was not used while the support of VS 2010 and .NET 3.5 was included). + - Because .NET Framework (net48) and .NET Core (net10.0) are different lines, they are cross-compiled by using conditional compilation (preprocessor). + - Breaking changes are basically for the cases of discontinuation on the runtime side, and a sufficient "obsolete" period is provided before the change. + +### Coding agent +The policy for making use of it is described in [AGENTS.md](AGENTS.md). ## C#, VB - Provision of VB version is not required. - If necessary, we will converte to VB by using the Sharpdeveloper. + Provision of the VB version is not required. If necessary, we will convert it to VB by using tools (Sharpdeveloper, generative AI). ## Flow ### GitHub Flow - GitHubFlow is not adopted because there is no culture of the shipment - that test and push constantly and deploy the product every day. + "Push the product every day, test it constantly and deploy it." + GitHub Flow is not adopted because there is no such culture of shipment in this project. - - GitHub Flow - Scott Chacon(原文) - http://scottchacon.com/2011/08/31/github-flow.html - - 上記記事の日本語訳 - https://gist.github.com/Gab-km/3705015 + - GitHub Flow - Scott Chacon (original) + https://scottchacon.com/2011/08/31/github-flow/ + - Japanese translation of the above article + https://gist.github.com/Gab-km/3705015 ### git-flow - This repository is based on the branch model of the the following URL. - - develop branch and master branch has been permanent. - - Create other branches as needed. + This repository is based on the git-flow branching model in "Reference" below. + + - The master and develop branches are permanent. + - Other branches are created as needed. #### Reference - A successful Git branching model » nvie.com - http://nvie.com/posts/a-successful-git-branching-model/ + https://nvie.com/posts/a-successful-git-branching-model/ - 見えないチカラ A successful Git branching model を翻訳しました - http://keijinsonyaban.blogspot.jp/2010/10/successful-git-branching-model.html + http://keijinsonyaban.blogspot.com/2010/10/a-successful-git-branching-model.html + + Note that a note by the author (Note of reflection, 2020/03/05) has been added to the original article above, + which states that git-flow is not recommended for web applications with continuous delivery and so on. + As described above, this project is not operated to ship every day, so git-flow is adopted. ### About the "pull request" #### Size of the "pull request" - - Reduce the size of "commit" and "pull request" for review of "pull request". + - Reduce the size of the "commit" and the "pull request" for the review of the "pull request". - - If multiple tasks of bug or enhance are present in the one "pull request", one delay affects the other. + - If multiple tasks of bugs or enhancements are present in one "pull request", one delay affects the others. - - For this reason, you must create a feature branch for each task of bug or enhance. - After that, ask the review to me by sending each time "pull request" from the feature branch. + - For this reason, you need to create a feature branch for each task of a bug or an enhancement. + After that, ask me for a review by sending a "pull request" from the feature branch each time. - - Also, please do not commit unnecessary changes that indentation is changed by the IDE or editor. + - Also, please do not commit unnecessary changes such as indentation changed by the IDE or the editor. #### Send a "pull request" - - Fork to the repository by each user from OpenTouryo repository. - After having done fork, create a feature branch from the develop branch. + - Fork from the OpenTouryo repository to the repository of each user. + After that, create a feature branch from the develop branch and work on it. + + - Send the "pull request" from your feature branch to the develop branch of the fork source. - - Send "pull request" to the "develop branch of fork source" from your feature branch. + - If the develop branch of the fork source has been changed, do "pull" or "fetch & merge" to the feature branch. - - If "develop branch of fork source" was changed, - then you should do the "pull" or "fetch & merge" operation to the feature branch. +#### Notes for the "pull request" + - Keep the develop / feature branches up to date with the following steps. -#### Notes for "pull request" - - You keep the develop / feature branch up to date as follows. + 1. "pull" or "fetch & merge" the develop branch of OpenTouryo into your develop / feature branch. + 2. Recreate the feature branch from your develop branch. + 3. Reflect the changes to the feature branch. + 4. Test and push, and then send the "pull request". - - "pull" or "fetch & merge" OpenTouryo develop branch from your develop / feature branch. - and you recreate the feature branch from your develop branch and you reflect changes to the feature branch. - After that, test and push, and finally send "pull request". + - These steps serve the following two purposes. - - There is also a way to fork again instead of pull or fetch & marge, - but comments and changes that are not merged original fork source are lost. + - Keeping up with the changes of the develop branch of the fork source. + - Preventing the commit log from being contaminated by rolling back the program after an incorrect change. - - To prevent contaminating the commit log by rolling back program after the incorrect change, follow these steps. - - You recreate the feature branch from your develop branch. -   - And you reflect changes again to the feature branch. -   - After that, test and push, and finally send "pull request". + - There is also a way to fork again instead of "pull" or "fetch & merge", but the comments and the changes that are not merged into the fork source are lost. diff --git a/Contributing.ja.md b/Contributing.ja.md index 42ec4ef00..b99070764 100644 --- a/Contributing.ja.md +++ b/Contributing.ja.md @@ -6,21 +6,28 @@ ### コメント - コメント量はコード量の1/3 (33%) 程度を目安にして下さい。 - メンテナンスを考慮して、高めのコメント比率を設定しています。 - 冗長なコメントは不要です。現時点の冗長なコメントの量は43%程度でした。 + - メンテナンスを考慮して、高めのコメント比率を設定しています。 + - 冗長なコメントは不要です。現時点の(冗長な)コメントの量は43%程度でした。 - - 変更履歴はヘッダの履歴だけ継続します。修正の開始・終了などの記載は不要です。 + - 変更履歴はGit導入後もヘッダの履歴だけ継続します。修正の開始・終了などの記載は不要です。 ### コーディング - このプロジェクトでは重複したコードや情報の書き込みが禁止されています。 これは "Once and Only Once" や "Don't repeat yourself" です。 - - プロジェクトファイルで指定されたのランタイムで使用可能なステートメントに限られますので注意下さい。 - 例えば、以前はVS 2010, .NET 3.5のサポートが含まれていました(現在はVS 2015, .NET 4.6からのサポート)。 - このためVS 2010, .NET 3.5で使用できないasync/awaitキーワードなどは本プロジェクトで使用されていません。 + - C#、VB、.NET Framework 系(net48)、.NET Core 系(net10.0)のクロスコンパイルです。 + ただし、VB版は .NET Framework 系(net48)版のみの提供になります。 + + - 下位互換は高く維持し、破壊的な変更は最小限にします。 + - 新・旧ランタイムをサポートする場合は、旧に合わせた実装を行います(例:VS2010, .NET3.5サポートが含まれていた時は async/await を使用しなかった)。 + - .NET Framework系(net48)、.NET Core系(net10.0)は別系列なので条件付きコンパイル(プリプロセッサ)を使用してクロスコンパイルします。 + - 破壊的な変更は、基本的にランタイム側のdisconのケースで、変更の前に十分に「obsolete」の期間を設けます。 + +### コーディングエージェント +活用方針は [AGENTS.md](AGENTS.md) に記載してあります。 ## C#, VB - VB版の提供は必須ではありません。必要であればこちらでSharpdeveloperを使用してVBに変換します。 + VB版の提供は必須ではありません。必要であればこちらでツール(Sharpdeveloper、生成AI)を使用してVBに変換します。 ## 手順 @@ -29,21 +36,25 @@ という出荷の文化はこのプロジェクトに無い為、GitHubFlowは採用しません。 - GitHub Flow - Scott Chacon(原文) - http://scottchacon.com/2011/08/31/github-flow.html + https://scottchacon.com/2011/08/31/github-flow/ - 上記記事の日本語訳 https://gist.github.com/Gab-km/3705015 ### git-flow - このリポジトリは、次の URL の git-flow ブランチ・モデルに基づいています。 + このリポジトリは、下記「参考」の git-flow ブランチ・モデルに基づいています。 - master と develop ブランチを常設しています。 - その他のブランチは必要に応じて作成します。 #### 参考 - A successful Git branching model » nvie.com - http://nvie.com/posts/a-successful-git-branching-model/ + https://nvie.com/posts/a-successful-git-branching-model/ - 見えないチカラ A successful Git branching model を翻訳しました - http://keijinsonyaban.blogspot.jp/2010/10/successful-git-branching-model.html + http://keijinsonyaban.blogspot.com/2010/10/a-successful-git-branching-model.html + + なお上記の原典には、著者による注記(Note of reflection、2020/03/05)が追記されており、 + 継続的デリバリを行う Web アプリなどには git-flow を勧めない旨が述べられています。 + このプロジェクトは前述のとおり毎日出荷する運用ではないため、git-flow を採用しています。 ### "プルリクエスト"について @@ -58,7 +69,7 @@ - また、IDEやEditorによりインデントが変更されるような不要な修正もコミットしないで下さい。 #### "プルリクエスト"を送る - - Opentouryoリポジトリから各ユーザのリポジトリに fork します。 + - OpenTouryoリポジトリから各ユーザのリポジトリに fork します。 その後に develop ブランチから feature ブランチを作成し作業します。 - "プルリクエスト"は feature ブランチから fork 元の develop ブランチに対して送信します。 @@ -66,15 +77,16 @@ - もし fork 元の develop ブランチが変更されているようなら、feature ブランチに pull 若しくは fetch & merge をします。 #### "プルリクエスト"についての注意事項 - - あなたは、次のように develop / feature ブランチを最新の状態に維持します。 + - develop / feature ブランチは、次の手順で最新の状態に維持します。 + + 1. OpenTouryo の develop ブランチを、あなたの develop / feature ブランチへ pull 若しくは fetch & merge します。 + 2. あなたの develop ブランチから feature ブランチを再作成します。 + 3. feature ブランチへ変更を反映します。 + 4. テストおよびプッシュし、"プルリクエスト"を送ります。 - - OpenTouryoの develop ブランチを、あなたの develop / feature ブランチから pull 若しくは fetch & merge してください。 - そして、あなたはあなたの develop ブランチから feature ブランチを再作成し、あなたはfeatureブランチへの変更を反映します。 - その後、テストおよびプッシュし、"プルリクエスト"を送ります。 + - この手順は、次の 2 つを兼ねています。 - - pull や fetch & margeの代わりに再度 fork する方法もありますが、コメントや元のfork 元にマージされていない変更は失われます。 + - fork 元の develop ブランチの変更に追随すること。 + - 間違った変更の後にプログラムをロールバックして、コミットログが汚染されるのを防ぐこと。 - - 間違った変更の後にプログラムをロールバックしてコミットログが汚染されることを防止するために、次の手順に従ってください。 - - あなたは、あなたの develop ブランチから feature ブランチを再作成します。 - - そして、あなたは feature ブランチへの変更を反映します。 - - その後、テストおよびプッシュし、"プルリクエスト"を送ります。 + - pull や fetch & merge の代わりに再度 fork する方法もありますが、コメントや、fork 元にマージされていない変更は失われます。 diff --git a/GitHubUsage.md b/GitHubUsage.md new file mode 100644 index 000000000..42ea1018c --- /dev/null +++ b/GitHubUsage.md @@ -0,0 +1,462 @@ +# GitHub の使用状況 + +**このリポジトリで GitHub のどの機能を、どう設定して使っているか。** + +設定は GitHub 側(Web UI / API)にあり、**リポジトリのファイルからは見えない**。 +何をどういう理由で設定したかを、ここに残す。 + +> 変更したら本書も更新すること。**設定と本書が食い違うと、本書の方が害になる。** + +**本書はリポジトリ内部の記録である。** 利用者に影響する変更は Issue に書く。 + +| 内容 | 一次情報 | +|---|---| +| CodeQL のトリアージと、**利用者に影響する変更** | [#536](https://github.com/OpenTouryoProject/OpenTouryo/issues/536) | +| Secret scanning の除外パス | [`.github/secret_scanning.yml`](.github/secret_scanning.yml) | +| 手順の早見 | [`CHEATSHEET.md`](root/programs/CHEATSHEET.md) | + +最終更新: 2026-08-10 + +--- + +## 1. セキュリティ + +### 適用している構成 + +組織 `OpenTouryoProject` の **Code security configuration**「**OpenTouryo standard**」(id `265927`)を、 +**このリポジトリにのみ**適用している(組織の既定にはしていない)。 + +https://github.com/organizations/OpenTouryoProject/settings/security_products + +| 項目 | 値 | 理由 | +|---|---|---| +| Dependency graph | 有効 | 公開リポジトリでは常時 | +| Dependabot alerts | 有効 | | +| Dependabot security updates | 有効 | 既に運用中。構成として明示的に固定した | +| Code scanning(CodeQL 既定セットアップ) | 有効 | ワークフローを自前で持たずに済む | +| Private vulnerability reporting | 有効 | **暗号・認証ライブラリを公開している**ため、非公開の報告窓口が要る | +| Secret scanning | 有効 | | +| **Secret scanning: Push protection** | **有効** | 2026-08-10 に有効化(後述) | +| **Secret scanning: Non-provider patterns** | **無効** | **後述** | +| **Secret scanning: Validity checks** | **無効** | **後述** | +| GitHub Advanced Security | 有効 | 公開リポジトリでは無料 | +| Enforcement | Unenforced | リポジトリ個別の調整余地を残す | + +> **`GitHub recommended`(GitHub 提供のグローバル構成)は使っていない。** +> 上の 3 項目が推奨と食い違うため、独自構成を作った。 + +> **`advanced_security: enabled` は公開リポジトリだから無料である。** +> この構成を**非公開リポジトリへ適用するとライセンスを消費する**。使い回す際は注意。 + +### 3 項目を無効にしている理由 + +#### Push protection + +**段階分けのため、最初は無効にした。** 有効にすると、検知した push をその場で止める。 + +``` +1. .github/secret_scanning.yml を develop へ入れる +2. Secret scanning だけ先に有効化 → アラート 0 件で立ち上がり、棚卸しは不要だった +3. Push protection を有効化 → 2026-08-10 実施 +``` + +いきなり両方入れると、**リリース作業の途中で不意に止まる**。 +なお Push protection は `.github/secret_scanning.yml` の除外を**見ない**。 + +#### Non-provider patterns + +汎用のパスワードらしき文字列まで拾う。 +このリポジトリには **`Password=` を含む設定ファイルが 49 件**あり(テスト・サンプルの接続文字列)、 +**有効にすると本物が埋もれる。** + +#### Validity checks + +検知した候補を**発行元へ問い合わせて有効性を確認**する。外部通信であり、必要性がない。 + +### 除外パス + +[`.github/secret_scanning.yml`](.github/secret_scanning.yml) を参照。 +**テスト専用と分かっている資材だけ**を除外している。 + +- `root/files/resource/X509/**` … 暗号・署名テスト用の証明書と秘密鍵 22 件 +- ClickOnce の `WSClientWinCone_sample_TemporaryKey.pfx` + +**先にこのファイルを `develop` へ入れてから Secret scanning を有効化したので、 +アラートは 0 件で立ち上がった**(棚卸しが発生しなかった)。 + +### 有効化した時点のアラート + +| | 件数 | +|---|---| +| Secret scanning | **0** | +| Code scanning(CodeQL) | **30**(critical 1 / high 23 / medium 9) | + +CodeQL の内訳(上位)。 + +``` +8 Inefficient regular expression +8 Missing X-Frame-Options HTTP header +6 Unsafe jQuery plugin +4 'requireSSL' attribute is not set to true +2 Cookie 'Secure' attribute is not set to true +2 DOM text reinterpreted as HTML +1 Deserialization of untrusted data ← critical +``` + +### トリアージの方針 + +> **経緯と実施内容は +> [#536](https://github.com/OpenTouryoProject/OpenTouryo/issues/536) が一次情報。** +> **利用者に影響する変更が 2 点ある**(`CipherMode_ECB` の非推奨化と、 +> Cookie の `Secure` 属性)。リリース ノートからはそちらを参照する。 + +**アラート 1 件ごとに Issue は立てない。** Security タブが追跡するので、 +同じものを Issue でも管理すると二重管理になる。 +**Issue に書くのは「何を決めたか」と「利用者への影響」**であり、 +一覧そのものではない。 + +| 分類 | 件数 | 方針 | +|---|---|---| +| **同梱のサードパーティ製 JS** | 15 | **棄却済み**(`won't fix`)。jQuery / jQuery Validation であり、修正対象ではない。更新はライブラリの版上げで行う。`-vsdoc.js` は IntelliSense 用で実行されない | +| **`BinarySerialize.cs`(critical)** | 1 | **棄却済み**(`won't fix`)。**net48 でのみ継続利用**。`Public_netcore100.csproj` で `<Compile Remove>` しており、netcore100 ではコンパイルされない(`BinaryFormatter` は .NET 9 で削除済み)。net48 の下位互換のために残す | +| **`Missing X-Frame-Options`** | 8 | **6 件は対応済み**(下表)。残る 2 件は MVC の `Views/Web.config` で、**応答ヘッダを出す設定ファイルではない**ため対応しない | +| **`requireSSL` が `true` でない** | 4 | **対応済み。** `requireSSL="true"` の行を**コメントアウトで併記**し、「本番ではコメントアウトを外す」と明記。**サンプルは HTTP で動かす**ため、既定は `false` のまま | +| **`Encryption using ECB`** | 1 | **対応済み → 棄却。** `EnumSymmetricAlgorithm.CipherMode_ECB` に **`[Obsolete]` を付与**した。利用者が指定したときだけ通る 5 択の 1 つで、**既定ではない**(指定しなければ .NET 既定の CBC)。リポジトリ内に指定箇所は 0 件。**削除は下位互換を壊す**ため、非推奨化に留めた。コードは残るのでアラートは消えず、`won't fix` で棄却する | +| **`Cookie 'Secure'` 未設定** | 2 | **対応済み → 棄却。** 指摘されたのは `StdMigration/CookieExtensions.cs` の `Set` 3 つのうち **`CookieOptions` を受け取らない 2 つ**で、**リポジトリ内に呼び出しが 1 件も無い**(利用者向けに残している移植 API)。実際に Cookie を作るのは `CookieOptions` 版を呼ぶ `FxCmnFunction` で、そちらの **4 箇所**(net48 / netcore100 各 2)を修正した。**`HttpOnly` は設定済みだったが `Secure` が無かった**(前者は XSS 対策、後者は盗聴対策で別物) | +| **`DOM text reinterpreted as HTML`** | 2 | **多層防御を追加したが、アラートは残る → 棄却。** 擬似ダイアログの `iframe.src` に URL を設定する前に `Fx_IsSafeDialogUrl()` でスキームを検証するようにした。**CodeQL はこの検証関数をサニタイザと認識しない**ため、指摘は消えない。**既存の脆弱性を塞いだのではない**(URL はフレームワークの `ShowModalScreen` が組み立て、利用者入力は入らず、AppScan もクリア済み) | + +**棄却は削除ではない。** Security タブに `Dismissed` として残り、 +棄却した人・日時・理由・コメントが記録される。復帰もできる。 + +### `X-Frame-Options` の値を対象ごとに分けている理由 + +| 対象 | 値 | 理由 | +|---|---|---| +| `WebForms_Sample`(CS / VB) | **`SAMEORIGIN`** | 擬似ダイアログが**同一オリジンの `iframe`** を使う(`Scripts/touryo/common.js` の `FxIFrame`)。**`DENY` にすると動作しなくなる** | +| `MVC_Sample`(CS / VB) | `DENY` | MVC 版の `common.js` は**別物(818 行)で `iframe` を使わない**。WebForms 版は 1656 行で `iframe` 6 箇所 | +| `ASPNETWebService`(CS / VB) | `DENY` | SOAP の Web サービス。フレームに表示する用途がない | + +**既定は `DENY`、必要な所だけ `SAMEORIGIN` に緩める。** +一律に緩めると、緩める必要のない画面まで枠に入れられるようになる。 + +### Cookie の `Secure` は「HTTPS のときだけ」立てる + +```csharp +cookieOptions.HttpOnly = true; +cookieOptions.Secure = MyHttpContext.Current.Request.IsHttps; // netcore100 +newCookie.Secure = HttpContext.Current.Request.IsSecureConnection; // net48 +``` + +**無条件に `true` にしてはならない。** HTTP で動かす開発環境とサンプルで、 +ブラウザが Cookie を保存しなくなり、**セッション タイムアウト検出が機能しなくなる** +(疎通も通らなくなる)。 + +**CodeQL が指摘した場所と、直すべき場所が違った例。** + +`StdMigration/CookieExtensions.cs` の `Set` は 3 つある。 + +| オーバーロード | 指摘 | 呼び出し | +|---|---|---| +| `Set(key, value)` | **あり** | **0 件**(利用者向けに残している移植 API) | +| `Set(key, value, int expireTime)` | **あり** | **0 件**(同上) | +| `Set(key, value, CookieOptions)` | なし | `FxCmnFunction` が使用 | + +**クラス自体は使われている。** +`Samples4NetCore/Backend/MVC_Sample` も `MyHttpContext` / `SessionExtensions` とあわせ、 +`FxCmnFunction.DeleteCookieForSessionTimeoutDetection()` 経由で +`CookieOptions` 版を呼んでいる。 + +**直したのは `FxCmnFunction` 側**(Cookie を実際に組み立てている場所)。 +**net48 側は指摘されていないが、同じ設計の別実装なので揃えた。** + +> `Samples4NetCore` の `Startup.cs` には +> `//Secure = CookieSecurePolicy.Always` がコメントアウトで残っている。 +> アプリ全体の Cookie ポリシーで一括指定する方法もある(未検討)。 + +### CodeQL の挙動(踏んだので記録する) + +#### ① 棄却は、コードが動くと外れる + +**アラートの同一性は「ルール + 位置」で判定される。** +棄却した箇所の周辺を編集して行番号がずれると、 +**別のアラートとして作り直され、`open` に戻る。** + +`Encryption using ECB` がこれに当たった。棄却済みだったが、 +`#pragma warning disable` とコメントを足したことで **287 行 → 291 行**にずれ、 +新しい番号で `open` に戻ったため、**同じ理由で棄却し直した。** + +**棄却済みの箇所を触ったら、棄却が残っているかを確認すること。** + +#### ② `fixed` は「直った」とは限らない + +`#537` のマージ後、`fixed` が 12 件になったが、 +**本当に解消したのは `Missing X-Frame-Options` の 6 件だけ**だった。 + +``` +fixed 12 件 ≠ 12 件が直った + 6 件 解消(新しいアラートが出ていない) + 6 件 位置が変わっただけ(同数が open に出ている) +``` + +**`fixed` の件数だけを見て「減った」と判断してはならない。** +`open` の中身とあわせて確認する。 + +#### ③ PR のチェックと、ブランチ全体のスキャンは別物 + +**PR のチェックは差分中心で、ブランチ全体の状態とは一致しない。** + +- `#537` の `CodeQL` チェックは `fail` だったが、**新しい脆弱性ではなかった**。 + 行番号がずれた 2 件を「この PR で追加された」と数えたため +- 逆に、PR 時点では `'requireSSL'` が解消したように見えたが、 + **`develop` の全体スキャンでは残っていた** + +**判断は `develop`(既定ブランチ)のスキャン結果で行うこと。** + +#### ④ 検証を足してもアラートは消えないことがある + +`DOM text reinterpreted as HTML` に対して `Fx_IsSafeDialogUrl()` を追加したが、 +**CodeQL はこの関数をサニタイザと認識せず、指摘は残った。** + +**「アラートが消えること」と「安全になること」は別である。** + +| | アラート | 実際の安全性 | +|---|---|---| +| `'requireSSL'`(コメントで併記) | **消えない** | **変わらない**(有効な設定は `false` のまま) | +| `DOM text ...`(検証を追加) | **消えない** | **上がった**(危険なスキームを実際に弾く) | +| `X-Frame-Options`(ヘッダ追加) | **消えた** | **上がった** | + +**アラート件数を目的にすると判断を誤る。** 何を守りたいかで決めること。 + +--- + +## 2. ブランチと保護 + +| ブランチ | 役割 | 保護 | +|---|---|---| +| `develop` | 既定ブランチ。開発の集約先 | force-push 禁止 / 削除禁止 | +| `master` | リリース | 上記 + **レビュー 1 名必須** | +| `deps` | Dependabot PR の受け先 | なし | + +ブランチ運用は git-flow。**規約は [`Contributing.ja.md`](Contributing.ja.md)。** + +### 現状の弱点 + +- **`develop` に必須ステータス チェックは置かない**(意図的)。 + `deps` ⇔ `develop` ⇔ feature と往復が多く、毎回のマージが CI 待ちになるため。 + 代わりに **`master` 宛の PR で CI を動かす**(7 節) +- `master` の `enforce_admins` は無効(少人数運用のため意図的) +- `delete_branch_on_merge` は無効。マージ済みブランチが残る + +> **squash merge / rebase merge を許可している。** +> ただし **squash はコミットを消すため、NuGet パッケージの Source Link を壊す** +> ([`root/programs/CS/NuGet/README.md`](root/programs/CS/NuGet/README.md) 7 節)。 +> `master` へは `--no-ff` で入れること。**運用で担保している。** + +--- + +## 3. GitHub Actions + +### `.github/` の中身 + +| ファイル | 役割 | +|---|---| +| [`workflows/build-windows.yml`](.github/workflows/build-windows.yml) | 検証 3 本(ビルド・単体テスト・疎通)を windows-latest で | +| [`workflows/dependabot-retarget.yml`](.github/workflows/dependabot-retarget.yml) | Dependabot PR の向き先を `deps` へ変更 | +| [`secret_scanning.yml`](.github/secret_scanning.yml) | Secret scanning のアラートから除外するパス(1 節) | + +**`dependabot.yml` は置いていない**(4 節)。 + +### ワークフロー + +| ファイル | 発火 | `permissions` | +|---|---|---| +| `build-windows.yml` | `push: [deps]` / **`pull_request: [master]`** / 手動 | `contents: read` | +| `dependabot-retarget.yml` | `pull_request_target`(`opened`) | `pull-requests: write` | +| CodeQL(既定セットアップ) | GitHub 管理。`push` / `pull_request` / 週次 | ワークフロー ファイルを持たない | + +`build-windows.yml` は既知の署名エラー(`MSB3482` / `MSB3325` / `MSB3321`)を除外する。 +**ローカルと CI で出るコードが違う**理由はファイル冒頭のコメントにある。 + +> **`dependabot-retarget.yml` は `pull_request_target` を使う。** +> これは**ベース ブランチ側の定義を、書き込み権限付きで動かす**トリガである。 +> ここで PR のコードを `checkout` して実行すると、 +> **PR に任意のコードを書ける相手へ権限を渡すことになる**(pwn request)。 +> +> 本ワークフローは **`checkout` を行わず**、`gh` コマンドだけを実行し、 +> 権限も `pull-requests: write` の 1 つに絞っている。 +> **この 2 点は変更しないこと。** 理由はファイル冒頭のコメントにある。 + +### GitHub 側の設定 + +``` +Actions enabled +allowed_actions all … 使用できるアクションを制限していない +sha_pinning_required false … アクションの SHA 固定を強制していない +default_workflow_permissions read … 2026-08-10 に write から変更 +can_approve_pull_request_reviews false … 2026-08-10 に true から変更 +Secrets / Variables なし +``` + +**既定を `read` にした。** 各ワークフローは `permissions:` を明示して +最小権限にしているため、**既定を下げても動く**(実測で確認)。 +**`permissions:` を書き忘れた新しいワークフローが、 +書き込み権限を持ってしまう状態を無くすため。** + +> それでも**新しいワークフローを足すときは `permissions:` を書くこと。** +> 何を必要としているかが、ファイルを見て分かる方がよい。 + +**`can_approve_pull_request_reviews` も無効にした。** +Actions が PR を承認できると、`master` のレビュー必須が形骸化するため。 + +`Secrets` は 1 つも登録していない。**認証が要る操作は入れていない**ということであり、 +足すときは「本当に必要か」を先に考える。 + +--- + +## 4. Dependabot + +- **version updates はリポジトリに `.github/dependabot.yml` を置いていない**(GitHub UI 側の設定で稼働) +- PR は `dependabot-retarget.yml` が `deps` へ向け直す +- `deps` で CI を通してから `develop` へまとめてマージする + +> **`dependabot.yml` を置けば `target-branch: deps` を直接指定でき、 +> retarget ワークフローが不要になる可能性がある。** +> ただし retarget の実挙動が未検証のため保留(#517)。 + +--- + +## 5. 有効にしていない機能 + +| 機能 | 判断 | +|---|---| +| **Discussions** | **無効のまま。** Issue で回っており、有効にすると窓口が分散する | +| Projects | 有効だが未使用 | +| Wiki | 有効。[リリース エンジニアリング等の文書](https://github.com/OpenTouryoProject/OpenTouryo/wiki)を置いている | +| Auto-merge | 無効 | +| Web commit signoff | 無効 | + +--- + +## 6. 実行したコマンドの記録 + +**エージェントが `gh` で直接実行した設定変更。** 参照系(GET)は除く。 + +### 2026-08-10 : セキュリティ構成の作成と適用 + +前提として `admin:org` スコープが要る(**リポジトリ admin だけでは足りない**)。 + +```bash +gh auth refresh -h github.com -s admin:org # 対話的。人が実行 +``` + +構成の作成。 + +```bash +cat > cfg.json <<'JSON' +{ + "name": "OpenTouryo standard", + "description": "Secret scanning は有効、Push protection は棚卸し後に有効化する段階分け構成。non-provider patterns と validity checks は無効。", + "advanced_security": "enabled", + "dependency_graph": "enabled", + "dependabot_alerts": "enabled", + "dependabot_security_updates": "enabled", + "code_scanning_default_setup": "enabled", + "secret_scanning": "enabled", + "secret_scanning_push_protection": "disabled", + "secret_scanning_non_provider_patterns": "disabled", + "secret_scanning_validity_checks": "disabled", + "private_vulnerability_reporting": "enabled", + "enforcement": "unenforced" +} +JSON + +gh api -X POST orgs/OpenTouryoProject/code-security/configurations --input cfg.json +# → id 265927 +``` + +このリポジトリにのみ適用。 + +```bash +gh api -X POST orgs/OpenTouryoProject/code-security/configurations/265927/attach \ + -f scope=selected -F 'selected_repository_ids[]=18209571' +``` + +確認。 + +```bash +gh api repos/OpenTouryoProject/OpenTouryo --jq '.security_and_analysis' +gh api repos/OpenTouryoProject/OpenTouryo/private-vulnerability-reporting +gh api repos/OpenTouryoProject/OpenTouryo/code-scanning/default-setup --jq '{state, languages}' +gh api orgs/OpenTouryoProject/code-security/configurations/265927/repositories \ + --jq '.[] | {status, repo: .repository.full_name}' +``` + +### 2026-08-10 : Push protection の有効化 + +Secret scanning のアラートが 0 件で安定したことを確認した上で実施。 +**構成の値を変えるだけ**で、リポジトリ個別の設定は触らない。 + +```bash +gh api -X PATCH orgs/OpenTouryoProject/code-security/configurations/265927 \ + -f secret_scanning_push_protection=enabled + +# リポジトリ側へ反映されたかを確認する +gh api repos/OpenTouryoProject/OpenTouryo --jq '.security_and_analysis' +``` + +**戻すとき**も同じ形(`-f secret_scanning_push_protection=disabled`)。 + +### 2026-08-10 : Actions の既定権限を絞る + +**リポジトリ設定**(組織の構成ではない)。`repo` スコープで実行できる。 + +```bash +gh api -X PUT repos/OpenTouryoProject/OpenTouryo/actions/permissions/workflow -f default_workflow_permissions=read -F can_approve_pull_request_reviews=false + +# 確認 +gh api repos/OpenTouryoProject/OpenTouryo/actions/permissions/workflow +``` + +**下げる前に、各ワークフローが `permissions:` を明示しているかを確認すること。** +既定に頼っているワークフローがあると、権限不足で失敗する。 + +```bash +grep -A3 '^permissions:' .github/workflows/*.yml +``` + +### 有効化後の運用 + +**新しく push する内容だけ**が検査される。既存の履歴は対象外。 + +| | | +|---|---| +| 止まるもの | **発行元を特定できる形のキー**(NuGet の `oy2...`、AWS、GitHub PAT など) | +| 止まらないもの | `.pfx` / `.cer`、接続文字列の `Password=`(`Non-provider patterns` が無効のため) | + +止まった場合は理由を選んでバイパスできる(**管理者に通知され、記録が残る**)。 + +> **`.github/secret_scanning.yml` の除外は Push protection には効かない。** +> あちらはアラート(Secret scanning)の抑制であり、push の判定は見ていない。 + +--- + +## 7. 未着手の提案 + +| | 内容 | +|---|---| +| **`master` の CI 必須化** | `build-windows.yml` に `on: pull_request: branches: [master]` を足し、`master` のブランチ保護で必須チェックにする。**リリースの関所**として働く(下記) | +| `allowed_actions` を絞る / SHA 固定 | 現在 `all` / 強制なし。サプライ チェーン対策。**運用が重くなる**ので、必要性とあわせて判断する | +| `delete_branch_on_merge` | マージ済みブランチを自動削除する | +| `SECURITY.md` | Private vulnerability reporting は有効にしたが、文書は未整備 | +| Issue / PR テンプレート | 「調査 → 実装 → 検証」の型が定まっているのでテンプレート化できる | +| `.github/dependabot.yml` | #517 の決着後 | + +> **`develop` を必須チェックの対象にはしない。** +> `deps` ⇔ `develop` ⇔ feature と**往復が多いハブ**であり、 +> 毎回のマージが CI 待ちになる。 +> `deps` 由来の変更は**すでに `deps` で検証済み**なので、二度手間でもある。 +> +> **`master` は往復しない。** `develop` からのマージはリリース時だけで、 +> 1 回あたり 9 分程度の待ちは受け入れられる。 +> `RELEASE.md` フェーズ 1 の「検証 3 本」を、機械的に担保できる。 + diff --git a/README.md b/README.md index e328daf96..aa56059e6 100644 --- a/README.md +++ b/README.md @@ -7,29 +7,32 @@ Click [here](Readme.ja.md) for Japanese version of this file. The programs in this repository are developed in the following IDE/targetFramework: - IDE (Integrated Development Environment) - Visual Studio 2022 + Visual Studio 2026 - targetFramework (Run-time environment) - .NET Framework 4.8 (net48) - - .NET 8.0 (net8.0) + - .NET 10.0 (net10.0) -The name of projects and solutions include the targetFramework. -For example, the projects and solutions for net48(.NET Framework 4.8) are named {identifier}_net48.{ext}. +The name of projects and solutions include an identifier of the targetFramework. +For example, the projects and solutions for .NET Framework 4.8 are named {identifier}_net48.{ext}, +and the ones for .NET 10.0 are named {identifier}_netcore100.{ext}. + +## Documents +The documents of *Open Touryo* are stored in the [OpenTouryoDocuments](https://github.com/OpenTouryoProject/OpenTouryoDocuments) repository. -## Summary -Please refer to the following files. - [List of documents, Japanese Version](https://github.com/OpenTouryoProject/OpenTouryoDocuments/blob/master/documents/0_Introduction/ja-JP) - [Function List, Japanese Version (Excel)](https://github.com/OpenTouryoProject/OpenTouryoDocuments/blob/master/documents/0_Introduction/ja-JP/Functional_list.xlsx) -## Details -The documents are stored in [OpenTouryoDocuments](https://github.com/OpenTouryoProject/OpenTouryoDocuments) repository. -For more details, refer to the documents in [OpenTouryoDocuments](https://github.com/OpenTouryoProject/OpenTouryoDocuments) repository. - +Some of the documents are [available as a Wiki in this repository](https://github.com/OpenTouryoProject/OpenTouryo/wiki). ## Contents -### Directory - -#### [/license/](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/license) +### [/license/](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/license) License files are stored in this directory. -#### [/root/](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root) +### [/root/](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root) Programs, configuration files, sql files, and more are stored in this directory. + +For the setup and build steps, refer to [/root/README.md](root/README.md). + +### [AGENTS.md](AGENTS.md) +This is the **entry point** when working on this repository with a coding agent. +It summarizes the policies to follow and the links to the documents to refer to. diff --git a/Readme.ja.md b/Readme.ja.md index 385fe2ef5..8c4c44fa9 100644 --- a/Readme.ja.md +++ b/Readme.ja.md @@ -7,29 +7,32 @@ このリポジトリのプログラムは、以下のIDE/targetFramework を前提に開発しています。 - IDE(統合開発環境) - Visual Studio 2022 + Visual Studio 2026 - targetFramework(実行環境) - .NET Framework 4.8 (net48) - - .NET 8.0 (net8.0) + - .NET 10.0 (net10.0) -プロジェクトやソリューションの名前には、targetFrameworkが含まれます。 -たとえば、net48(.NET Framework 4.8) を対象としたプロジェクト・ソリューションは、"{identifier}_net48.{ext}" と命名しています。 +プロジェクトやソリューションの名前には、targetFramework の識別子が含まれます。 +たとえば、.NET Framework 4.8 を対象としたプロジェクト・ソリューションは "{identifier}_net48.{ext}"、 +.NET 10.0 を対象としたものは "{identifier}_netcore100.{ext}" と命名しています。 + +## 資料 +Open 棟梁のドキュメントは、[OpenTouryoDocuments リポジトリ](https://github.com/OpenTouryoProject/OpenTouryoDocuments)にあります。 -## 概要 -以下のファイルを参照してください。 - [資料一覧](https://github.com/OpenTouryoProject/OpenTouryoDocuments/blob/master/documents/0_Introduction/ja-JP) - [機能一覧 (Excel)](https://github.com/OpenTouryoProject/OpenTouryoDocuments/blob/master/documents/0_Introduction/ja-JP/Functional_list.xlsx) -## 詳細 -Open 棟梁のドキュメントは、[OpenTouryoDocuments リポジトリ](https://github.com/OpenTouryoProject/OpenTouryoDocuments)にあります。 -詳細は、[OpenTouryoDocuments リポジトリ](https://github.com/OpenTouryoProject/OpenTouryoDocuments)のドキュメントを参照してください。 - +一部の資料は[当該リポジトリ上でWiki化](https://github.com/OpenTouryoProject/OpenTouryo/wiki/Home.ja)されています。 ## 内容物 -### ディレクトリ - -#### [/license/](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/license) +### [/license/](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/license) このディレクトリには、ライセンスファイルが格納されています。 -#### [/root/](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root) +### [/root/](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root) このディレクトリには、プログラム、設定ファイル、SQL ファイルなどが格納されています。 + +セットアップとビルドの手順は [/root/Readme.ja.md](root/Readme.ja.md) を参照してください。 + +### [AGENTS.md](AGENTS.md) +コーディング エージェントで本リポジトリを扱う場合の**入口**です。 +守るべきポリシーと、参照すべき文書への導線をまとめています。 diff --git a/root/README.md b/root/README.md index fa33cc129..a336dd936 100644 --- a/root/README.md +++ b/root/README.md @@ -1,78 +1,53 @@ # Open Touryo ## Outline -*Open Touryo* is an application framework based on .NET Framework and .NET Core. -The programs of Open Touryo are available in the following repositories: -- OpenTouryoTemplates repository - - Summary - The programs in this repository are the *development infrastructure (project template)* of the programs using Open Touryo. - And the programs are partitioned into the folders for each version of Visual Studio. - - Intended User - The *application developers* using Open Touryo. -- OpenTouryo repository (*Current repository*) - - Summary - The programs in this repository are the *matrix* of OpenTouryoTemplates repository. - (First, the features of Open Touryo are implemented in this repository. And then, the features are introduced into OpenTouryoTemplates repository.) - - Intended User - *Open source developers*. - -Therefore, the users who use Open Touryo in a system development project need to use [OpenTouryoTemplates repository](https://github.com/OpenTouryoProject/OpenTouryoTemplates). -The following contents are the usage of Open Touryo for *open source developers*. - -Click [here](Readme.ja.md) for Japanese version of this file. - -## Running sample application tasks -You can run the sample application bundled with Open Touryo according to the following steps. - -Notation *Optional*: -Open Touryo supports the following DBMSs and data providers. But the data providers, having the notation *optional*, are not included in the programs of Open Touryo. When using the DBMSs and data providers having the notation *optional*, download the data provider manually, and modify [the data access project of Open Touryo, that is DamXXX.csproj](https://github.com/OpenTouryoProject/OpenTouryo/tree/develop/root/programs/CS/Frameworks/Infrastructure/Public/Db), to refer the data provider. +*Open Touryo* is an application framework based on .NET Framework and .NET Core. + +Click [here](Readme.ja.md) for the Japanese version of this file. + +## How to run the programs for developing Open Touryo itself +- The following are the steps to run Open Touryo itself and the sample applications bundled with it. +- For the setup to develop an application *using* Open Touryo, refer to [this repository](https://github.com/OpenTouryoProject/OpenTouryoCodingAgentAssets/). +- When developing Open Touryo itself with a coding agent, read [AGENTS.md](../AGENTS.md) first. ### Install prerequisites -Install Visual Studio 2015 beforehand. -If you develop for .NET Standard or .NET Core, install Visual Studio 2017 beforehand. -see: https://docs.microsoft.com/ja-jp/dotnet/core/windows-prerequisites - -Further, when implementing or testing the *data access class*, install the DBMS(s) to be used. -Open Touryo supports the following DBMSs: -- SQL Server -(You can use an arbitrary version of SQL Server. And you can use different editions than Express Edition.) -- Oracle Database (including Express Edition) -- IBM DB2 ... optional -- HiRDB ... optional -- MySQL -- PostgreSQL +- Install Visual Studio beforehand (or Visual Studio Code with the .NET SDK and extensions). + +- Also, prepare the DBMS to be used out of the ones supported by Open Touryo. [LocalServicesOnDocker](https://github.com/NetDevInfraWGinOSSConsortium/LocalServicesOnDocker) is useful for this. + +- The supported data providers can be checked in [Touryo.Infrastructure.Public.Db](https://github.com/OpenTouryoProject/OpenTouryo/tree/develop/root/programs/CS/Frameworks/Infrastructure/Public/Db). + +- The officially supported data providers are *SQL / OLE / ODBC / ODP / MCN / NPG*. + +- *DB2 / HiRDB / OracleClient* are currently excluded, but their templates remain, so you can support them yourself by making use of agents and so on. + +- The abbreviations and the namespaces of the ADO.NET data providers + - SQL: Microsoft.Data.SqlClient + - OLE: System.Data.Odbc + - ODBC: System.Data.OleDb + - ODP: Oracle.ManagedDataAccess.Client + - MCN: MySql.Data.MySqlClient + - NPG: Npgsql + - DB2: IBM.Data.DB2 + - HiRDB: Hitachi.HiRDB + - OracleClient: System.Data.OracleClient ### Deploy Open Touryo -Copy *root* folder to just under C drive. If not, the build may fail for the Windows maximum path length limitation. - -### Obtain and deploy data providers -The correspondence between the DBMSs and the data providers is as follows. - -- Oracle - - Oracle.DataAccess.dll ... optional - - Oracle.ManagedDataAccess.dll -- IBM DB2 - - IBM.Data.DB2.dll ... optional -- HiRDB - - x86: pddndp40.dll, pddndpcore40.dll ... optional - - x64: pddndp40x.dll, pddndpcore40x.dll ... optional -- MySQL - - MySql.Data.dll -- PostgreSQL - - Npgsql.dll - -### Set up sample database +Copy the *root* folder to just under the C drive. If you copy it elsewhere, the build may fail because of the Windows maximum path length limitation. + +### Set up the sample database + +#### Make use of [LocalServicesOnDocker](https://github.com/NetDevInfraWGinOSSConsortium/LocalServicesOnDocker) + #### SQL Server -Sample application requires *Northwind* database. -So, download the setup script installer of *Northwind* database from the following Microsoft site and install. +The sample applications require the *Northwind* database. +Download the setup script of the *Northwind* database from the following Microsoft site and install it. - - Download: NorthWind and pubs Sample Databases for SQL Server 2000 - Microsoft Download Center - http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=23654 +- Download: NorthWind and pubs Sample Databases for SQL Server 2000 - Microsoft Download Center + http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=23654 -When completing the installation, *SQL Server 2000 Sample Databases* folder is created in C drive. -When using SQL Server 2012 or later, open *instnwnd.sql* file in an editor and comment out the following code. -**Note**: -Because *sp_option* system stored procedure does not exist in SQL Server 2012 or later, this step is required. +When the installation succeeds, the *SQL Server 2000 Sample Databases* folder is created just under the C drive. +When using SQL Server 2012 or later, open the *instnwnd.sql* file in that folder with an editor and comment out the following code. (Because the *sp_dboption* system stored procedure does not exist in SQL Server 2012 or later) ```sql exec sp_dboption 'Northwind','trunc. log on chkpt.','true' @@ -80,449 +55,104 @@ exec sp_dboption 'Northwind','select into/bulkcopy','true' ``` Execute the following command at a command prompt. -**Note**: -In the following command, the path of the folder that contains *SQLCMD.EXE* changes according to the version of SQL Server. Execute command after confirming the path of folder in your environment. +(In the following command, the folder path of *SQLCMD.EXE* differs depending on the version of SQL Server. Confirm the folder path in your environment before executing the command) ```bat "C:\Program Files\Microsoft SQL Server\100\Tools\Binn\SQLCMD.EXE" -S localhost\SQLExpress -E -i "C:\SQL Server 2000 Sample Databases\instnwnd.sql" ``` -#### DBMSs except for SQL Server -- Create an empty database in each DBMSs. -- Create test table in the database by running C:\root\files\resource\Sql\\[DBMS Name]\TestTable.txt. - -### Build program -When using Open Touryo, it is necessary to build programs **by running the batch files using MSBuild only at the first time**. -**Note**: -Open Touryo Template Base contains two parts: -- Framework (Base class 1 and base class 2) -- Sample application (Subclass) - -It is necessary to copy the *deliverables generated by building*, that is, *dll files* to the default folder of Open Touryo. -Therefore, it is necessary to run the batch files which execute a series of build processes. - -The batch files are stored in the following folder: -- C:\root\programs\CS -- C:\root\programs\VB - -By executing `0_ExecAllBat.bat`, you can execute necessary batch files together. Refer to the table below, check the necessary batch to be executed, customize `0_ExecAllBat.bat` as necessary, and execute it. - -<table Border="1"> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;" colspan="1" rowspan="2">#</td> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;" colspan="1" rowspan="2">Batch file name </td> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;" colspan="1" rowspan="2">Description</td> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;" colspan="2" rowspan="1">Existence</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">C#</td> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">VB</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">1</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">0_ExecAllBat.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Perform a batch build using the following files: Customize as needed.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">2</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">1_DeleteDir.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Delete (Clean up) the folders that are generated by building.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">3</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">1_DeleteFile.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Delete (Clean up) the temporary files. </td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">4</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_net45.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the framework (Base class 1 and library part) to make NuGet package that targets .NET Framework 4.5.2. </td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">5</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_net46.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the framework (Base class 1 and library part) to make NuGet package that targets .NET Framework 4.6. </td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">6</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_net47.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the framework (Base class 1 and library part) to make NuGet package that targets .NET Framework 4.7. </td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">7</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_net48.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the framework (Base class 1 and library part) to make NuGet package that targets .NET Framework 4.8.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">8</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_netstd20.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the framework (Base class 1 and library part) to make NuGet package that targets .NET Standard 2.0. </td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">9</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_netstd21.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the framework (Base class 1 and library part) to make NuGet package that targets .NET Standard 2.1.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">10</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_nettcore30.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the framework (Base class 1 and library part) to make NuGet package that targets .NET Core 3.0.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">10</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_nettcore50.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the framework (Base class 1 and library part) to make NuGet package that targets .NET 5.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">10</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_nettcore60.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the framework (Base class 1 and library part) to make NuGet package that targets .NET 6.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">11</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_net45.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework (base class 2, library part) of Business namespace that targets .NET Framework 4.5.2.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">12</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_net46.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework (base class 2, library part) of Business namespace that targets .NET Framework 4.6.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">13</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_net47.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework (base class 2, library part) of Business namespace that targets .NET Framework 4.7.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">14</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_net48.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework (base class 2, library part) of Business namespace that targets .NET Framework 4.8.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">15</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_net45.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework for rich client application (base class 2, library part) of Business namespace that targets .NET Framework 4.5.2.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*2</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">16</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_net46.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework for rich client application (base class 2, library part) of Business namespace that targets .NET Framework 4.6.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*2</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">17</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_net47.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework for rich client application (base class 2, library part) of Business namespace that targets .NET Framework 4.7.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*2</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">18</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_net48.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework for rich client application (base class 2, library part) of Business namespace that targets .NET Framework 4.8.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*2</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">19</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_netcore20.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework (base class 2, library part) of Business namespace that targets .NET Core 2.0.</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">20</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_netcore30.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework (base class 2, library part) of Business namespace that targets .NET Core 3.0.</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">20</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_netcore50.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework (base class 2, library part) of Business namespace that targets .NET 5.</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">20</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_netcore60.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework (base class 2, library part) of Business namespace that targets .NET 6.</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">21</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_netcore30.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework for rich client application (base class 2, library part) of Business namespace that targets .NET Core 3.0.</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*2, *3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">21</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_netcore50.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework for rich client application (base class 2, library part) of Business namespace that targets .NET 5.</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*2, *3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">21</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_netcore60.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build a framework for rich client application (base class 2, library part) of Business namespace that targets .NET 6.</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*2, *3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">22</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">4_Build_CopyAssemblies.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Copy the primary output of the above build to the reference folder.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">23</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">4_Build_Framework_Tool.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Framework-based tools bundled with Open Touryo.</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">24</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">4_Build_Framework_ToolCore.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Core-based tools bundled with Open Touryo.</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">25</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">5_Build_Bat_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Framework-based sample application. (Batch application)</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">26</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">5_Build_BatCore_sample.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Core-based sample application. (Batch application)</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">27</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">5_Build_2CS_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Framework-based sample application. (Two-tier client server application)</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">28</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">5_Build_2CSCore_sample.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Core-based sample application. (Two-tier client server application)</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">29</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">6_Build_WSSrv_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Framework-based sample application. (Web services (Server-side logic))</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">30</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">6_Build_WSSrvCore_sample.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Core-based sample application. (Web services (Server-side logic))</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">31</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">7_Build_Framework_WS.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Framework-based framework. (Service interface)</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">32</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">7_Build_Framework_WSCore.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Core-based framework. (Service interface)</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">33</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">8_Build_WSClnt_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Framework-based sample application. (Web service client) </td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">34</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">8_Build_WSClntCore_sample.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the .NET Core-based sample application. (Web service client) </td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">35</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">10_Build_WebApp_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the sample web application. (ASP.NET)</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">36</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">10_Build_WebAppCore_sample.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build the sample web application. (ASP.NET Core)</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">37</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">99_BuildLibsAtOtherRepos.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Batch file for to use the Business namespace of the repository in other repositories. (using OpenTouryoTemplates-master branch)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">38</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">99_BuildLibsAtOtherReposInTimeOfDev.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Batch file for to use the Business namespace of the repository in other repositories. (using OpenTouryo-develop branch)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">39</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Perform batch build and execution of the following test code.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">40</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode_Public.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build and execute the test code of the following Public namespace.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">41</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode_SecCUI.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build and execute the CUI test code of the following Public.Security namespace.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">42</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode_SecCUI.sh</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build and execute the CUI test code of the following Public.Security namespace usin WSL.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">43</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode_SecGUI.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Build and execute the GUI test code of the following Public.Security namespace.</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">44</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_ChangePackages_net45.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Batch file to switch packages.config when creating NuGet package. (for .NET Framework 4.5.2)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">45</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_ChangePackages_net46.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Batch file to switch packages.config when creating NuGet package. (for .NET Framework 4.6)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">46</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_ChangePackages_net47.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Batch file to switch packages.config when creating NuGet package. (for .NET Framework 4.7)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">47</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_ChangePackages_net48.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Batch file to switch packages.config when creating NuGet package. (for .NET Framework 4.8)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">48</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_Common.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Common settings (for MSBuild)</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">49</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_Common2.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Common settings (for Visual Studio)</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -</table> - -<div style="font-size: small"> - <span style="color: red;">*1</span> Need to run when making NuGet package.<br /> - <span style="color: red;">*2</span> Need to run when developing rich client application.<br /> - <span style="color: red;">*3</span> Need to run when developing application that targets .NET Standard or .NET Core.<br /> - <span style="color: red;">*4</span> Select according to the actual architecture. -</div> - -- If necessary, revise the environment variable *BUILDFILEPATH* in z_Common.bat according to the build environment. - -- The libraries which are used by Open Touryo Template Base for Visual Studio 2015 are downloaded by NuGet. NuGet libraries might not be downloaded normally under proxy environment. So, when using proxy environment, create environment variable *http_proxy* as follows: - - Open *C:\root\programs\CS\z_Common.bat* and *C:\root\programs\VB\z_Common.bat* in an editor. - - By default, the code which creates environment variable *http_proxy* is commented. - So, uncomment this code by removing '@rem'. - - Set your proxy information in environment variable *http_proxy*. - -- When the following error occurred at build time, install *Windows SDK for Windows 8*. (Refer to [issue of Open Touryo](https://github.com/OpenTouryoProject/OpenTouryoTemplates/issues/48#issuecomment-241349223).) -``` -C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(2863,5): error MSB3086: Task could not find "AL.exe" using the SdkToolsPath "" or the registry key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0A\WinSDK-NetFx40Tools-x86". Make sure the SdkToolsPath is set and the tool exists in the correct processor specific location under the SdkToolsPath and that the Microsoft Windows SDK is installed +#### DBMSs other than SQL Server +- Create an empty database in each DBMS. +- Create the tables for testing by running C:\root\files\resource\Sql\\[DBMS name]\TestTable.txt. + +### Build the programs +- To build the programs of Open Touryo, run the build batch files. + +- The build batch files are stored in the following folders. + - C:\root\programs\ + - C:\root\programs\CS + - C:\root\programs\VB + +#### Structure of the build batch files + +**The number at the beginning of a file name indicates the build order.** +The build proceeds from the smaller numbers, stacking up in the order of +infrastructure, tools, and then sample applications. + +| Number | Role | +|---|---| +| `0_` | Batch execution (`0_ExecAllBat.bat` calls the following in order) | +| `1_` | Clean up (deleting `bin` / `obj` / `packages` and so on) | +| `2_` | Framework itself (the assemblies to be packed into NuGet packages) | +| `3_` | Business layer (the base classes and templates for business code) | +| `4_` | Copying assemblies for reference, and the bundled tools | +| `5_` `6_` `8_` `10_` | Sample applications | +| `7_` | Service interface for web services (on the framework side) | +| `9_` | (Not used on the C# side. Used for the WPF client on the VB side) | +| `y_` | Test code | +| `z_` | Common processing (called from the beginning of each batch file. Not run by itself) | + +- **By executing `0_ExecAllBat.bat`, everything from the infrastructure to the + sample applications is built.** The individual batch files are for rebuilding only a part. +- **`y_` (the test code) is not included in `0_ExecAllBat.bat`.** To run the unit tests, + use `2_RunAllTests.ps1` described below, or run the `y_` batch files individually. +- The file names containing `Core`, or `netcore100`, target .NET 10.0. + The others (`net48`) target .NET Framework 4.8. +- **The clean up of `1_` is executed repeatedly**, because the infrastructure and the + sample applications are rebuilt at different timings. Therefore, when the whole build + has finished, no intermediate files remain except for the ones built last. + +#### Common processing (z_Common.bat) + +- Each batch file calls `z_Common.bat` at its beginning, which provides the following: + - **Resolving the build tool** ... MSBuild is located by `vswhere` (independent of the edition) + - **Build configuration** ... `BUILD_CONFIG` (Debug / Release) and `DEBUG_TYPE` + - **NuGet settings** ... the proxy, and the MSBuild to be used on restore + +- `z_Common2.bat` is the **devenv version** of the same. It remains for the cases where + a build does not pass with MSBuild but passes with devenv. Normally it is not used. + +- The libraries used by Open Touryo are downloaded via NuGet. Therefore, the NuGet libraries might not be downloaded normally under a proxy environment. When using a proxy environment, define the *http_proxy* environment variable as follows. + - Open C:\root\programs\CS\z_Common.bat and C:\root\programs\VB\z_Common.bat with a text editor. + - By default, the part that defines the *http_proxy* environment variable is commented out, so remove "@rem" to uncomment it. + - Set your proxy information in the *http_proxy* environment variable. + +#### Verification after the build + +Confirming that the build passes, running the unit tests, and checking that the sample +applications work can be done with the scripts in `C:\root\programs\`. +**All of them report the result by their exit code.** + +```powershell +cd C:\root\programs +.\0_RunAll.ps1 # Runs the following three together ``` - -### Start ASP.NET state service -Open a command prompt as an administrator and execute the following commands. + +| Script | Description | +|---|---| +| `1_BuildAll.ps1` | Builds everything (equivalent to `0_ExecAllBat.bat`), aggregating errors and warnings | +| `2_RunAllTests.ps1` | Runs the unit tests and compares the results with the previous ones | +| `3_SmokeTest.ps1` | Starts the sample applications and checks that they work | + +For the procedures and the criteria, refer to +[`BUILDING.md`](programs/BUILDING.md) / [`TESTING.md`](programs/TESTING.md) / +[`SMOKETEST.md`](programs/SMOKETEST.md) in the same folder. +The whole release procedure is summarized in [`RELEASE.md`](programs/RELEASE.md). + +### Start the ASP.NET state service +Open a command prompt as an administrator and execute the following commands. ```bat sc config aspnet_state start= auto net start aspnet_state ``` -### Run the sample application -Open the following file. -- Open web.config or app.config (for .NET Core, appsettings.json) and revise the values in *connectionStrings* section according to the actual database environment. +### Run the sample applications +- Open the following files. +- Open web.config or app.config (appsettings.json in the case of .NET Core), and +modify the values of the connectionString section according to your actual database environment. - Run the sample application. -At the login screen, enter the arbitrary alphanumeric characters. (By default, the password authentication is not executed.) +If a login screen appears, enter arbitrary alphanumeric characters. (Password authentication is not performed by default) -#### Web application: +#### Web applications: - ASP.NET Web Forms - C:\root\programs\CS\Samples\WebApp_sample\WebForms_Sample\WebForms_Sample.sln - C:\root\programs\VB\Samples\WebApp_sample\WebForms_Sample\WebForms_Sample.sln @@ -530,7 +160,7 @@ At the login screen, enter the arbitrary alphanumeric characters. (By default, t - C:\root\programs\CS\Samples\WebApp_sample\MVC_Sample\MVC_Sample.sln - C:\root\programs\VB\Samples\WebApp_sample\MVC_Sample\MVC_Sample.sln -#### Two-tier client server application: +#### Two-tier client server applications: - Windows Forms - C:\root\programs\CS\Samples\2CS_sample\2CSClientWin_sample\2CSClientWin_sample.sln - C:\root\programs\VB\Samples\2CS_sample\2CSClientWin_sample\2CSClientWin_sample.sln @@ -538,9 +168,9 @@ At the login screen, enter the arbitrary alphanumeric characters. (By default, t - C:\root\programs\CS\Samples\2CS_sample\2CSClientWPF_sample\2CSClientWPF_sample.sln - C:\root\programs\VB\Samples\2CS_sample\2CSClientWPF_sample\2CSClientWPF_sample.sln -#### Three-tier client server application: +#### Three-tier client server applications: - Windows Forms - - Windows forms application + - Ordinary Windows Forms application - C:\root\programs\CS\Samples\WS_sample\WSClient_sample\WSClientWin_sample\WSClientWin_sample.sln - C:\root\programs\VB\Samples\WS_sample\WSClient_sample\WSClientWin_sample\WSClientWin_sample.sln - ClickOnce application @@ -549,48 +179,39 @@ C:\root\programs\CS\Samples\WS_sample\WSClient_sample\WSClientWinCone_sample\WSC - C:\root\programs\CS\Samples\WS_sample\WSClient_sample\WSClientWPF_sample\WSClientWPF_sample.sln - C:\root\programs\VB\Samples\WS_sample\WSClient_sample\WSClientWPF_sample\WSClientWPF_sample.sln -### .NET Core application +### .NET Core applications + +**There is currently no plan to provide a .NET Core version for VB.** All of the following are for C# only. #### Infrastructure: -- C# - - C:\root\programs\CS\Frameworks\Infrastructure - - C:\root\programs\CS\Frameworks\Infrastructure\ServiceInterface\ASPNETWebServiceCore -- VB -... +- C:\root\programs\CS\Frameworks\Infrastructure +- C:\root\programs\CS\Frameworks\Infrastructure\ServiceInterface\ASPNETWebServiceCore #### Tools: -- C# - - C:\root\programs\CS\Frameworks\Tools -- VB -... +- C:\root\programs\CS\Frameworks\Tools + +#### Sample applications: +- C:\root\programs\CS\Samples4NetCore -#### Sample application: -- C# - - C:\root\programs\CS\Samples4NetCore -- VB -... ## Other items of note ### Copyright and license -Refer to [License](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/license) directory. +Refer to the [License](https://github.com/OpenTouryoProject/OpenTouryo/tree/master/license) directory. ### Bug fix -If you find the bug while you are using Open Touryo, create an new [issue](https://github.com/OpenTouryoProject/OpenTouryo/issues). -Open Touryo community confirms the issue and takes appropriate actions. - -### How to create NuGet packages -For the method of creating Open Touryo NuGet packages, see [this article](https://github.com/OpenTouryoProject/OpenTouryo/wiki/HowToCreateOpenTouryoNuGetPackages). +If you find a bug while using Open Touryo, report it as an [issue](https://github.com/OpenTouryoProject/OpenTouryo/issues). +The community will check the content and deal with it appropriately. -### Obtaining libraries, exporting control prodedures, attaching to license -- The libraries that can be obtained from package manager, that is NuGet or npm, are not bundled in Open Touryo. So, you don't have to export the libraries. -- If necessary, you have to obtain and export the other libraries, that is the libraries that can not be obtained from package manager, on your own. In this case, you have to attach the license of the libraries to be used to the license of Open Touryo. +### Obtaining libraries, export control procedures, and attaching to the license +- The libraries that can be obtained from a package manager such as NuGet or npm are not bundled with Open Touryo, so they do not need export control. +- The other libraries, that is, the ones that cannot be obtained from a package manager, need to be obtained, bundled, and exported by yourself as necessary. In that case, the licenses of the libraries you use need to be attached to the license of Open Touryo. ### Reference -The documents in *OpenTouryoDocument repository* are useful when using Open Touryo. +The documents in the OpenTouryoDocuments repository are available for using Open Touryo. - [Introduction](https://github.com/OpenTouryoProject/OpenTouryoDocuments/tree/master/documents/0_Introduction) -You can see the introduction materials, such as PowerPoint slides. +The overview documents of Open Touryo (PowerPoint slides and so on). - [User Guide](https://github.com/OpenTouryoProject/OpenTouryoDocuments/tree/master/documents/1_User_Guide) -You can confirm the structure of Open Touryo and the specification of each feature. +The mechanism of Open Touryo and the specifications of each feature. - [Tutorial](https://github.com/OpenTouryoProject/OpenTouryoDocuments/tree/master/documents/2_Tutorial) -You can see the *first step guide* of Open Touryo. +The first step guide of Open Touryo. diff --git a/root/Readme.ja.md b/root/Readme.ja.md index ac55b6e03..4170bf382 100644 --- a/root/Readme.ja.md +++ b/root/Readme.ja.md @@ -1,66 +1,44 @@ # Open 棟梁 ## 概要 -Open 棟梁は、.NET Framework と .NET Core をベースとしたアプリケーション フレームワークです。 -Open 棟梁のプログラムは、以下のリポジトリで公開しています。 -- OpenTouryoTemplates リポジトリ - - 概要 - Open 棟梁を使用したアプリケーションの**開発基盤 (テンプレート)** となるもので、 - Visual Studio のバージョンごとにフォルダが分かれている - - 想定利用者 - Open 棟梁を使用してアプリケーションを開発する人 -- OpenTouryo リポジトリ (**現在のリポジトリ**) - - 概要 - OpenTouryoTemplates リポジトリの**母体**となるもの - (Open 棟梁の各機能は、まず OpenTouryo リポジトリで開発され、 - その後 OpenTouryoTemplates リポジトリに取り込まれる) - - 想定利用者 - OSS 開発者 - -このため、システム開発プロジェクトで Open 棟梁を使用される方は、[OpenTouryoTemplates リポジトリ](https://github.com/OpenTouryoProject/OpenTouryoTemplates)を使用してください。以下、**OSS 開発者向け**に、Open 棟梁の利用方法をご紹介します。 +Open 棟梁は、.NET Framework と .NET Core をベースとしたアプリケーション フレームワークです。 このファイルの英語版は[こちら](README.md)から。 -## サンプルの実行手順 -Open 棟梁に同梱されるサンプルアプリケーションの実行手順は以下のとおりです。 - -**Optional 表記:** -以下、optional 表記のある DBMS とデータプロバイダは、Open 棟梁でサポートされていますが、Open 棟梁のプログラムには含まれていません。そのため、optional 表記のある DBMS とデータプロバイダを使う場合、必要に応じてデータプロバイダを手動でダウンロードし、[Open 棟梁のデータアクセス用のプロジェクト (DamXXX.csproj)](https://github.com/OpenTouryoProject/OpenTouryo/tree/develop/root/programs/CS/Frameworks/Infrastructure/Public/Db) から、当該データプロバイダに参照設定を張り直してください。 +## 本体開発用プログラムの実行手順 +- Open 棟梁の本体と同梱されるサンプルアプリの実行手順は以下のとおりです。 +- Open 棟梁を使用したアプリ開発を行う場合のセットアップは[コチラ](https://github.com/OpenTouryoProject/OpenTouryoCodingAgentAssets/)をご参照下さい。 +- コーディング エージェントで本体開発を行う場合は、先に [AGENTS.md](../AGENTS.md) をお読みください。 ### 前提ツールのインストール -あらかじめ、Visual Studio 2015 をインストールしておいてください。 -.NET Standard、.NET Core開発を行う場合は、Visual Studio 2017 をインストールしておいてください。 -参考: https://docs.microsoft.com/ja-jp/dotnet/core/windows-prerequisites - -また、Open 棟梁がサポートしている以下の DBMS へのデータアクセスクラスの開発・テストを行う場合は、使用する DBMS をインストールしてください。 -- SQL Server -(SQL Server のバージョンは任意です。また、エディションについては、Express Edition 以外もお使いいただけますが、サンプルアプリケーションに指定する接続文字列を修正する必要がありますので、ご注意ください) -- Oracle Database (Express Edition を含みます) -- IBM DB2 ... optional -- HiRDB ... optional -- MySQL -- PostgreSQL +- あらかじめ、Visual Studio (若しくは Visual Studio Code と .NET系の SDK と Extension)をインストールしておいてください。 + +- また、Open 棟梁がサポートしている DBMS 中から使用するものを準備してください。[LocalServicesOnDocker](https://github.com/NetDevInfraWGinOSSConsortium/LocalServicesOnDocker) が便利です。 + +- サポートしている データプロバイダは、[Touryo.Infrastructure.Public.Db](https://github.com/OpenTouryoProject/OpenTouryo/tree/develop/root/programs/CS/Frameworks/Infrastructure/Public/Db) から確認できます。 + +- 正式サポートされているデータプロバイダは「SQL/OLE/ODBC/ODP/MCN/NPG」です。 + +- 現在は除外されていますが「DB2/HiRDB/OracleClient」は雛形があるのでエージェントなどを活用してセルフ・サポートすることは可能です。 + +- 略号とADO.NETデータプロバイダの名前空間 + - SQL:Microsoft.Data.SqlClient + - OLE:System.Data.Odbc + - ODBC:System.Data.OleDb + - ODP:Oracle.ManagedDataAccess.Client + - MCN:MySql.Data.MySqlClient + - NPG:Npgsql + - DB2:IBM.Data.DB2 + - HiRDB:Hitachi.HiRDB + - OracleClient:System.Data.OracleClient ### Open 棟梁の配置 「root」フォルダを、C ドライブ直下にコピーしてください。C ドライブ直下以外にコピーすると、Windows のファイルパスの最大文字長の制限により、ビルドに失敗することがあります。 -### データプロバイダの取得と配置 -Open 棟梁が現在サポートしているデータベースと、対応するデータプロバイダは以下のとおりです。 - -- Oracle - - Oracle.DataAccess.dll ... optional - - Oracle.ManagedDataAccess.dll -- IBM DB2 - - IBM.Data.DB2.dll ... optional -- HiRDB - - x86: pddndp40.dll, pddndpcore40.dll ... optional - - x64: pddndp40x.dll, pddndpcore40x.dll ... optional -- MySQL - - MySql.Data.dll -- PostgreSQL - - Npgsql.dll - ### サンプルデータベースのセットアップ + +#### [LocalServicesOnDocker](https://github.com/NetDevInfraWGinOSSConsortium/LocalServicesOnDocker)を活用 + #### SQL Server サンプルアプリケーションの実行には、Northwind データベースが必要です。 以下のマイクロソフトのサイトから、Northwind データベースのセットアップ スクリプトをダウンロードし、インストールしてください。 @@ -87,418 +65,77 @@ exec sp_dboption 'Northwind','select into/bulkcopy','true' - C:\root\files\resource\Sql\\[DBMS 名]\TestTable.txt を実行し、テスト用のテーブルを作成してください。 ### プログラムのビルド -Open 棟梁のプログラムをビルドするときは、**初回のみ、MSBuild を使用したビルドバッチファイルを実行**して、プログラムをビルドします。 -これは、Open 棟梁のテンプレート・ベースには、「フレームワーク部分 (ベースクラス1,2)」と「サンプルアプリケーション」がありますが、フレームワーク部分のビルド生成物 (DLL ファイル) を Open 棟梁の既定の置き場にコピーするなどの処理が必要なためです。 -これらの一連のビルドプロセスをまとめたバッチファイルを実行します。 - -ビルドバッチファイルは、以下のフォルダにあります。 -- C:\root\programs\CS -- C:\root\programs\VB - -`0_ExecAllBat.bat` を実行すると、必要なバッチファイルをまとめて実行することができます。下の表を参考に、実行する必要のあるバッチファイルをご確認いただき、必要に応じて `0_ExecAllBat.bat` をカスタマイズした上で実行してください。 - -<table Border="1"> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;" colspan="1" rowspan="2">#</td> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;" colspan="1" rowspan="2">バッチファイル名</td> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;" colspan="1" rowspan="2">説明</td> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;" colspan="2" rowspan="1">存在</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">C#</td> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">VB</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">1</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">0_ExecAllBat.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">以下のファイルを使用してバッチビルドを行う。必要に応じてカスタマイズしてください。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">2</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">1_DeleteDir.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">ビルドによってできたフォルダを削除 (クリーンアップ) する。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">3</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">1_DeleteFile.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">一時ファイルなどを削除 (クリーンアップ) する。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">4</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_net45.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.5.2 をターゲットとする NuGet パッケージの作成用に、フレームワーク (ベースクラス1, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">5</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_net46.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.6 をターゲットとする NuGet パッケージの作成用に、フレームワーク (ベースクラス1, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">6</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_net47.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.7 をターゲットとする NuGet パッケージの作成用に、フレームワーク (ベースクラス1, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">7</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_net48.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.8 をターゲットとする NuGet パッケージの作成用に、フレームワーク (ベースクラス1, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">8</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_netstd20.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Standard 2.0 をターゲットとする NuGet パッケージの作成用に、フレームワーク (ベースクラス1, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">9</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_netstd21.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Standard 2.1 をターゲットとする NuGet パッケージの作成用に、フレームワーク (ベースクラス1, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">10</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_nettcore30.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Core 3.0 をターゲットとする NuGet パッケージの作成用に、フレームワーク (ベースクラス1, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">10</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_nettcore50.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET 5 をターゲットとする NuGet パッケージの作成用に、フレームワーク (ベースクラス1, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">10</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">2_Build_NuGet_nettcore60.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET 6 をターゲットとする NuGet パッケージの作成用に、フレームワーク (ベースクラス1, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*1, *3</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">11</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_net45.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.5.2 をターゲットとする Business名前空間のフレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">12</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_net46.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.6 をターゲットとする Business名前空間のフレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">13</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_net47.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.7 をターゲットとする Business名前空間のフレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">14</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_net48.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.8 をターゲットとする Business名前空間のフレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">15</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_net45.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.5.2 をターゲットとする Business名前空間のリッチクライアント用フレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*2</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">16</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_net46.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.6 をターゲットとする Business名前空間のリッチクライアント用フレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*2</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">17</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_net47.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.7 をターゲットとするBusiness名前空間のリッチクライアント用フレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*2</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">18</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_net48.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Framework 4.8 をターゲットとするBusiness名前空間のリッチクライアント用フレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*2</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">19</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_netcore20.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Core 2.0 をターゲットとする Business名前空間のフレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">20</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_netcore30.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Core 3.0 をターゲットとする Business名前空間のフレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">20</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_netcore50.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET 5 をターゲットとする Business名前空間のフレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">20</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_Business_netcore60.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET 6 をターゲットとする Business名前空間のフレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">21</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_netcore30.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Core 3.0 をターゲットとする Business名前空間のリッチクライアント用フレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*2, *3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">21</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_netcore50.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET 5 をターゲットとする Business名前空間のリッチクライアント用フレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*2, *3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">21</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">3_Build_BusinessRichClient_netcore60.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET 6 をターゲットとする Business名前空間のリッチクライアント用フレームワーク (ベースクラス2, ライブラリ部分) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*2, *3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">22</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">4_Build_CopyAssemblies.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">上記ビルドのプライマリ出力を参照先フォルダにコピーする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">23</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">4_Build_Framework_Tool.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Frameworkベースの付属ツールをビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">24</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">4_Build_Framework_ToolCore.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Coreベースの付属ツールをビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">25</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">5_Build_Bat_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Frameworkベースのサンプルアプリ (バッチ) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">26</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">5_Build_BatCore_sample.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Coreベースのサンプルアプリ (バッチ) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">27</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">5_Build_2CS_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Frameworkベースのサンプルアプリ (2 層 C/S) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">28</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">5_Build_2CSCore_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Coreベースのサンプルアプリ (2 層 C/S) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">29</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">6_Build_WSSrv_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Frameworkベースのサンプルアプリ (Web サービス (サーバー側ロジック)) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">30</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">6_Build_WSSrvCore_sample.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Coreベースのサンプルアプリ (Web サービス (サーバー側ロジック)) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">31</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">7_Build_Framework_WS.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Frameworkベースのフレームワーク (サービスインタフェース部分) をビルドする。 </td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">32</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">7_Build_Framework_WSCore.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Coreベースのフレームワーク (サービスインタフェース部分) をビルドする。 </td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">33</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">8_Build_WSClnt_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Frameworkベースのサンプルアプリ (Web サービスクライアント) をビルドする。</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">34</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">8_Build_WSClntCore_sample.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">.NET Coreベースのサンプルアプリ (Web サービスクライアント) をビルドする。</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">35</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">10_Build_WebApp_sample.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">サンプルWebアプリ (ASP.NET) をビルドする。 </td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;" colspan="2" rowspan="1">○*4</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">36</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">10_Build_WebAppCore_sample.bat</td> -<Td style="background-color:#F8CBAD;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">サンプルWebアプリ (ASP.NET Core) をビルドする。 </td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○*3, *4</td> -<Td style="background-color:#F8CBAD;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">37</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">99_BuildLibsAtOtherRepos.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">当該リポジトリのBusiness名前空間を他のリポジトリで利用する際のバッチ(OpenTouryoTemplates - master ブランチ用)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">38</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">99_BuildLibsAtOtherReposInTimeOfDev.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">当該リポジトリのBusiness名前空間を他のリポジトリで利用する際のバッチ(OpenTouryo - develop ブランチ用)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">39</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">以下のテストコードのバッチビルドと実行を行う。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">40</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode_Public.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">以下のPublic名前空間のテストコードのビルドと実行を行う。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">41</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode_SecCUI.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Public.Security名前空間のCUIテストコードのビルドと実行を行う。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">42</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode_SecCUI.sh</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Public.Security名前空間のCUIテストコードのビルドと実行を行う(WSL用)。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">43</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">y_Build_TestCode_SecGUI.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">Public.Security名前空間のGUIテストコードのビルドと実行を行う。</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">44</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_ChangePackages_net45.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">NuGet パッケージの作成時に、packages.config切り替えるバッチ(.NET Framework 4.5.2)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">45</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_ChangePackages_net46.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">NuGet パッケージの作成時に、packages.config切り替えるバッチ(.NET Framework 4.6)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">46</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_ChangePackages_net47.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">NuGet パッケージの作成時に、packages.config切り替えるバッチ(.NET Framework 4.7)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">47</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_ChangePackages_net48.bat</td> -<Td style="background-color:#C6E0B4;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">NuGet パッケージの作成時に、packages.config切り替えるバッチ(.NET Framework 4.8)</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#C6E0B4;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">-</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">48</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_Common.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">共通設定 (MSBuild 用)</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -<tr> -<Td style="background-color:#9BC2E6;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;font-weight:bold;">49</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">z_Common2.bat</td> -<Td style="background-color:#FFFFFF;text-align:left;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">共通設定 (Visual Studio 用) </td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -<Td style="background-color:#FFFFFF;text-align:center;color:#000000;font-family:'MS Pゴシック';font-size:11pt;">○</td> -</tr> -</table> - -<div style="font-size: small"> - <span style="color: red;">*1</span> NuGetパッケージを作成を作成する場合は必須<br /> - <span style="color: red;">*2</span> リッチクライアント アプリケーションを作成する場合は必須<br /> - <span style="color: red;">*3</span> .NET Standard、.NET Core ベースのアプリケーションを開発する場合は必須<br /> - <span style="color: red;">*4</span> 実際のアプリケーションの形態に応じて選択してください -</div> - -- 必要であれば、環境に合わせて、z_Common.bat 内の BUILDFILEPATH を書き換えてください。 +- Open 棟梁のプログラムをビルドするときは、ビルドバッチファイルを実行してビルドします。 + +- ビルドバッチファイルは、以下のフォルダにあります。 + - C:\root\programs\ + - C:\root\programs\CS + - C:\root\programs\VB + +#### ビルドバッチの構成 + +ビルドバッチは**ファイル名の先頭の番号がビルド順**を表しています。 +番号の小さいものから順に、基盤 → ツール → サンプルの順で積み上がる構成です。 + +| 番号 | 役割 | +|---|---| +| `0_` | 一括実行(`0_ExecAllBat.bat` が以下を順に呼び出します) | +| `1_` | クリーン(`bin` / `obj` / `packages` などの削除) | +| `2_` | フレームワーク本体(NuGet パッケージ化の対象となるアセンブリ) | +| `3_` | Business 層(業務コードの親クラス/テンプレート) | +| `4_` | 参照用アセンブリのコピー、付属ツール | +| `5_` `6_` `8_` `10_` | 各種サンプルアプリケーション | +| `7_` | Web サービスの受け口(フレームワーク側) | +| `9_` | (C# 側では未使用。VB 側で WPF クライアントに使用) | +| `y_` | 単体テストのコード | +| `z_` | 共通処理(各バッチの先頭から呼ばれます。単体では実行しません) | + +- **`0_ExecAllBat.bat` を実行すれば、基盤からサンプルまでが一括でビルドされます。** + 個別のバッチは、一部だけを作り直したいときに使います。 +- **`y_`(単体テスト)は `0_ExecAllBat.bat` に含まれません。** 単体テストを動かす場合は、 + 後述の `2_RunAllTests.ps1` を使うか、`y_` のバッチを個別に実行します。 +- ファイル名に `Core` が付くもの、または `netcore100` を含むものが .NET 10.0 向け、 + 付かないもの(`net48`)が .NET Framework 4.8 向けです。 +- `1_` のクリーンは**繰り返し実行されます**。基盤とサンプルを別々のタイミングで + 作り直すためで、このため全体をビルドし終えた時点では、 + 最後にビルドされたもの以外の中間生成物は残りません。 + +#### 共通処理(z_Common.bat) + +- 各バッチは先頭で `z_Common.bat` を呼び、次を用意します。 + - **ビルドツールの解決** … `vswhere` で MSBuild を探します(エディションに依存しません) + - **ビルド構成** … `BUILD_CONFIG`(Debug / Release)と `DEBUG_TYPE` + - **NuGet の設定** … プロキシ、および復元時に使う MSBuild の明示 + +- `z_Common2.bat` は同じ役割の **devenv 版**です。MSBuild では通らないが + devenv なら通る、というケースに備えて残されているもので、通常は使いません。 - Open 棟梁 が利用するライブラリは、NuGet 経由でダウンロードします。このため、プロキシ環境では、正常に NuGet ライブラリがダウンロードできないことがあります。プロキシ環境をお使いの場合は、以下のように http_proxy 環境変数を定義してください。 - C:\root\programs\CS\z_Common.bat および C:\root\programs\VB\z_Common.bat を、テキストエディタで開きます。 - 既定では、http_proxy 環境変数の定義部分はコメントアウトされていますので、"@rem" を削除して、このコメントを解除します。 - http_proxy 環境変数に、お使いのプロキシ情報を設定してください。 -- ビルド時に以下のエラーが発生した場合は、Windows 8 用の Windows SDK をインストールしてください。([Open 棟梁の issue](https://github.com/OpenTouryoProject/OpenTouryoTemplates/issues/48#issuecomment-241349223) が参考になります。) -``` -C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(2863,5): error MSB3086: タスクは SdkToolsPath "" またはレジストリ キー "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0A\WinSDK-NetFx40Tools-x86" を使用して "AL.exe"を見つけられませんでした。SdkToolsPath が設定されていること、SdkToolsPath の下の適切なプロセッサ固有の場所にツールが存在すること、および Microsoft Windows SDK がインストールされていることを確認してください。 [C:\root\programs\CS\Frameworks\Infrastructure\Public\Public.csproj] +#### ビルド後の検証 + +ビルドが通ることの確認、単体テスト、サンプルの疎通確認は、 +`C:\root\programs\` にあるスクリプトで行えます。いずれも**終了コードで合否が分かります**。 + +```powershell +cd C:\root\programs +.\0_RunAll.ps1 # 下記 3 本をまとめて実行 ``` - + +| スクリプト | 内容 | +|---|---| +| `1_BuildAll.ps1` | 全ビルド(`0_ExecAllBat.bat` 相当)。エラー・警告を集約して判定 | +| `2_RunAllTests.ps1` | 単体テストを実行し、結果を前回のものと比較 | +| `3_SmokeTest.ps1` | サンプルアプリケーションを起動して疎通を確認 | + +手順と判定基準は、同じフォルダの +[`BUILDING.md`](programs/BUILDING.md) / [`TESTING.md`](programs/TESTING.md) / +[`SMOKETEST.md`](programs/SMOKETEST.md) を参照してください。 +リリース時の作業全体は [`RELEASE.md`](programs/RELEASE.md) にまとめています。 + ### ASP.NET 状態サービスの準備 管理者としてコマンドプロンプトを起動し、下記コマンドを実行します。 ```bat @@ -542,24 +179,17 @@ C:\root\programs\CS\Samples\WS_sample\WSClient_sample\WSClientWinCone_sample\WSC ### .NET Core アプリケーション +**VB 版は、現時点で .NET Core 版の提供予定はありません。** 以下はいずれも C# のみです。 + #### 基盤: -- C# - - C:\root\programs\CS\Frameworks\Infrastructure - - C:\root\programs\CS\Frameworks\Infrastructure\ServiceInterface\ASPNETWebServiceCore -- VB -... +- C:\root\programs\CS\Frameworks\Infrastructure +- C:\root\programs\CS\Frameworks\Infrastructure\ServiceInterface\ASPNETWebServiceCore #### ツール: -- C# - - C:\root\programs\CS\Frameworks\Tools -- VB -... +- C:\root\programs\CS\Frameworks\Tools #### Sample アプリケーション: -- C# - - C:\root\programs\CS\Samples4NetCore -- VB -... +- C:\root\programs\CS\Samples4NetCore ## その他 特記事項 @@ -571,9 +201,6 @@ C:\root\programs\CS\Samples\WS_sample\WSClient_sample\WSClientWinCone_sample\WSC ご利用いただく中で、バグを発見されましたら、[issue](https://github.com/OpenTouryoProject/OpenTouryo/issues) としてご連絡ください。 コミュニティで内容を確認し、適切に対応いたします。 -### NuGetパッケージの作成方法 -Open 棟梁の NuGetパッケージを作成する方法については、[こちらの記事](https://github.com/OpenTouryoProject/OpenTouryo/wiki/HowToCreateOpenTouryoNuGetPackages.ja)をご参照ください。 - ### ライブラリの入手、輸出手続き、使用許諾への添付について - NuGetまたはnpmなどのパッケージ・マネージャーから取得できるライブラリは、Open 棟梁に同梱されないため、輸出管理する必要はありません。 - これ以外のライブラリ、つまりパッケージ・マネージャーから入手できないライブラリは、必要に応じて自身で入手・同梱して輸出する必要があります。この場合、Open棟梁のライセンスに、使用するライブラリのライセンスを添付する必要があります。 diff --git a/root/files/resource/Sql/ole_odbc/DaoShippers_D1_Insert.xml b/root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/ole_odbc/DaoShippers_D1_Insert.xml rename to root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D1_Insert.xml diff --git a/root/files/resource/Sql/ole_odbc/DaoShippers_D2_Select.xml b/root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/ole_odbc/DaoShippers_D2_Select.xml rename to root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D2_Select.xml diff --git a/root/files/resource/Sql/ole_odbc/DaoShippers_D3_Update.xml b/root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/ole_odbc/DaoShippers_D3_Update.xml rename to root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D3_Update.xml diff --git a/root/files/resource/Sql/ole_odbc/DaoShippers_D4_Delete.xml b/root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/ole_odbc/DaoShippers_D4_Delete.xml rename to root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D4_Delete.xml diff --git a/root/files/resource/Sql/ole_odbc/DaoShippers_D5_SelCnt.xml b/root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/ole_odbc/DaoShippers_D5_SelCnt.xml rename to root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_D5_SelCnt.xml diff --git a/root/files/resource/Sql/ole_odbc/DaoShippers_S1_Insert.sql b/root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/ole_odbc/DaoShippers_S1_Insert.sql rename to root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_S1_Insert.sql diff --git a/root/files/resource/Sql/ole_odbc/DaoShippers_S2_Select.xml b/root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/ole_odbc/DaoShippers_S2_Select.xml rename to root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_S2_Select.xml diff --git a/root/files/resource/Sql/ole_odbc/DaoShippers_S3_Update.xml b/root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/ole_odbc/DaoShippers_S3_Update.xml rename to root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_S3_Update.xml diff --git a/root/files/resource/Sql/ole_odbc/DaoShippers_S4_Delete.xml b/root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/ole_odbc/DaoShippers_S4_Delete.xml rename to root/files/resource/Sql/ole_odbc/DaoAutoGen/DaoShippers_S4_Delete.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/D layer definition information/AllTables.csv b/root/files/resource/Sql/oracle/DaoAutoGen/D layer definition information/AllTables.csv similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/D layer definition information/AllTables.csv rename to root/files/resource/Sql/oracle/DaoAutoGen/D layer definition information/AllTables.csv diff --git a/root/files/resource/Sql/oracle/Automatic generation/D layer definition information/AllTables_DBTypeInfo.csv b/root/files/resource/Sql/oracle/DaoAutoGen/D layer definition information/AllTables_DBTypeInfo.csv similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/D layer definition information/AllTables_DBTypeInfo.csv rename to root/files/resource/Sql/oracle/DaoAutoGen/D layer definition information/AllTables_DBTypeInfo.csv diff --git a/root/files/resource/Sql/oracle/Automatic generation/D layer definition information/AllTables_DotNetTypeInfo.csv b/root/files/resource/Sql/oracle/DaoAutoGen/D layer definition information/AllTables_DotNetTypeInfo.csv similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/D layer definition information/AllTables_DotNetTypeInfo.csv rename to root/files/resource/Sql/oracle/DaoAutoGen/D layer definition information/AllTables_DotNetTypeInfo.csv diff --git a/root/files/resource/Sql/oracle/Automatic generation/DTO/ORDERS2DataSet.xsd b/root/files/resource/Sql/oracle/DaoAutoGen/DTO/ORDERS2DataSet.xsd similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/DTO/ORDERS2DataSet.xsd rename to root/files/resource/Sql/oracle/DaoAutoGen/DTO/ORDERS2DataSet.xsd diff --git a/root/files/resource/Sql/oracle/Automatic generation/DTO/ORDERS2Entity.cs b/root/files/resource/Sql/oracle/DaoAutoGen/DTO/ORDERS2Entity.cs similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/DTO/ORDERS2Entity.cs rename to root/files/resource/Sql/oracle/DaoAutoGen/DTO/ORDERS2Entity.cs diff --git a/root/files/resource/Sql/oracle/Automatic generation/DTO/ORDERS2Entity.vb b/root/files/resource/Sql/oracle/DaoAutoGen/DTO/ORDERS2Entity.vb similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/DTO/ORDERS2Entity.vb rename to root/files/resource/Sql/oracle/DaoAutoGen/DTO/ORDERS2Entity.vb diff --git a/root/files/resource/Sql/oracle/Automatic generation/DTO/SHIPPERSDataSet.xsd b/root/files/resource/Sql/oracle/DaoAutoGen/DTO/SHIPPERSDataSet.xsd similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/DTO/SHIPPERSDataSet.xsd rename to root/files/resource/Sql/oracle/DaoAutoGen/DTO/SHIPPERSDataSet.xsd diff --git a/root/files/resource/Sql/oracle/Automatic generation/DTO/SHIPPERSEntity.cs b/root/files/resource/Sql/oracle/DaoAutoGen/DTO/SHIPPERSEntity.cs similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/DTO/SHIPPERSEntity.cs rename to root/files/resource/Sql/oracle/DaoAutoGen/DTO/SHIPPERSEntity.cs diff --git a/root/files/resource/Sql/oracle/Automatic generation/DTO/SHIPPERSEntity.vb b/root/files/resource/Sql/oracle/DaoAutoGen/DTO/SHIPPERSEntity.vb similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/DTO/SHIPPERSEntity.vb rename to root/files/resource/Sql/oracle/DaoAutoGen/DTO/SHIPPERSEntity.vb diff --git a/root/files/resource/Sql/oracle/Automatic generation/Dao/DaoORDERS2.cs b/root/files/resource/Sql/oracle/DaoAutoGen/Dao/DaoORDERS2.cs similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/Dao/DaoORDERS2.cs rename to root/files/resource/Sql/oracle/DaoAutoGen/Dao/DaoORDERS2.cs diff --git a/root/files/resource/Sql/oracle/Automatic generation/Dao/DaoORDERS2.vb b/root/files/resource/Sql/oracle/DaoAutoGen/Dao/DaoORDERS2.vb similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/Dao/DaoORDERS2.vb rename to root/files/resource/Sql/oracle/DaoAutoGen/Dao/DaoORDERS2.vb diff --git a/root/files/resource/Sql/oracle/Automatic generation/Dao/DaoSHIPPERS.cs b/root/files/resource/Sql/oracle/DaoAutoGen/Dao/DaoSHIPPERS.cs similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/Dao/DaoSHIPPERS.cs rename to root/files/resource/Sql/oracle/DaoAutoGen/Dao/DaoSHIPPERS.cs diff --git a/root/files/resource/Sql/oracle/Automatic generation/Dao/DaoSHIPPERS.vb b/root/files/resource/Sql/oracle/DaoAutoGen/Dao/DaoSHIPPERS.vb similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/Dao/DaoSHIPPERS.vb rename to root/files/resource/Sql/oracle/DaoAutoGen/Dao/DaoSHIPPERS.vb diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D1_Insert.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D1_Insert.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D1_Insert.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D2_Select.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D2_Select.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D2_Select.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D3_Update.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D3_Update.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D3_Update.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D4_Delete.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D4_Delete.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D4_Delete.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D5_SelCnt.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_D5_SelCnt.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_D5_SelCnt.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_S1_Insert.sql b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_S1_Insert.sql rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_S1_Insert.sql diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_S2_Select.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_S2_Select.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_S2_Select.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_S3_Update.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_S3_Update.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_S3_Update.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_S4_Delete.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoORDERS2_S4_Delete.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoORDERS2_S4_Delete.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D1_Insert.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D1_Insert.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D1_Insert.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D1_Insert_org.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D1_Insert_org.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D1_Insert_org.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D1_Insert_org.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D2_Select.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D2_Select.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D2_Select.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D3_Update.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D3_Update.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D3_Update.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D4_Delete.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D4_Delete.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D4_Delete.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D5_SelCnt.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_D5_SelCnt.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_D5_SelCnt.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S1_Insert.sql b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S1_Insert.sql rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S1_Insert.sql diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S1_Insert_org.sql b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S1_Insert_org.sql similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S1_Insert_org.sql rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S1_Insert_org.sql diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S2_Select.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S2_Select.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S2_Select.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S3_Update.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S3_Update.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S3_Update.xml diff --git a/root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S4_Delete.xml b/root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/oracle/Automatic generation/SQL/DaoSHIPPERS_S4_Delete.xml rename to root/files/resource/Sql/oracle/DaoAutoGen/SQL/DaoSHIPPERS_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/D layer definition information/AllTables.csv b/root/files/resource/Sql/sqlserver/DaoAutoGen/D layer definition information/AllTables.csv similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/D layer definition information/AllTables.csv rename to root/files/resource/Sql/sqlserver/DaoAutoGen/D layer definition information/AllTables.csv diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/D layer definition information/AllTables_DBTypeInfo.csv b/root/files/resource/Sql/sqlserver/DaoAutoGen/D layer definition information/AllTables_DBTypeInfo.csv similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/D layer definition information/AllTables_DBTypeInfo.csv rename to root/files/resource/Sql/sqlserver/DaoAutoGen/D layer definition information/AllTables_DBTypeInfo.csv diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/D layer definition information/AllTables_DotNetTypeInfo.csv b/root/files/resource/Sql/sqlserver/DaoAutoGen/D layer definition information/AllTables_DotNetTypeInfo.csv similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/D layer definition information/AllTables_DotNetTypeInfo.csv rename to root/files/resource/Sql/sqlserver/DaoAutoGen/D layer definition information/AllTables_DotNetTypeInfo.csv diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/CategoriesDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CategoriesDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/CategoriesDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CategoriesDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/CategoriesEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CategoriesEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/CategoriesEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CategoriesEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/CategoriesEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CategoriesEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/CategoriesEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CategoriesEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/CustomersDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CustomersDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/CustomersDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CustomersDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/CustomersEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CustomersEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/CustomersEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CustomersEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/CustomersEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CustomersEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/CustomersEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/CustomersEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeeTerritoriesDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeeTerritoriesDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeeTerritoriesDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeeTerritoriesDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeeTerritoriesEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeeTerritoriesEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeeTerritoriesEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeeTerritoriesEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeeTerritoriesEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeeTerritoriesEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeeTerritoriesEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeeTerritoriesEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeesDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeesDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeesDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeesDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeesEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeesEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeesEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeesEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeesEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeesEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/EmployeesEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/EmployeesEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/Order_DetailsDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Order_DetailsDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/Order_DetailsDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Order_DetailsDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/Order_DetailsEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Order_DetailsEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/Order_DetailsEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Order_DetailsEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/Order_DetailsEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Order_DetailsEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/Order_DetailsEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Order_DetailsEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/Orders2DataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Orders2DataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/Orders2DataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Orders2DataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/Orders2Entity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Orders2Entity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/Orders2Entity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Orders2Entity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/Orders2Entity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Orders2Entity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/Orders2Entity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/Orders2Entity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/OrdersDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/OrdersDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/OrdersDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/OrdersDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/OrdersEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/OrdersEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/OrdersEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/OrdersEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/OrdersEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/OrdersEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/OrdersEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/OrdersEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/ProductsDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ProductsDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/ProductsDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ProductsDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/ProductsEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ProductsEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/ProductsEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ProductsEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/ProductsEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ProductsEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/ProductsEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ProductsEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/RegionDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/RegionDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/RegionDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/RegionDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/RegionEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/RegionEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/RegionEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/RegionEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/RegionEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/RegionEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/RegionEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/RegionEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/ShippersDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ShippersDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/ShippersDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ShippersDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/ShippersEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ShippersEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/ShippersEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ShippersEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/ShippersEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ShippersEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/ShippersEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/ShippersEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/SuppliersDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/SuppliersDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/SuppliersDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/SuppliersDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/SuppliersEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/SuppliersEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/SuppliersEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/SuppliersEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/SuppliersEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/SuppliersEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/SuppliersEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/SuppliersEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/TerritoriesDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/TerritoriesDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/TerritoriesDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/TerritoriesDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/TerritoriesEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/TerritoriesEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/TerritoriesEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/TerritoriesEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/DTO/TerritoriesEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/TerritoriesEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/DTO/TerritoriesEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/DTO/TerritoriesEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoCategories.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoCategories.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoCategories.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoCategories.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoCategories.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoCategories.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoCategories.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoCategories.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoCustomers.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoCustomers.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoCustomers.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoCustomers.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoCustomers.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoCustomers.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoCustomers.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoCustomers.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoEmployeeTerritories.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoEmployeeTerritories.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoEmployeeTerritories.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoEmployeeTerritories.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoEmployeeTerritories.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoEmployeeTerritories.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoEmployeeTerritories.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoEmployeeTerritories.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoEmployees.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoEmployees.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoEmployees.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoEmployees.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoEmployees.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoEmployees.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoEmployees.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoEmployees.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrder_Details.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrder_Details.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrder_Details.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrder_Details.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrder_Details.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrder_Details.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrder_Details.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrder_Details.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrders.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrders.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrders.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrders.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrders.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrders.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrders.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrders.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrders2.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrders2.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrders2.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrders2.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrders2.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrders2.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoOrders2.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoOrders2.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoProducts.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoProducts.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoProducts.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoProducts.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoProducts.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoProducts.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoProducts.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoProducts.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoRegion.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoRegion.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoRegion.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoRegion.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoRegion.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoRegion.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoRegion.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoRegion.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoShippers.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoShippers.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoShippers.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoShippers.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoShippers.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoShippers.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoShippers.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoShippers.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoSuppliers.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoSuppliers.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoSuppliers.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoSuppliers.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoSuppliers.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoSuppliers.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoSuppliers.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoSuppliers.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoTerritories.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoTerritories.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoTerritories.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoTerritories.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoTerritories.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoTerritories.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/Dao/DaoTerritories.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen/Dao/DaoTerritories.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCategories_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCategories_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoCustomers_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoCustomers_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployeeTerritories_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployeeTerritories_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoEmployees_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoEmployees_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrder_Details_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrder_Details_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders2_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders2_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoOrders_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoOrders_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S1_Insert_org.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S1_Insert_org.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S1_Insert_org.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S1_Insert_org.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoProducts_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoProducts_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoRegion_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoRegion_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoShippers_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoShippers_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S1_Insert_org.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S1_Insert_org.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S1_Insert_org.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S1_Insert_org.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoSuppliers_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoSuppliers_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation/SQL/DaoTerritories_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen/SQL/DaoTerritories_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/1.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/1.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/1.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/1.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/2.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/2.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/2.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/2.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/3.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/3.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/3.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/3.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/A.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/A.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/A.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/A.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/B.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/B.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/B.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/B.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/C.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/C.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/CreateTable/C.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/CreateTable/C.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_rand.csv b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_rand.csv similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_rand.csv rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_rand.csv diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_rand_DBTypeInfo.csv b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_rand_DBTypeInfo.csv similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_rand_DBTypeInfo.csv rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_rand_DBTypeInfo.csv diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_rand_DotNetTypeInfo.csv b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_rand_DotNetTypeInfo.csv similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_rand_DotNetTypeInfo.csv rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_rand_DotNetTypeInfo.csv diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_timestamp.csv b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_timestamp.csv similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_timestamp.csv rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_timestamp.csv diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_timestamp_DBTypeInfo.csv b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_timestamp_DBTypeInfo.csv similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_timestamp_DBTypeInfo.csv rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_timestamp_DBTypeInfo.csv diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_timestamp_DotNetTypeInfo.csv b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_timestamp_DotNetTypeInfo.csv similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/D layer definition information/tstest_timestamp_DotNetTypeInfo.csv rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/D layer definition information/tstest_timestamp_DotNetTypeInfo.csv diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table1DataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table1DataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table1DataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table1DataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table1Entity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table1Entity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table1Entity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table1Entity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table1Entity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table1Entity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table1Entity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table1Entity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table2DataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table2DataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table2DataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table2DataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table2Entity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table2Entity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table2Entity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table2Entity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table2Entity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table2Entity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table2Entity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table2Entity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table3DataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table3DataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table3DataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table3DataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table3Entity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table3Entity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table3Entity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table3Entity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table3Entity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table3Entity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_table3Entity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_table3Entity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableADataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableADataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableADataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableADataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableAEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableAEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableAEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableAEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableAEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableAEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableAEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableAEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableBDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableBDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableBDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableBDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableBEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableBEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableBEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableBEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableBEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableBEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableBEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableBEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableCDataSet.xsd b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableCDataSet.xsd similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableCDataSet.xsd rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableCDataSet.xsd diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableCEntity.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableCEntity.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableCEntity.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableCEntity.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableCEntity.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableCEntity.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/DTO/ts_test_tableCEntity.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/DTO/ts_test_tableCEntity.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table1.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table1.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table1.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table1.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table1.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table1.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table1.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table1.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table2.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table2.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table2.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table2.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table2.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table2.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table2.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table2.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table3.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table3.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table3.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table3.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table3.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table3.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_table3.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_table3.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableA.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableA.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableA.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableA.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableA.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableA.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableA.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableA.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableB.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableB.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableB.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableB.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableB.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableB.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableB.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableB.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableC.cs b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableC.cs similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableC.cs rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableC.cs diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableC.vb b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableC.vb similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/Dao/Daots_test_tableC.vb rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/Dao/Daots_test_tableC.vb diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S1_Insert_org.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S1_Insert_org.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S1_Insert_org.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S1_Insert_org.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table1_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table1_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S1_Insert_org.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S1_Insert_org.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S1_Insert_org.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S1_Insert_org.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table2_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table2_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S1_Insert_org.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S1_Insert_org.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S1_Insert_org.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S1_Insert_org.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_table3_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_table3_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S1_Insert_org.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S1_Insert_org.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S1_Insert_org.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S1_Insert_org.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableA_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableA_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S1_Insert_org.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S1_Insert_org.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S1_Insert_org.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S1_Insert_org.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableB_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableB_S4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D1_Insert.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D1_Insert.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D1_Insert.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D1_Insert.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D4_Delete.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D5_SelCnt.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D5_SelCnt.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_D5_SelCnt.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_D5_SelCnt.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S1_Insert.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S1_Insert.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S1_Insert.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S1_Insert.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S1_Insert_org.sql b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S1_Insert_org.sql similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S1_Insert_org.sql rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S1_Insert_org.sql diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S2_Select.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S2_Select.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S2_Select.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S2_Select.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S3_Update.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S3_Update.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S3_Update.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S3_Update.xml diff --git a/root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S4_Delete.xml b/root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S4_Delete.xml similarity index 100% rename from root/files/resource/Sql/sqlserver/Automatic generation(TimeStamp/SQL/Daots_test_tableC_S4_Delete.xml rename to root/files/resource/Sql/sqlserver/DaoAutoGen_TimeStamp/SQL/Daots_test_tableC_S4_Delete.xml diff --git a/root/files/tools/DGenTemplates/README.md b/root/files/tools/DGenTemplates/README.md new file mode 100644 index 000000000..084e9fc15 --- /dev/null +++ b/root/files/tools/DGenTemplates/README.md @@ -0,0 +1,141 @@ +# DGenTemplates — D層/画面 自動生成テンプレート + +`DaoGen_Tool`(墨壺)と `DPQuery_Tool` が使う**テンプレート置き場**。 + +**格納物はテンプレートのみで、生成物は含まない。** +全ファイルが置換トークン(`_Xxx_`)または制御コメント(`ControlComment:`)を含む。 + +生成時に**フォルダをツールの画面で指定する**(既定値は `appsettings.json` の +`InputFilesRoot`)。ツール側に本フォルダのパスは埋め込まれていない。 + +--- + +## 1. 何がどのツールで使われるか + +**2 つのツールが同じフォルダを共有している。** 片方だけを見て「未使用」と判断しないこと。 + +| テンプレート | DaoGen_Tool | DPQuery_Tool | +|---|---|---| +| `DaoTemplate.cs` / `.vb` | — | **○**(`DaoTemplate`) | +| `DaoTemplate2.cs` / `.vb` | — | — | +| `DaoTemplate3.cs` / `.vb` | **○**(`DaoTemplate3`) | — | +| `EntityTemplate.cs` / `.vb` | ○ | ○ | +| `EntityTemplate_bk.cs` / `.vb` | —(3 節) | — | +| `DataSetTemplate.xsd` | ○ | ○ | +| `TableAdapter.cs` / `.vb` | ○ | ○ | +| `ConditionalSearch` / `SearchAndUpdate` / `Detail`(`.aspx` + `.cs` / `.vb`) | **○** 単票 | — | +| `_Screen_*`(同 3 画面) | — | **○** 結合表 | +| `s1_`〜`s4_`(静的 SQL) | ○ | ○ | +| `d1_`〜`d5_`(動的 SQL) | ○ | ○ | + +- **`_Screen_` の有無は「新旧」ではなく「結合表か単票か」。** + 接頭辞なしは単一テーブル(`_TableName_` / `_ColumnName_`)、 + `_Screen_` 付きは結合テーブル(`_JoinTableName_` / `_JoinTextboxColumnName_`)。 +- 対応は各ツールの `appsettings.json`(`*TemplateFileName`)が正。 + +--- + +## 2. DaoTemplate の 3 世代 + +**いずれも現役の選択肢**で、設定で切り替える。既定はツールごとに異なる。 + +| | クエリ キャッシュ | パラメタの型指定 | 使用ツール | +|---|---|---|---| +| `DaoTemplate` | — | — | DPQuery_Tool | +| `DaoTemplate2` | あり | — | (既定では未使用) | +| `DaoTemplate3` | あり | **あり**(`DaoParam` で `DbType` / `Size` / `Direction`) | DaoGen_Tool | + +`2` → `3` の差は 13 行で、`DaoParam` による型指定への対応のみ(2020/06/20)。 + +--- + +## 3. EntityTemplate と EntityTemplate_bk + +> **`_bk` は「単に古い控え」ではない。** 機能は `_bk` の方が多いが、**意図的に既定から外されている。** + +| | `EntityTemplate`(既定) | `EntityTemplate_bk` | +|---|---|---| +| 主キー列のプロパティ名 | `_ColumnName_`(=列名) | `PK__ColumnName_` | +| 設定済みフラグ | なし | `IsSet__ColumnName_` | +| ループ ブロック | `PKColumn` / `ElseColumn` | 左記 + `PPUpdSet` / `PPLike` | + +### なぜ機能が多い方が使われないのか + +**項目移送の方式が変わったため。** + +`_bk` は「自動生成 Dao への**項目移送**」を目的とした設計で、主キーを名前で区別していた。 +その後、`Public/Dto` に POCO 変換部品が入り、**プロパティ名を列名として突合する**方式になった。 + +```csharp +// DataToPoco.cs — プロパティ名でそのまま列を引く +string srcName = ai_dst.AccessorName; // POCO のプロパティ名 +if (hs.Contains(srcName)) { object srcValue = dr[srcName]; } +``` + +この方式では **`PK_` 接頭辞は列名と一致せず、主キー列が黙って未設定になる** +(`map` 引数で対応表を渡せば回避できるが、自動生成 DTO ごとに用意することになる)。 + +`IsSet` フラグと `PPUpdSet` / `PPLike` も、列名をキーとする `Dictionary` 方式 +(`_3TierParameterValue` の `InsertUpdateValues` など)で同等のことが表現できる。 + +### 経緯 + +``` +2018/07/19 Public/Dto/DataToPoco.cs 新規作成(Dapper / AutoMapper.Data 代替) +2018/07/20 Public/Dto/PocoToPoco.cs 新規作成(AutoMapper 代替) +2018/07/25 Issue #293「EntityTemplate is redundant.」起票 +2018/07/30 d7023598 EntityTemplate を単純化し、_bk として従来版を退避 +2018/08/01 Issue #293 クローズ +``` + +[#293](https://github.com/OpenTouryoProject/OpenTouryo/issues/293) の起票者の記述。 + +> 当初は自動生成 Dao への項目移送を目的としてこう設計されたのだと思う。 +> しかし ViewModel を生成する目的からすると、このテンプレートは適切でない。 +> **既定のテンプレートは POCO 形式であるべき**だと考える。 + +**`_bk` を既定に戻す場合は、`DataToPoco` / `PocoToPoco` を使う箇所で +`map` 引数による対応付けが要る**ことに注意する。 + +--- + +## 4. テンプレートの記法 + +### 置換トークン `_Xxx_` + +生成時に実際の値へ置換される。主なもの(出現数は画面テンプレート群での実測)。 + +| トークン | 意味 | +|---|---| +| `_TableName_` / `_ColumnName_` | 表名・列名(単票) | +| `_JoinTableName_` / `_JoinColumnName_` / `_JoinTextboxColumnName_` | 同(結合表) | +| `_TimeStampColName_` | 排他制御に使うタイム スタンプ列 | +| `_DAP_` / `_DBMS_` | データ プロバイダ・DBMS の切替 | +| `_CodebehindLanguage_` / `_ClassTemplateFileExtension_` | C# / VB の切替 | + +置換対象の一覧は、各ツールの `appsettings.json` の **`Rp` 接頭辞のキー**にある。 + +### 制御コメント `ControlComment:` + +繰り返しの範囲を示す。`.aspx` では HTML コメント、コード ファイルでは行コメント。 + +``` +ControlComment:LoopStart-PKColumn … 主キー列の繰り返し +ControlComment:LoopStart-ElseColumn … 主キー以外の列 +ControlComment:LoopStart-JoinTables … 結合テーブル +ControlComment:LoopStart-PPUpdSet … EntityTemplate_bk のみ +ControlComment:LoopStart-PPLike … EntityTemplate_bk のみ +``` + +--- + +## 5. 変更するときの注意 + +- **C# 版と VB 版は対で維持する。** 片方だけ直すと生成結果が言語で食い違う。 +- **プロパティ名を列名から変えない。** `DataToPoco` / `PocoToPoco` が + プロパティ名で突合するため(3 節)。 +- 画面テンプレートは Entity(DTO)を使わず、`_3TierParameterValue` の + `Dictionary<string, object>`(`AndEqualSearchConditions` / `InsertUpdateValues`)で値を渡す。 + **DTO の形を変えても画面には影響しない**が、逆も同様で、DTO 側の都合で画面を直す必要はない。 +- ツールの CLI からの使い方は + [`DaoGen_Tool/README.md`](../../../programs/CS/Frameworks/Tools/DaoGen_Tool/README.md) を参照。 diff --git a/root/programs/0_RunAll.ps1 b/root/programs/0_RunAll.ps1 new file mode 100644 index 000000000..14e6e7f12 --- /dev/null +++ b/root/programs/0_RunAll.ps1 @@ -0,0 +1,31 @@ +# --- 処理部:他のps1ファイルを順次実行 --- +# ※ ダブル クリック起動でもカレント ディレクトリに依存しないよう $PSScriptRoot を使う。 +# ※ 順序は固定(RELEASE.md 3 節)。1 のクリーンとアセンブリ配置が 2・3 の前提になる。 +$scripts = @("1_BuildAll.ps1", "2_RunAllTests.ps1", "3_SmokeTest.ps1") +$results = @() + +foreach ($s in $scripts) +{ + & (Join-Path $PSScriptRoot $s) + $results += [pscustomobject]@{ スクリプト = $s; 終了コード = $LASTEXITCODE } +} + +# --- 結果のまとめ --- +Write-Host "" +Write-Host "================ 全体のまとめ ================" +$results | Format-Table -AutoSize | Out-String | Write-Host + +# 1_BuildAll.ps1 は既知の署名エラー(MSB3482)で 1 になることがある。 +# 終了コードだけで判断せず、エラー一覧の内容を確認すること(RELEASE.md 3 節)。 +$ng = @($results | Where-Object { $_.終了コード -ne 0 }) +if ($ng.Count -eq 0) +{ + Write-Host "すべて OK です。" -ForegroundColor Green +} +else +{ + Write-Host ("{0} 本が 0 以外で終了しました。上のログを確認してください。" -f $ng.Count) -ForegroundColor Yellow +} + +# --- 画面を残すための処理 --- +Read-Host "`nEnterキーを押すとウィンドウを閉じます" diff --git a/root/programs/0_SetVersion.ps1 b/root/programs/0_SetVersion.ps1 new file mode 100644 index 000000000..3068d316e --- /dev/null +++ b/root/programs/0_SetVersion.ps1 @@ -0,0 +1,271 @@ +<# +.SYNOPSIS + Open 棟梁のリリース バージョンを、関係する全ファイルに一括反映する。 + +.DESCRIPTION + バージョン番号の定義箇所は 2 系統に分かれており、手作業では追随を忘れやすい(#531)。 + + (1) CS\Frameworks\Infrastructure\Directory.Build.props の OpenTouryoVersion + … SDK 形式 csproj(*_netcore100.csproj)が <Version> で参照する。 + (2) 各 net48 プロジェクトの Properties\AssemblyInfo.cs の AssemblyVersion + … 旧形式 csproj は Microsoft.Common.props を通らないため + Directory.Build.props が効かない。別管理になっている。 + + (2) の追随を忘れると、同じ NuGet パッケージの中で net48 と net10.0 の + アセンブリの版が食い違う。**公開後には直せない。** + + _NuGetPack.bat はパッケージ化の前にこの一致を検査して停止するが、 + 本スクリプトは、そもそもずれた状態を作らないためのもの。 + +.PARAMETER Version + 設定するバージョン。3 桁(例: 3.1.0)か、 + プレリリース サフィックス付き(例: 3.3.0-alpha1)で指定する。 + + ・OpenTouryoVersion … 指定した文字列をそのまま書き込む(3.3.0-alpha1) + ・AssemblyVersion … サフィックスを落とし、4 桁目に 0 を補う(3.3.0.0) + + **アセンブリの版にサフィックスは入らない。** + SDK 形式 csproj の <Version> も、AssemblyVersion / FileVersion には + VersionPrefix(3.3.0)を、InformationalVersion には全体(3.3.0-alpha1)を + 割り当てる。その挙動に合わせてある。 + +.PARAMETER WhatIf + 書き換えずに、変更内容だけを表示する。 + +.EXAMPLE + .\0_SetVersion.ps1 -Version 3.1.0 + +.EXAMPLE + .\0_SetVersion.ps1 -Version 3.1.0 -WhatIf + +.NOTES + ・net48 側の対象は「NuGet パッケージに入る 6 本」のみ。 + DamPstGrS は net48 が無い。Business は非パッケージかつ意図的に + 別系統(1.0.0)のため、対象にしない。 + ・書き換え後は 0_Release4Nuget.bat でのリビルドが必要。 + OpenTouryoVersion はアセンブリに焼き込まれるため、 + 先にパッケージ化すると古いアセンブリに新しい版番号が付く。 + ・手順の全体は RELEASE.md フェーズ 0 を参照。 +#> +[CmdletBinding(SupportsShouldProcess = $true)] +param( + [Parameter(Mandatory = $true)] + [string]$Version +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +# -------------------------------------------------- +# コンソールのコード ページと、PowerShell の出力エンコードは別物(ANALYSIS.md 8.5)。 +# 判定を分けること。 +# -------------------------------------------------- +if ((cmd /c chcp) -notmatch '65001') +{ + cmd /c chcp 65001 | Out-Null +} + +if ([Console]::OutputEncoding.CodePage -ne 65001) +{ + [Console]::OutputEncoding = New-Object Text.UTF8Encoding $false +} + +# -------------------------------------------------- +# 引数の検証 +# -------------------------------------------------- +# プレリリース サフィックス(-alpha1 等)を許す。 +# 前半 3 桁を VersionPrefix として取り出し、アセンブリの版に使う。 +if ($Version -notmatch '^([0-9]+\.[0-9]+\.[0-9]+)(-[0-9A-Za-z][0-9A-Za-z.-]*)?$') +{ + Write-Host "[ERROR] Version の書式が不正です。3 桁、またはサフィックス付きで指定してください。" -ForegroundColor Red + Write-Host " 例: 3.1.0 / 3.3.0-alpha1 指定値: $Version" -ForegroundColor Red + exit 1 +} + +$versionPrefix = $Matches[1] +$assemblyVersion = "$versionPrefix.0" + +# -------------------------------------------------- +# 対象ファイル +# +# net48 側は「NuGet パッケージに入る 6 本」のみ。 +# _NuGetPack.bat の検査対象と一致させること。 +# -------------------------------------------------- +$infra = Join-Path $PSScriptRoot "CS\Frameworks\Infrastructure" +$props = Join-Path $infra "Directory.Build.props" + +$net48Projects = @( + "Public", + "Public\Security", + "Framework", + "Framework\RichClient", + "Public\Db\DamManagedOdp", + "Public\Db\DamMySQL" +) + +# -------------------------------------------------- +# 読み書きのヘルパ +# +# BOM の有無を保って書き戻す。5.1 の Get-Content / Set-Content は +# 既定のエンコードが ANSI のため使わない(ANALYSIS.md 8.5)。 +# -------------------------------------------------- +function Read-TextFile +{ + param([string]$Path) + + $bytes = [IO.File]::ReadAllBytes($Path) + $hasBom = ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) + + if ($hasBom) + { + $text = [Text.Encoding]::UTF8.GetString($bytes, 3, $bytes.Length - 3) + } + else + { + $text = [Text.Encoding]::UTF8.GetString($bytes) + } + + return [pscustomobject]@{ Text = $text; HasBom = $hasBom } +} + +function Write-TextFile +{ + param([string]$Path, [string]$Text, [bool]$HasBom) + + [IO.File]::WriteAllText($Path, $Text, (New-Object Text.UTF8Encoding $HasBom)) +} + +# -------------------------------------------------- +# 置換 +# +# 戻り値は、変更があったかどうか。 +# 変更前の値が見つからない場合はエラーで停止する(黙って素通りさせない)。 +# -------------------------------------------------- +$results = @() +$failed = $false + +function Update-VersionInFile +{ + param( + [string]$Path, + [string]$Label, + [string]$Pattern, + [string]$Replacement, + [string]$NewValue + ) + + if (-not (Test-Path $Path)) + { + $script:results += [pscustomobject]@{ 対象 = $Label; 変更前 = "-"; 変更後 = "-"; 結果 = "NG (ファイルが無い)" } + $script:failed = $true + return + } + + $file = Read-TextFile -Path $Path + $found = [regex]::Matches($file.Text, $Pattern) + + if ($found.Count -eq 0) + { + $script:results += [pscustomobject]@{ 対象 = $Label; 変更前 = "-"; 変更後 = "-"; 結果 = "NG (該当行が無い)" } + $script:failed = $true + return + } + + # グループ 1 は置換時に残す前置き、グループ 2 が現在のバージョン。 + # 全パターンでこの並びに揃えてある。 + $before = $found[0].Groups[2].Value + + if ($before -eq $NewValue) + { + $script:results += [pscustomobject]@{ 対象 = $Label; 変更前 = $before; 変更後 = $NewValue; 結果 = "変更なし" } + return + } + + $updated = [regex]::Replace($file.Text, $Pattern, $Replacement) + + if ($PSCmdlet.ShouldProcess($Path, "$before -> $NewValue")) + { + Write-TextFile -Path $Path -Text $updated -HasBom $file.HasBom + $script:results += [pscustomobject]@{ 対象 = $Label; 変更前 = $before; 変更後 = $NewValue; 結果 = "更新" } + } + else + { + $script:results += [pscustomobject]@{ 対象 = $Label; 変更前 = $before; 変更後 = $NewValue; 結果 = "更新(WhatIf)" } + } +} + +Write-Host "" +Write-Host "--------------------------------------------------" +Write-Host " OpenTouryoVersion = $Version (NuGet パッケージの版)" +Write-Host " AssemblyVersion = $assemblyVersion (アセンブリの版)" + +if ($Version -ne $versionPrefix) +{ + Write-Host " ※ プレリリース サフィックスは、アセンブリの版には入らない。" +} + +Write-Host "--------------------------------------------------" + +# -------------------------------------------------- +# (1) Directory.Build.props +# -------------------------------------------------- +Update-VersionInFile ` + -Path $props ` + -Label "Directory.Build.props" ` + -Pattern '(<OpenTouryoVersion>)([^<]*)(?=</OpenTouryoVersion>)' ` + -Replacement "`${1}$Version" ` + -NewValue $Version + +# -------------------------------------------------- +# (2) net48 の AssemblyInfo.cs +# +# コメント アウトされた行(例: // [assembly: AssemblyVersion("1.0.*")])は +# 対象外にする。行頭から属性までの間に // が無いことを条件にしている。 +# AssemblyFileVersion は、在れば一緒に更新する。 +# -------------------------------------------------- +foreach ($project in $net48Projects) +{ + $path = Join-Path $infra (Join-Path $project "Properties\AssemblyInfo.cs") + + Update-VersionInFile ` + -Path $path ` + -Label "$project (AssemblyVersion)" ` + -Pattern '(?m)^(?!\s*//)(\s*\[assembly:\s*AssemblyVersion\(")([0-9][^"]*)(?="\)\])' ` + -Replacement "`${1}$assemblyVersion" ` + -NewValue $assemblyVersion + + $file = Read-TextFile -Path $path + + if ($file.Text -match '(?m)^(?!\s*//)\s*\[assembly:\s*AssemblyFileVersion\("') + { + Update-VersionInFile ` + -Path $path ` + -Label "$project (AssemblyFileVersion)" ` + -Pattern '(?m)^(?!\s*//)(\s*\[assembly:\s*AssemblyFileVersion\(")([0-9][^"]*)(?="\)\])' ` + -Replacement "`${1}$assemblyVersion" ` + -NewValue $assemblyVersion + } +} + +# -------------------------------------------------- +# 結果 +# -------------------------------------------------- +Write-Host "" +$results | Format-Table -AutoSize | Out-String -Width 200 | Write-Host + +if ($failed) +{ + Write-Host "[ERROR] 更新できなかったファイルがあります。上の NG を確認してください。" -ForegroundColor Red + exit 1 +} + +Write-Host "次に行うこと" -ForegroundColor Yellow +Write-Host " 1. Business 系が 1.0.0 のままであることを確認する(意図的に別系統)" +Write-Host " 2. コミットして push する(Source Link はこのコミットに固定される)" +Write-Host " 3. CS\0_Release4Nuget.bat でリビルドする(版はアセンブリに焼き込まれる)" +Write-Host " 4. CS\NuGet\_NuGetPack.bat でパッケージ化する(版の一致が再検査される)" +Write-Host "" +Write-Host " 詳細は RELEASE.md フェーズ 0 を参照。" +Write-Host "" + +exit 0 diff --git a/root/programs/1_BuildAll.ps1 b/root/programs/1_BuildAll.ps1 new file mode 100644 index 000000000..f601ee92f --- /dev/null +++ b/root/programs/1_BuildAll.ps1 @@ -0,0 +1,318 @@ +<# +.SYNOPSIS + 全ビルド(0_ExecAllBat.bat 相当)を実行し、エラー・警告を集約して合否を判定する。 + +.DESCRIPTION + リリース時の「build バッチで全ビルドが通ることを確認」を機械化したもの(#513 段階 2)。 + + 既存のビルド バッチをそのまま呼び出し、出力を解析して結果を集約する。 + 「何をビルドするか」の正はバッチ側に残し、本スクリプトは実行と判定のみを担う。 + + <なぜラッパーが必要か> + ・各バッチは MSBuild の終了コードを伝播しない(%ERRORLEVEL% を見ていない) + ・各バッチの末尾に pause があり、対話入力を待つ + ・-v:d(詳細)で出力が膨大なため、目視での確認が難しい + このため、stdin を与えて実行し、出力から error / warning を抽出して判定する。 + +.PARAMETER Only + ステップ名の部分一致で対象を絞る(例: -Only "net48")。動作確認用。 + +.PARAMETER SkipClean + クリーン処理(1_DeleteDir / 1_DeleteFile)を省略する。 + ※ リリース判定では省略しないこと。前回のビルド成果物が残っていると、 +   ビルドが通ったように見えることがある。 + +.PARAMETER OutputDir + 各ステップの出力ログの保存先。既定は %TEMP%\OpenTouryoBuildLogs。 + +.PARAMETER IgnoreErrors + 「既知のエラー」として合否判定から除外する正規表現。複数指定できる。 + 除外したものは黙って消さず、件数と内容をサマリに別枠で出す。 + + 環境に依存して必ず出るエラーを、終了コードを汚さずに扱うための引数。 + 例: ClickOnce の署名エラー(MSB3482)は、csproj が証明書の拇印を +   直接指定しているため、その証明書が無い環境では必ず失敗する。 + +.EXAMPLE + .\1_BuildAll.ps1 + +.EXAMPLE + .\1_BuildAll.ps1 -Only "Framework_Tool" -SkipClean + +.EXAMPLE + .\1_BuildAll.ps1 -IgnoreErrors "MSB3482" + +.NOTES + 作成者 :玄人 幸道 + 更新履歴 : + 日時 更新者 内容 + ---------- ---------------- ------------------------------------------------- + 2026/08/01 玄人 幸道 新規作成(リリース ワークのエージェント化) + 2026/08/05 玄人 幸道 IgnoreErrors を追加(CI での既知エラーの除外) +#> +[CmdletBinding()] +param( + [string]$Only, + [switch]$SkipClean, + [string]$OutputDir = (Join-Path $env:TEMP "OpenTouryoBuildLogs"), + [string[]]$IgnoreErrors = @() +) + +# 本スクリプトは root\programs に置き、C# 側(root\programs\CS)を対象とする。 +# ビルド バッチはすべて CS 直下にあるため、そこを起点にする。 +$csRoot = Join-Path $PSScriptRoot "CS" +New-Item -ItemType Directory -Force $OutputDir | Out-Null + +# ------------------------------------------------------------------ +# コンソールのコード ページを先に UTF-8 にしておく +# ------------------------------------------------------------------ +# z_Common.bat は先頭で chcp 65001 を実行する。コード ページはコンソール +# 全体の設定なので、子プロセスで変えても呼び出し元の画面に影響する。 +# 日本語環境の既定は 932 で、932 → 65001 の切り替わりで画面が再描画され、 +# **それまでに表示したステップの結果が消える**。 +# +# z_Common.bat を最初に呼ぶのは 2_Build_NuGet_net48.bat(3 ステップ目)なので、 +# 何も表示していない今のうちに切り替えておけば、実行中は変化しない。 +# +# 元に戻さないのは、戻す操作でも再描画が起きてサマリが消えるため。 +# 各ビルド バッチも 65001 にしたまま終了するので、挙動は従来と同じ。 +if ((cmd /c chcp) -notmatch '65001') +{ + cmd /c chcp 65001 | Out-Null +} + +# コンソールのコード ページとは別に、PowerShell 側の出力エンコードも合わせる。 +# Windows PowerShell 5.1 は起動時の値を保持しており、実行中にコード ページが +# 変わっても追随しない。ここを合わせないと、バッチ(UTF-8 で出力)の内容を +# 旧コード ページで解釈してしまい、ログとエラー一覧が文字化けする。 +# ※ 2 回目以降の実行ではコード ページが既に 65001 で上の分岐を通らないため、 +# この処理は分岐の外に置く必要がある。 +if ([Console]::OutputEncoding.CodePage -ne 65001) +{ + [Console]::OutputEncoding = New-Object Text.UTF8Encoding $false +} + +# ------------------------------------------------------------------ +# ビルド ステップの定義(0_ExecAllBat.bat と同じ順序・同じ内容) +# ------------------------------------------------------------------ +# Clean = $true のものは -SkipClean で省略される。 +$steps = @( + # --- net48 : 基盤 --- + @{ Name = "Clean (net48 基盤)"; Bat = "1_DeleteDir.bat"; Clean = $true } + @{ Name = "Clean files (net48 基盤)"; Bat = "1_DeleteFile.bat"; Clean = $true } + @{ Name = "NuGet (net48)"; Bat = "2_Build_NuGet_net48.bat" } + @{ Name = "Business (net48)"; Bat = "3_Build_Business_net48.bat" } + @{ Name = "Business.RichClient (net48)"; Bat = "3_Build_BusinessRichClient_net48.bat" } + + # --- netcore100 : 基盤 --- + @{ Name = "Clean (core 基盤)"; Bat = "1_DeleteDir.bat"; Clean = $true } + @{ Name = "Clean files (core 基盤)"; Bat = "1_DeleteFile.bat"; Clean = $true } + @{ Name = "NuGet (netcore100)"; Bat = "2_Build_NuGet_netcore100.bat" } + @{ Name = "Business (netcore100)"; Bat = "3_Build_Business_netcore100.bat" } + @{ Name = "Business.RichClient (core)"; Bat = "3_Build_BusinessRichClient_netcore100.bat" } + + # --- 参照用アセンブリのコピー --- + @{ Name = "CopyAssemblies"; Bat = "4_Build_CopyAssemblies.bat" } + + # --- net48 : ツールとサンプル --- + @{ Name = "Clean (net48 サンプル)"; Bat = "1_DeleteDir.bat"; Clean = $true } + @{ Name = "Clean files (net48 サンプル)"; Bat = "1_DeleteFile.bat"; Clean = $true } + @{ Name = "Framework_Tool (net48)"; Bat = "4_Build_Framework_Tool.bat" } + @{ Name = "2CS_sample (net48)"; Bat = "5_Build_2CS_sample.bat" } + @{ Name = "Bat_sample (net48)"; Bat = "5_Build_Bat_sample.bat" } + @{ Name = "CLI_sample (net48)"; Bat = "5_Build_CLI_sample.bat" } + @{ Name = "WSSrv_sample (net48)"; Bat = "6_Build_WSSrv_sample.bat" } + @{ Name = "Framework_WS (net48)"; Bat = "7_Build_Framework_WS.bat" } + @{ Name = "WSClnt_sample (net48)"; Bat = "8_Build_WSClnt_sample.bat" } + @{ Name = "WebApp_sample (net48)"; Bat = "10_Build_WebApp_sample.bat" } + + # --- netcore100 : ツールとサンプル --- + @{ Name = "Clean (core サンプル)"; Bat = "1_DeleteDir.bat"; Clean = $true } + @{ Name = "Clean files (core サンプル)"; Bat = "1_DeleteFile.bat"; Clean = $true } + @{ Name = "Framework_ToolCore"; Bat = "4_Build_Framework_ToolCore.bat" } + @{ Name = "2CSCore_sample"; Bat = "5_Build_2CSCore_sample.bat" } + @{ Name = "BatCore_sample"; Bat = "5_Build_BatCore_sample.bat" } + @{ Name = "CLICore_sample"; Bat = "5_Build_CLICore_sample.bat" } + @{ Name = "WSSrvCore_sample"; Bat = "6_Build_WSSrvCore_sample.bat" } + @{ Name = "Framework_WSCore"; Bat = "7_Build_Framework_WSCore.bat" } + @{ Name = "WSClntCore_sample"; Bat = "8_Build_WSClntCore_sample.bat" } + @{ Name = "WebAppCore_sample"; Bat = "10_Build_WebAppCore_sample.bat" } +) + +# ------------------------------------------------------------------ +# 出力の解析 +# ------------------------------------------------------------------ +# MSBuild のエラー・警告行は「: error CS1002:」のような形式で、 +# コード部分はロケールによらないため、これを抽出する。 +# ("ビルドに成功しました" 等のサマリ文言は日本語環境で変わるため使わない) +# +# ※ コードを伴わない「: error :」形式もある。 +#   例: NuGet の restore 失敗 +#   Microsoft.NuGet.targets(198,5): error : Your project does not reference ... +#   このためコード部分は省略可能として扱う。 +function Get-Diagnostics([string[]]$lines) +{ + $errors = New-Object System.Collections.Generic.List[string] + $warnings = New-Object System.Collections.Generic.List[string] + + foreach ($line in $lines) + { + if ($line -match ':\s*error(\s+[A-Za-z]+\d+)?\s*:') + { + $errors.Add($line.Trim()) + } + elseif ($line -match ':\s*warning(\s+[A-Za-z]+\d+)?\s*:') + { + $warnings.Add($line.Trim()) + } + elseif ($line -match '^\s*\[ERROR\]') + { + # z_Common.bat が MSBuild 未検出時に出力する独自のエラー + $errors.Add($line.Trim()) + } + } + + # 同一の指摘が複数プロジェクトから重複して出るため、一意化する。 + return [pscustomobject]@{ + Errors = @($errors | Select-Object -Unique) + Warnings = @($warnings | Select-Object -Unique) + } +} + +# -IgnoreErrors に指定された正規表現のいずれかに一致するか。 +# 一致したものは合否判定から外すが、握り潰しにならないよう別枠で一覧する。 +function Test-KnownError([string]$line) +{ + foreach ($pattern in $IgnoreErrors) + { + if ($line -match $pattern) + { + return $true + } + } + return $false +} + +# ------------------------------------------------------------------ +# 実行 +# ------------------------------------------------------------------ +Push-Location $csRoot +$results = @() +$allErrors = New-Object System.Collections.Generic.List[string] +$allKnown = New-Object System.Collections.Generic.List[string] +$total = [Diagnostics.Stopwatch]::StartNew() + +foreach ($s in $steps) +{ + if ($Only -and ($s.Name -notlike "*$Only*") -and ($s.Bat -notlike "*$Only*")) + { + continue + } + if ($SkipClean -and $s.Clean) + { + continue + } + + $bat = Join-Path $csRoot $s.Bat + if (-not (Test-Path $bat)) + { + Write-Host (" [{0}] バッチが見つかりません : {1}" -f $s.Name, $s.Bat) -ForegroundColor Red + $results += [pscustomobject]@{ ステップ = $s.Name; 結果 = "バッチ無し"; エラー = "-"; 警告 = "-"; 秒 = "-" } + continue + } + + Write-Host ("=== {0} ===" -f $s.Name) -ForegroundColor Cyan + + $safe = ($s.Name -replace '[^A-Za-z0-9]', '_') + $log = Join-Path $OutputDir "$safe.log" + $sw = [Diagnostics.Stopwatch]::StartNew() + + # 各バッチは末尾に pause を持つため、stdin を与えて実行する + # (0_ExecAllBat.bat の "echo | call ..." と同じ方式)。 + cmd /c "echo. | call `"$bat`"" *>&1 | Out-File $log -Encoding UTF8 + $sw.Stop() + + $diag = Get-Diagnostics (Get-Content $log -EA SilentlyContinue) + + # 既知のエラーを判定対象から外す。件数はサマリに残すため、捨てずに分けて持つ。 + $stepErrors = New-Object System.Collections.Generic.List[string] + $stepKnown = New-Object System.Collections.Generic.List[string] + + foreach ($e in $diag.Errors) + { + if (Test-KnownError $e) + { + $stepKnown.Add($e) + $allKnown.Add(("[{0}] {1}" -f $s.Name, $e)) + } + else + { + $stepErrors.Add($e) + $allErrors.Add(("[{0}] {1}" -f $s.Name, $e)) + } + } + + $verdict = if ($stepErrors.Count -eq 0) { "OK" } else { "NG" } + $color = if ($verdict -eq "OK") { "Green" } else { "Red" } + $knownNote = if ($stepKnown.Count -gt 0) { " / 既知 {0}" -f $stepKnown.Count } else { "" } + Write-Host (" {0} エラー {1} / 警告 {2}{3} ({4:N1} 秒)" -f ` + $verdict, $stepErrors.Count, $diag.Warnings.Count, $knownNote, $sw.Elapsed.TotalSeconds) -ForegroundColor $color + + $results += [pscustomobject]@{ + ステップ = $s.Name + 結果 = $verdict + エラー = $stepErrors.Count + 既知 = $stepKnown.Count + 警告 = $diag.Warnings.Count + 秒 = [Math]::Round($sw.Elapsed.TotalSeconds, 1) + } +} + +$total.Stop() +Pop-Location + +# ------------------------------------------------------------------ +# サマリ +# ------------------------------------------------------------------ +Write-Host "" +Write-Host "================ サマリ ================" +$results | Format-Table -AutoSize | Out-String | Write-Host +Write-Host (" 所要時間 : {0:N1} 分" -f $total.Elapsed.TotalMinutes) +Write-Host (" ログ : {0}" -f $OutputDir) + +if ($allErrors.Count -gt 0) +{ + Write-Host "" + Write-Host "================ エラー一覧 ================" -ForegroundColor Red + $allErrors | Select-Object -First 30 | ForEach-Object { Write-Host (" " + $_) } + if ($allErrors.Count -gt 30) + { + Write-Host (" ... 他 {0} 件(詳細はログを参照)" -f ($allErrors.Count - 30)) + } +} + +# 除外したものは必ず表示する。黙って消すと、-IgnoreErrors が広すぎたときに気付けない。 +if ($allKnown.Count -gt 0) +{ + Write-Host "" + Write-Host "======== 既知として除外したエラー ========" -ForegroundColor Yellow + Write-Host (" 除外条件 : {0}" -f ($IgnoreErrors -join " , ")) + $allKnown | Select-Object -First 30 | ForEach-Object { Write-Host (" " + $_) } + if ($allKnown.Count -gt 30) + { + Write-Host (" ... 他 {0} 件(詳細はログを参照)" -f ($allKnown.Count - 30)) + } +} + +$ng = @($results | Where-Object { $_.結果 -ne "OK" }) +Write-Host "" +if ($ng.Count -eq 0) +{ + Write-Host " 全ステップ OK" -ForegroundColor Green + exit 0 +} +else +{ + Write-Host (" {0} ステップが NG" -f $ng.Count) -ForegroundColor Red + exit 1 +} diff --git a/root/programs/2_RunAllTests.ps1 b/root/programs/2_RunAllTests.ps1 new file mode 100644 index 000000000..b23792343 --- /dev/null +++ b/root/programs/2_RunAllTests.ps1 @@ -0,0 +1,331 @@ +<# +.SYNOPSIS + 単体テストのビルド バッチを実行し、再生成された結果ファイルを HEAD と比較して合否を一覧する。 + +.DESCRIPTION + リリース時の「単体テスト スクリプトの実行結果を diff で目視」を機械化したもの(#513 段階 1)。 + + <既存の運用> + y_Build_TestCode*.bat は「ビルド → テスト実行 → 結果を Result*.txt へ出力」まで行う。 + この Result*.txt は Git 管理下にあり、バッチを実行すると上書きされる。 + すなわち従来の手順は次のとおりだった。 + + 1. バッチを実行して Result*.txt を再生成する + 2. git diff で「前回のリリース時の結果」との差分を目視する + + <本スクリプト> + 同じ構造のまま、2 の目視を機械比較に置き換える。 + + 期待値 : HEAD にコミットされている Result*.txt(git show で取得) + 実測値 : バッチが再生成したワーキング ツリーの Result*.txt + + 比較は CompareResult.ps1 が行い、実行ごとに変わる値(日時・処理時間・ + スレッド ID・パス・署名値等)を正規化してから差分を取る。 + + <ビルドをバッチに委ねている理由> + csproj / sln を直接 msbuild すると、nuget.exe restore が行うネイティブ DLL の + 配置(Microsoft.Data.SqlClient.SNI 等)が漏れ、実行時に DllNotFoundException になる。 + 「何をどうビルドするか」の正はバッチ側に置く。 + + <前提> + ・Frameworks をビルド済み(Build_net48 / Build_netcore100 が存在すること) + ・SQL Server の Northwind に接続できること(TestBatch が使用) + + <副作用> + ワーキング ツリーの Result*.txt が書き換わる。これは従来のバッチ運用と同じで、 + 内容の検収(コミットするか戻すか)は人が git diff で判断する。 + +.PARAMETER OutputDir + HEAD 版の期待値とビルド ログの出力先。既定は %TEMP%\OpenTouryoTestResults。 + +.PARAMETER SkipBuild + バッチの実行を省略し、ワーキング ツリーにある既存の Result*.txt を比較する。 + +.EXAMPLE + .\2_RunAllTests.ps1 + +.EXAMPLE + .\2_RunAllTests.ps1 -SkipBuild + +.NOTES + 作成者 :玄人 幸道 + 更新履歴 : + 日時 更新者 内容 + ---------- ---------------- ------------------------------------------------- + 2026/08/01 玄人 幸道 新規作成(リリース ワークのエージェント化) +#> +[CmdletBinding()] +param( + [string]$OutputDir = (Join-Path $env:TEMP "OpenTouryoTestResults"), + [switch]$SkipBuild +) + +$ErrorActionPreference = "Continue" + +# ------------------------------------------------------------------ +# カレント ディレクトリからの実行を許可する +# ------------------------------------------------------------------ +# PowerShell は子プロセスに NoDefaultCurrentDirectoryInExePath=1 を渡す。 +# 一方 y_Build_TestCode*.bat は、出力フォルダへ cd したうえで +# SimpleBatch.exe /Dap SQL ... +# のようにパス区切りを含まない名前で実行するため、この変数が効いていると +# 'SimpleBatch.exe' is not recognized as an internal or external command +# となり、結果ファイルが空になる(バッチ自体は成功扱いで進む)。 +# バッチを直接ダブル クリックした場合と同じ条件にするため、ここで解除する。 +Remove-Item Env:\NoDefaultCurrentDirectoryInExePath -EA SilentlyContinue + +# 本スクリプトは root\programs に置き、C# 側(root\programs\CS)を対象とする。 +$progRoot = $PSScriptRoot +# ビルド バッチ(y_Build_TestCode*.bat)が置かれている root\programs\CS +$csRoot = Join-Path $progRoot "CS" +# 単体テストのプロジェクトと結果ファイルが置かれている場所 +$testsRoot = Join-Path $csRoot "Frameworks\Tests" +$repoRoot = (& git -C $testsRoot rev-parse --show-toplevel) +New-Item -ItemType Directory -Force $OutputDir | Out-Null + +# ------------------------------------------------------------------ +# コンソールのコード ページを先に UTF-8 にしておく +# ------------------------------------------------------------------ +# ビルド バッチが呼ぶ z_Common.bat は先頭で chcp 65001 を実行する。 +# コード ページはコンソール全体の設定なので、子プロセスで変えても +# 呼び出し元の画面に影響し、日本語環境の既定 932 からの切り替わりで +# 画面が再描画されて**それまでの表示が消える**。 +# 何も表示していない今のうちに切り替えておけば、実行中は変化しない。 +# 戻さないのは、戻す操作でも再描画が起きてサマリが消えるため。 +if ((cmd /c chcp) -notmatch '65001') +{ + cmd /c chcp 65001 | Out-Null +} + +# コンソールのコード ページとは別に、PowerShell 側の出力エンコードも合わせる。 +# Windows PowerShell 5.1 は起動時の値を保持しており、実行中にコード ページが +# 変わっても追随しない。ここを合わせないと、バッチ(UTF-8 で出力)の内容を +# 旧コード ページで解釈してしまい、ログとエラー一覧が文字化けする。 +# ※ 2 回目以降の実行ではコード ページが既に 65001 で上の分岐を通らないため、 +# この処理は分岐の外に置く必要がある。 +if ([Console]::OutputEncoding.CodePage -ne 65001) +{ + [Console]::OutputEncoding = New-Object Text.UTF8Encoding $false +} + +# ------------------------------------------------------------------ +# テスト証明書の配置 +# ------------------------------------------------------------------ +# EncAndDecUtilCUI の csproj は *.cer / *.pfx を CopyToOutputDirectory しているため、 +# これらが無いとビルドが MSB3030 で失敗する。 +# y_Build_TestCode_SecCUI.bat も copy_cert.bat を呼ぶが、そちらは C:\root\files\... を +# 参照するため、リポジトリだけを clone した環境では配置できない。 +# ここではリポジトリ内の正本(root/files/resource/X509/)から補う。 +function Copy-TestCertificates +{ + $destDir = Join-Path $testsRoot "EncAndDecUtilCUI" + $srcDir = Join-Path $testsRoot "..\..\..\..\files\resource\X509" + + if (-not (Test-Path $srcDir)) + { + Write-Host " 証明書の正本フォルダが見つかりません : $srcDir" -ForegroundColor Yellow + return + } + + $names = @("SHA256RSA", "SHA256DSA", "SHA256ECDSA", "SHA384ECDSA", "SHA521ECDSA") + $copied = 0 + + foreach ($n in $names) + { + foreach ($ext in @("cer", "pfx")) + { + $dest = Join-Path $destDir "$n.$ext" + if (Test-Path $dest) { continue } + + $src = Join-Path $srcDir "$n.$ext" + if (Test-Path $src) + { + Copy-Item $src $dest -Force + $copied++ + } + else + { + Write-Host (" 証明書が見つかりません : {0}" -f $src) -ForegroundColor Yellow + } + } + } + + if ($copied -gt 0) + { + Write-Host (" テスト証明書を {0} 件配置しました。" -f $copied) + } +} + +# ------------------------------------------------------------------ +# テストの定義 +# ------------------------------------------------------------------ +# Result : バッチが再生成する結果ファイル(Tests からの相対パス) +# = 期待値でもある(HEAD 版と比較する) +# Bat : ビルドとテスト実行を行うバッチ(root\programs\CS 配下) +# SkipLog4net : log4net の内部トレースを比較対象から外すか +$tests = @( + @{ + Name = "TestCode (net48)"; Bat = "y_Build_TestCode_Public.bat" + Result = "TestCode\Result48.txt"; SkipLog4net = $false + } + @{ + Name = "TestCode (net10.0)"; Bat = "y_Build_TestCode_Public.bat" + Result = "TestCode\ResultCore100.txt"; SkipLog4net = $false + } + @{ + Name = "TestDataAccess (net48)"; Bat = "y_Build_TestCode_DataAccess.bat" + Result = "TestDataAccess\Result48.txt"; SkipLog4net = $false + } + @{ + Name = "TestDataAccess (net10.0)"; Bat = "y_Build_TestCode_DataAccess.bat" + Result = "TestDataAccess\ResultCore100.txt"; SkipLog4net = $false + } + @{ + Name = "SimpleBatch (net48)"; Bat = "y_Build_TestCode_Batch.bat" + Result = "TestBatch\ResultSimpleBatch48.txt"; SkipLog4net = $true + } + @{ + Name = "SimpleBatch (net10.0)"; Bat = "y_Build_TestCode_Batch.bat" + Result = "TestBatch\ResultSimpleBatchCore100.txt"; SkipLog4net = $true + } + @{ + Name = "EncAndDecUtilCUI (net48)"; Bat = "y_Build_TestCode_SecCUI.bat" + Result = "EncAndDecUtilCUI\Result48.txt"; SkipLog4net = $false + } + @{ + Name = "EncAndDecUtilCUI (net10.0)"; Bat = "y_Build_TestCode_SecCUI.bat" + Result = "EncAndDecUtilCUI\ResultCore100.txt"; SkipLog4net = $false + } +) + +# ------------------------------------------------------------------ +# 期待値(HEAD 版)の取り出し +# ------------------------------------------------------------------ +# バッチがワーキング ツリーの Result*.txt を上書きするため、 +# 上書きされる前に HEAD の内容を退避しておく。 +# ※ git show は参照系のみ。ワーキング ツリーには一切触れない。 +Write-Host "=== 事前準備 ===" -ForegroundColor Cyan +Copy-TestCertificates + +$expectedOf = @{} + +foreach ($t in $tests) +{ + $full = Join-Path $testsRoot $t.Result + # git が扱えるようリポジトリ相対・スラッシュ区切りにする + $rel = ($full.Substring($repoRoot.Length).TrimStart('\','/') -replace '\\','/') + $safe = ($t.Name -replace '[^A-Za-z0-9]', '_') + $dst = Join-Path $OutputDir "expected_$safe.txt" + + # バイト列を保つため cmd のリダイレクトで受ける + # (PowerShell のパイプを経由すると再エンコードされる) + cmd /c "git -C `"$repoRoot`" show `"HEAD:$rel`" > `"$dst`" 2>nul" + + if ((Test-Path $dst) -and (Get-Item $dst).Length -gt 0) + { + $expectedOf[$t.Name] = $dst + } + else + { + Write-Host (" HEAD から取得できません : {0}" -f $rel) -ForegroundColor Yellow + } +} + +Write-Host (" 期待値(HEAD 版)を {0} 件退避しました。" -f $expectedOf.Count) + +# ------------------------------------------------------------------ +# ビルドとテスト実行 +# ------------------------------------------------------------------ +# 1 本のバッチが net48 版と .NET (Core) 版の両方をビルド・実行するため、 +# 同一バッチは 1 回だけ実行する。 +if (-not $SkipBuild) +{ + foreach ($bat in ($tests | ForEach-Object { $_.Bat } | Select-Object -Unique)) + { + Write-Host "" + Write-Host ("=== ビルドと実行 : {0} ===" -f $bat) -ForegroundColor Cyan + + $path = Join-Path $csRoot $bat + if (-not (Test-Path $path)) + { + Write-Host " バッチが見つかりません" -ForegroundColor Red + continue + } + + $log = Join-Path $OutputDir ("build_" + ($bat -replace '[^A-Za-z0-9]','_') + ".log") + $sw = [Diagnostics.Stopwatch]::StartNew() + + Push-Location $csRoot + # バッチ末尾の pause に対応するため stdin を与える。 + cmd /c "echo. | call `"$path`"" *>&1 | Out-File $log -Encoding UTF8 + Pop-Location + + $sw.Stop() + Write-Host (" 完了 ({0:N1} 秒) ログ : {1}" -f $sw.Elapsed.TotalSeconds, $log) + } +} + +# ------------------------------------------------------------------ +# 比較 +# ------------------------------------------------------------------ +$cmp = Join-Path $progRoot "CompareResult.ps1" +$results = @() + +foreach ($t in $tests) +{ + Write-Host "" + Write-Host ("=== {0} ===" -f $t.Name) -ForegroundColor Cyan + + $actual = Join-Path $testsRoot $t.Result + + if (-not $expectedOf.ContainsKey($t.Name)) + { + Write-Host " 期待値(HEAD 版)が無いため比較できません" -ForegroundColor Red + $results += [pscustomobject]@{ テスト = $t.Name; 結果 = "期待値無し"; 差分 = "-" } + continue + } + if (-not (Test-Path $actual)) + { + Write-Host " 結果ファイルが生成されていません" -ForegroundColor Red + $results += [pscustomobject]@{ テスト = $t.Name; 結果 = "結果無し"; 差分 = "-" } + continue + } + + # CompareResult.ps1 は画面表示に Write-Host を使うため、 + # 件数は -PassThru のオブジェクトで受け取る。 + if ($t.SkipLog4net) + { + $cmpResult = & $cmp -Expected $expectedOf[$t.Name] -Actual $actual -SkipLog4netTrace -PassThru + } + else + { + $cmpResult = & $cmp -Expected $expectedOf[$t.Name] -Actual $actual -PassThru + } + + $results += [pscustomobject]@{ + テスト = $t.Name + 結果 = $cmpResult.Result + 差分 = $cmpResult.DiffCount + } +} + +# ------------------------------------------------------------------ +# サマリ +# ------------------------------------------------------------------ +Write-Host "" +Write-Host "================ サマリ ================" +$results | Format-Table -AutoSize | Out-String | Write-Host +Write-Host (" 期待値・ログ : {0}" -f $OutputDir) +Write-Host " 実測値 : ワーキング ツリーの Result*.txt(git diff で確認できます)" + +$ng = @($results | Where-Object { $_.結果 -ne "OK" }) +if ($ng.Count -eq 0) +{ + Write-Host " 全テスト OK" -ForegroundColor Green + exit 0 +} +else +{ + Write-Host (" {0} 件が NG" -f $ng.Count) -ForegroundColor Yellow + exit 1 +} diff --git a/root/programs/3_SmokeTest.ps1 b/root/programs/3_SmokeTest.ps1 new file mode 100644 index 000000000..0339aa960 --- /dev/null +++ b/root/programs/3_SmokeTest.ps1 @@ -0,0 +1,1156 @@ +<# +.SYNOPSIS + サンプル アプリを起動して疎通を確認し、合否を一覧する。 + +.DESCRIPTION + リリース時の「サンプルを幾つか見繕って手動で疎通を行う」を機械化したもの(#513 段階 3)。 + + <段階 1・2 との違い> + 段階 1(2_RunAllTests.ps1)は「出力が前回と同じか」を見る回帰テスト。 + 本スクリプトは「起動して、想定どおり動き、例外なく終わるか」を見る疎通テスト。 + 期待結果ファイルは持たず、判定条件を定義側に書く。 + + <対象> + 非 UI 系(バッチ・CLI)と Web 系(Web アプリ・Web サービス)。 + WinForms / WPF 系は UI Automation が必要で維持費が高いため対象外とし、 + リリース チェックリストの手作業項目として残す。 + + <ビルド> + リポジトリ既定のビルド バッチを呼ぶ。理由は 2_RunAllTests.ps1 と同じで、 + csproj を直接ビルドすると nuget.exe restore が行うネイティブ DLL の配置が漏れる。 + + なお 0_ExecAllBat.bat は途中で 1_DeleteDir.bat を繰り返し実行し、 + 配下の bin / obj を再帰的に削除する。このため 1_BuildAll.ps1 の完走後に + 残るのは最後にビルドされた Core サンプルだけで、net48 サンプルは残らない。 + 本スクリプトが自分でビルドするのはこのため。 + + <DB> + SQL Server の Northwind を使用する。 + RerunnableBatch 系は Orders(830 件) を読み Orders2 へ INSERT するため、 + 実行前に Orders2 を空にする必要がある。実行後は 830 件=初期状態に戻る。 + +.PARAMETER Only + 対象名の部分一致で絞る(例: -Only "Rerunnable")。 + +.PARAMETER SkipBuild + ビルドを省略し、既存のバイナリで疎通のみ行う。 + +.PARAMETER OutputDir + ログの保存先。既定は %TEMP%\OpenTouryoSmokeTest。 + +.EXAMPLE + .\3_SmokeTest.ps1 + +.EXAMPLE + .\3_SmokeTest.ps1 -Only "net48" -SkipBuild + +.NOTES + 作成者 :玄人 幸道 + 更新履歴 : + 日時 更新者 内容 + ---------- ---------------- ------------------------------------------------- + 2026/08/01 玄人 幸道 新規作成(リリース ワークのエージェント化) + 2026/08/07 玄人 幸道 Orders2が無ければ作成するようにした +#> +[CmdletBinding()] +param( + [string]$Only, + [switch]$SkipBuild, + [string]$OutputDir = (Join-Path $env:TEMP "OpenTouryoSmokeTest") +) + +$ErrorActionPreference = "Continue" + +# ------------------------------------------------------------------ +# カレント ディレクトリからの実行を許可する +# ------------------------------------------------------------------ +# PowerShell は子プロセスに NoDefaultCurrentDirectoryInExePath=1 を渡すが、 +# ビルド バッチは出力フォルダへ cd したうえでパス区切りを含まない名前で +# 実行するため、これが効いていると exe を起動できない。 +# (TESTING.md の「PowerShell から .bat を呼ぶときの注意」と同じ) +Remove-Item Env:\NoDefaultCurrentDirectoryInExePath -EA SilentlyContinue + +# 本スクリプトは root\programs に置き、C# 側(root\programs\CS)を対象とする。 +# ビルド バッチもサンプルも CS 配下にあるため、そこを起点にする。 +$csRoot = Join-Path $PSScriptRoot "CS" +New-Item -ItemType Directory -Force $OutputDir | Out-Null + +# 対象に与える stdin(空)。 +# Start-Process -RedirectStandardInput は実在するファイルを要求するため、先に作る。 +# これが無いと Console.ReadKey() が本当にキー入力を待つ。 +$emptyIn = Join-Path $OutputDir "empty.in" +if (-not (Test-Path $emptyIn)) +{ + New-Item -ItemType File $emptyIn | Out-Null +} + +# ------------------------------------------------------------------ +# コンソールのコード ページを先に UTF-8 にしておく +# ------------------------------------------------------------------ +# ビルド バッチが呼ぶ z_Common.bat は先頭で chcp 65001 を実行する。 +# コード ページはコンソール全体の設定なので、子プロセスで変えても +# 呼び出し元の画面に影響し、日本語環境の既定 932 からの切り替わりで +# 画面が再描画されて**それまでの表示が消える**。 +# 何も表示していない今のうちに切り替えておけば、実行中は変化しない。 +# 戻さないのは、戻す操作でも再描画が起きてサマリが消えるため。 +if ((cmd /c chcp) -notmatch '65001') +{ + cmd /c chcp 65001 | Out-Null +} + +# コンソールのコード ページとは別に、PowerShell 側の出力エンコードも合わせる。 +# Windows PowerShell 5.1 は起動時の値を保持しており、実行中にコード ページが +# 変わっても追随しない。ここを合わせないと、バッチ(UTF-8 で出力)の内容を +# 旧コード ページで解釈してしまい、ログとエラー一覧が文字化けする。 +# ※ 2 回目以降の実行ではコード ページが既に 65001 で上の分岐を通らないため、 +# この処理は分岐の外に置く必要がある。 +if ([Console]::OutputEncoding.CodePage -ne 65001) +{ + [Console]::OutputEncoding = New-Object Text.UTF8Encoding $false +} + +# ------------------------------------------------------------------ +# 接続文字列 +# ------------------------------------------------------------------ +# サンプルが実際に使う App.config から読む。 +# ここで別途ハードコードすると、サンプル側の変更に追随できなくなる。 +function Get-SampleConnectionString +{ + $config = Join-Path $csRoot "Samples\Bat_sample\SimpleBatch_sample\App.config" + if (-not (Test-Path $config)) { return $null } + + $xml = [xml](Get-Content $config -Raw) + $node = $xml.configuration.connectionStrings.add | + Where-Object { $_.name -eq "ConnectionString_SQL" } + return $node.connectionString +} + +$connString = Get-SampleConnectionString + +function Invoke-Sql([string]$sql) +{ + $c = New-Object System.Data.SqlClient.SqlConnection $connString + $c.Open() + try + { + $cmd = $c.CreateCommand() + $cmd.CommandText = $sql + return $cmd.ExecuteScalar() + } + finally { $c.Close() } +} + +# ------------------------------------------------------------------ +# 対象の定義 +# ------------------------------------------------------------------ +# Name : 表示名 +# Bat : ビルドに使うバッチ(root\programs\CS 配下) +# Exe : 実行ファイル(net48)。Dll を指定した場合は dotnet で実行する。 +# Args : コマンドライン引数 +# Pre : 実行前に行う準備(スクリプト ブロック) +# Expect : 標準出力がこの正規表現に一致すれば成功 +# Verify : 追加の検証(スクリプト ブロック)。$true を返せば成功 +# +# ※ サンプルは末尾に Console.ReadKey() を持つため、出力をリダイレクトすると +# 必ず例外で終わる。これはテスト内容とは無関係なので、判定から除外する。 +$batchArgs = @("/DAP", "SQL", "/MODE1", "individual", "/MODE2", "static", "/EXROLLBACK", "-") + +# ------------------------------------------------------------------ +# Orders2(Northwind 標準には無い表) +# ------------------------------------------------------------------ +# instnwnd.sql に含まれないため、**DB を作り直すたびに消える**。 +# 無いまま実行すると「オブジェクト名 'Orders2' が無効です」で事前準備が落ち、 +# 原因が読み取れない。ここで作ってしまう。 +# +# DDL は同梱の CREATE ORDERS2.sql をそのまま流す。**ここに書き写さない。** +# (同じ DDL がサンプル配下に 9 つ重複しており、さらに増やす意味がない) +function Initialize-Orders2 +{ + $exists = Invoke-Sql "SELECT OBJECT_ID('dbo.Orders2', 'U')" + if ($null -ne $exists -and $exists -isnot [DBNull]) { return } + + $ddl = Join-Path $csRoot "Samples\Bat_sample\RerunnableBatch_sample\CREATE ORDERS2.sql" + if (-not (Test-Path $ddl)) + { + throw "Orders2 が無く、DDL も見つかりません : $ddl" + } + + Write-Host " Orders2 がありません。作成します($ddl)。" + + # sqlcmd ではなく SqlClient で流すため、GO(バッチ区切り)は自前で分ける。 + # SqlClient は GO を解釈できず、構文エラーになる。 + foreach ($batch in ((Get-Content $ddl -Raw) -split '(?im)^\s*GO\s*$')) + { + # USE は流さない。接続先は接続文字列に従う(別 DB を指していても壊さない)。 + if ($batch -match '\S' -and $batch -notmatch '(?im)^\s*USE\s') + { + Invoke-Sql $batch | Out-Null + } + } +} + +# RerunnableBatch 系は Orders → Orders2 の INSERT。実行前に Orders2 を空にする。 +$clearOrders2 = { + Initialize-Orders2 + Invoke-Sql "DELETE FROM [Orders2]" | Out-Null +} +# 実行後は Orders と同数(830 件)になっていること。 +$verifyOrders2 = { + $src = [int](Invoke-Sql "SELECT COUNT(*) FROM [Orders]") + $dst = [int](Invoke-Sql "SELECT COUNT(*) FROM [Orders2]") + Write-Host (" Orders {0} 件 → Orders2 {1} 件" -f $src, $dst) + return ($dst -eq $src -and $src -gt 0) +} + +# ------------------------------------------------------------------ +# DaoGen_Tool(墨壺)の CUI モード +# ------------------------------------------------------------------ +# #508 で追加された CUI。2 モードを DAODEFGEN → DAOSQLGEN の順に実行し、 +# 前段が出力した定義 CSV を後段の入力に使う。 +# +# <パス区切りの注意> +# コマンドライン解析(StringVariableOperator.GetCommandArgs)は +# 「\」をエスケープ文字として扱うため、パスの区切りは「/」にする。 +# 「C:\temp\out」と書くと「\」が消えて別のパスになる(ツールの /HELP にも記載)。 +# +# <テンプレート> +# root/files/tools/DGenTemplates(DaoTemplate*.cs / *Template.xml などの平置き)。 + +$daoGenTemplate = ((Join-Path $csRoot "..\..\files\tools\DGenTemplates" | Resolve-Path).Path) -replace '\\', '/' + +# 対象を 2 テーブルに絞る。全テーブルを回すと時間がかかるだけで、 +# 疎通の確認としては同じことを見ている。 +$daoGenTables = "Shippers,Orders" + +# 作業フォルダを作る(net48 / Core で分ける) +function New-DaoGenWork([string]$tag) +{ + $work = Join-Path $OutputDir "daogen_$tag" + New-Item -ItemType Directory -Force (Join-Path $work "gen") | Out-Null + # 前回の生成物を残さない(残っていると「生成された」の判定が甘くなる) + Get-ChildItem $work -Recurse -File -EA SilentlyContinue | Remove-Item -Force -EA SilentlyContinue + return $work +} + +function New-DaoGenArgs([string]$tag, [string]$mode) +{ + $work = Join-Path $OutputDir "daogen_$tag" + $csv = ($work + "/DaoDef.csv").Replace("\", "/") + $gen = ($work + "/gen").Replace("\", "/") + + if ($mode -eq "DAODEFGEN") + { + return @("/CUI", "/MODE", "DAODEFGEN", "/OUTPUT", $csv, "/DAP", "SQL", "/TABLES", $daoGenTables) + } + return @("/CUI", "/MODE", "DAOSQLGEN", "/DAODEF", $csv, + "/TEMPLATE", $daoGenTemplate, "/OUTPUT", $gen, + "/DAP", "SQL", "/LANG", "CS", "/ENTITY") +} + +# 定義 CSV に対象テーブルが並んでいること +function Test-DaoDef([string]$tag) +{ + $csv = Join-Path (Join-Path $OutputDir "daogen_$tag") "DaoDef.csv" + if (-not (Test-Path $csv)) { Write-Host " 定義 CSV が生成されていない"; return $false } + + $text = Get-Content $csv -Raw + $ok = ($text -match 'Shippers') -and ($text -match 'Orders') + Write-Host (" 定義 CSV : {0} 行" -f (Get-Content $csv).Count) + return $ok +} + +# Dao・DTO・SQL が生成されていること +function Test-DaoGen([string]$tag) +{ + $gen = Join-Path (Join-Path $OutputDir "daogen_$tag") "gen" + $files = @(Get-ChildItem $gen -Recurse -File -EA SilentlyContinue) + Write-Host (" 生成ファイル : {0} 件" -f $files.Count) + + # Dao クラス(.cs)と 動的 SQL(.xml)と 静的 SQL(.sql)が揃っていること + $hasCs = @($files | Where-Object { $_.Name -eq "DaoShippers.cs" }).Count -gt 0 + $hasXml = @($files | Where-Object { $_.Extension -eq ".xml" }).Count -gt 0 + $hasSql = @($files | Where-Object { $_.Extension -eq ".sql" }).Count -gt 0 + return ($hasCs -and $hasXml -and $hasSql) +} + +$prepareDaoGen48 = { [void](New-DaoGenWork "net48") } +$prepareDaoGenCore = { [void](New-DaoGenWork "core") } +$daoDefArgs48 = New-DaoGenArgs "net48" "DAODEFGEN" +$daoSqlArgs48 = New-DaoGenArgs "net48" "DAOSQLGEN" +$daoDefArgsCore = New-DaoGenArgs "core" "DAODEFGEN" +$daoSqlArgsCore = New-DaoGenArgs "core" "DAOSQLGEN" +$verifyDaoDef48 = { Test-DaoDef "net48" } +$verifyDaoGen48 = { Test-DaoGen "net48" } +$verifyDaoDefCore = { Test-DaoDef "core" } +$verifyDaoGenCore = { Test-DaoGen "core" } + +# ------------------------------------------------------------------ +# DeployZipPackWithHTTP の CUI モード +# ------------------------------------------------------------------ +# #528 で /MFTGEN(マニュフェスト生成)を追加し、生成から配置まで CUI で通せる。 +# +# <配置先を C:\ 直下にしない> +# 同梱サンプルのマニフェストは c:\FormAppRoot\ を指すが、 +# 疎通確認で環境を汚さないよう、$OutputDir 配下を指すマニフェストを作り直す。 +# +# <引数の癖>(Tools\DeployZipPackWithHTTP\README.md 3.4 節) +# ・「\」はエスケープ文字として食べられる → パスは「/」で渡す +# ・ただし /INSDIR だけは「\」を残す(ins 行がそのまま配置先になるため) +# ・空白を含む値は、自分で引用符を付ける +$deployWebPort = 51084 +$deploySampleSrc = Join-Path $csRoot "Frameworks\Tools\DeployZipPackWithHTTP\Sample\FormAppRoot" + +# **配布物(ZIP)は追跡していない。** FormAppRoot から毎回作る。 +# /ZIPGEN … ルート直下(/TOPONLY)と各フォルダ(/ROOTINZIP)を別々の ZIP にする +# /MFTGEN … その ZIP からマニュフェストを作る +# 作り置きを追跡すると、元を直したときの作り直し漏れで MD5 が合わなくなる。 +$deployZipNames = @("root", "aaa", "bbb", "ccc") + +function Get-DeployWork([string]$tag) +{ + return (Join-Path $OutputDir "deploy_$tag") +} + +# 配信フォルダを用意し、FormAppRoot から ZIP を作る +function New-DeployWeb([string]$tag, [string]$exe) +{ + $work = Get-DeployWork $tag + $web = Join-Path $work "web" + $ins = Join-Path $work "ins" + + Get-ChildItem $work -Recurse -File -EA SilentlyContinue | Remove-Item -Force -EA SilentlyContinue + New-Item -ItemType Directory -Force $web | Out-Null + New-Item -ItemType Directory -Force $ins | Out-Null + + # .mft は既定で MIME 未登録のため 404.3 になる + $conf = '<?xml version="1.0" encoding="utf-8"?>' + "`r`n" + + '<configuration><system.webServer><staticContent>' + + '<remove fileExtension=".mft" />' + + '<mimeMap fileExtension=".mft" mimeType="text/plain" />' + + '</staticContent></system.webServer></configuration>' + Set-Content (Join-Path $web "web.config") $conf -Encoding UTF8 + + #region ZIP を作る(/ZIPGEN) + + # **パスの区切りは「/」で渡す。** コマンドライン解析が「\」を食べる。 + $src = $deploySampleSrc.Replace("\", "/") + + foreach ($name in $deployZipNames) + { + $out = (Join-Path $web $name).Replace("\", "/") + + if ($name -eq "root") + { + # ルート直下だけ(サブフォルダは各 ZIP が持つ)。書庫内ルートは作らない。 + $a = @("/ZIPGEN", "/SRCDIR", $src, "/ZIPFILE", $out, "/TOPONLY") + } + else + { + # フォルダごと。書庫内ルートをフォルダ名にする(個別のフォルダ圧縮)。 + $a = @("/ZIPGEN", "/SRCDIR", "$src/$name", "/ZIPFILE", $out, "/ROOTINZIP", $name) + } + + $log = Join-Path $OutputDir "deploy_zipgen_$tag`_$name.log" + Start-Process $exe -ArgumentList $a -NoNewWindow -Wait ` + -WorkingDirectory (Split-Path $exe) -RedirectStandardOutput $log + + if (-not (Test-Path (Join-Path $web ($name + ".zip")))) + { + Write-Host (" ZIP を生成できない : {0}.zip" -f $name) + return $work + } + } + + #endregion + + return $work +} + +function New-MftGenArgs([string]$tag) +{ + $work = Get-DeployWork $tag + $web = Join-Path $work "web" + + # **ファイル一覧を採ってはいけない。** + # 引数は対象定義の時点(Pre より前)で組み立てられるため、ZIP はまだ無い。 + # 名前は決まっているので、そこから組み立てる。 + $zips = @($deployZipNames | Sort-Object | + ForEach-Object { (Join-Path $web ($_ + ".zip")).Replace("\", "/") }) -join "," + + # ins 行はそのまま配置先になるので「\」を残す(「\\」でエスケープ) + $ins = (Join-Path $work "ins") + "\" + $insArg = $ins.Replace("\", "\\") + + $mft = (Join-Path $web "FormAppRoot.mft").Replace("\", "/") + + # **exe 行はインストール先からの相対パス。** サブフォルダのものは、そう書く。 + # 二重起動チェックがこれを使うため、実在しないパスを書くと検出が効かない。 + return @("/MFTGEN", "/ZIPFILES", $zips, "/INSDIR", $insArg, + "/EXENAME", '"top.exe, aaa\\top1.exe, bbb\\top2.exe"', "/MFTFILE", $mft) +} + +# /NB … マニフェストの exe 行で指定されたアセンブリを起動しない +# /FORCE … 履歴を消して毎回やり直す(前回の結果に依存しない) +$deployArgs = @("/CUI", "/NB", "/FORCE", "/WWWURL", + ("http://localhost:{0}/FormAppRoot.mft" -f $deployWebPort)) + +# マニュフェストが生成され、MD5 が実ファイルのものと一致すること +function Test-MftGen([string]$tag) +{ + $web = Join-Path (Get-DeployWork $tag) "web" + $mft = Join-Path $web "FormAppRoot.mft" + if (-not (Test-Path $mft)) { Write-Host " マニュフェストが生成されていない"; return $false } + + $lines = @(Get-Content $mft -Encoding UTF8) + Write-Host (" マニュフェスト : {0} 行" -f $lines.Count) + + $zips = @($lines | Where-Object { $_ -like "zip *" }) + $md5s = @($lines | Where-Object { $_ -like "md5 *" }) + + if (($zips.Count -ne $deployZipNames.Count) -or ($md5s.Count -ne $deployZipNames.Count)) + { + Write-Host " zip / md5 の組数が合わない" + return $false + } + + # **書かれた MD5 を、実ファイルから計算し直して突き合わせる。** + # ここが合わないと配布時に弾かれる。作り置きの ZIP を使っていた頃は、 + # 元を直したのに ZIP を作り直さず、ここで気付けなかった。 + $md5 = [System.Security.Cryptography.MD5]::Create() + + for ($i = 0; $i -lt $zips.Count; $i++) + { + $name = $zips[$i].Substring(4).Trim() + $path = Join-Path $web $name + + if (-not (Test-Path $path)) { Write-Host (" ZIP が無い : {0}" -f $name); return $false } + + $want = $md5s[$i].Substring(4).Trim() + $got = [Convert]::ToBase64String($md5.ComputeHash([IO.File]::ReadAllBytes($path))) + + if ($want -ne $got) { Write-Host (" MD5 が一致しない : {0}" -f $name); return $false } + } + + return $true +} + +# 配置結果が、圧縮前のフォルダと一致すること +function Test-Deploy([string]$tag) +{ + $ins = Join-Path (Get-DeployWork $tag) "ins" + $md5 = [System.Security.Cryptography.MD5]::Create() + + $src = @(Get-ChildItem $deploySampleSrc -Recurse -File) + $dst = @(Get-ChildItem $ins -Recurse -File -EA SilentlyContinue) + Write-Host (" 配置 : {0} / {1} ファイル" -f $dst.Count, $src.Count) + + if ($dst.Count -ne $src.Count) { return $false } + + foreach ($f in $src) + { + $rel = $f.FullName.Substring($deploySampleSrc.Length + 1) + $t = Join-Path $ins $rel + if (-not (Test-Path $t)) { Write-Host (" 欠落 : {0}" -f $rel); return $false } + + $a = [Convert]::ToBase64String($md5.ComputeHash([IO.File]::ReadAllBytes($f.FullName))) + $b = [Convert]::ToBase64String($md5.ComputeHash([IO.File]::ReadAllBytes($t))) + if ($a -ne $b) { Write-Host (" 内容相違 : {0}" -f $rel); return $false } + } + + return $true +} + +# 配信用の IIS Express を起動・停止する +# +# Web 系の対象(Kind = "Web")は本文側が起動・停止するが、こちらは +# **EXE を実行する対象なので、その仕組みに乗らない。** +# Pre で起動し、Verify の最後で止める。 +$script:deployWebProc = $null + +function Start-DeployWeb([string]$tag) +{ + $iis = Join-Path $env:ProgramFiles "IIS Express\iisexpress.exe" + if (-not (Test-Path $iis)) { return $false } + + # **前回の残りを先に止める。** + # 起動に失敗した IIS Express が URL の登録を握ったままだと、 + # 次の起動が 0x800700b7(既に存在する)で失敗し続ける。 + Stop-DeployWeb + + $web = Join-Path (Get-DeployWork $tag) "web" + $log = Join-Path $OutputDir "deploy_web_$tag.log" + + $script:deployWebProc = Start-Process $iis ` + -ArgumentList "/path:`"$web`"", "/port:$deployWebPort", "/systray:false" ` + -PassThru -WindowStyle Hidden ` + -RedirectStandardOutput $log -RedirectStandardError "$log.err" + + # 起動を待つ(接続できるまで最大 15 秒) + # + # **コンテンツを要求して待ってはいけない。** 404 でも「起動している」ため、 + # 応答の内容で判定すると、ファイルが無いときに待ち続けて + # 起動したままのプロセスが残る。TCP で繋がるかだけを見る。 + for ($i = 0; $i -lt 30; $i++) + { + Start-Sleep -Milliseconds 500 + + $client = New-Object System.Net.Sockets.TcpClient + try + { + $client.Connect("localhost", $deployWebPort) + if ($client.Connected) { $client.Close(); return $true } + } + catch { } + finally { $client.Dispose() } + } + + Write-Host " 配信サーバが応答しない" + Stop-DeployWeb + return $false +} + +function Stop-DeployWeb +{ + if ($null -ne $script:deployWebProc) + { + try { $script:deployWebProc | Stop-Process -Force -EA SilentlyContinue } catch { } + $script:deployWebProc = $null + } +} + +# ZIP を作るのは対象と同じ実行ファイル(net48 / .NET 10 のそれぞれで確かめる) +$deployExe48 = Join-Path $csRoot "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\OpenTouryo.DeployZipPackWithHTTP.exe" +$deployExeCore = Join-Path $csRoot "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\net10.0-windows7.0\OpenTouryo.DeployZipPackWithHTTP.exe" + +$prepareDeploy48 = { [void](New-DeployWeb "net48" $deployExe48) } +$prepareDeployCore = { [void](New-DeployWeb "core" $deployExeCore) } +$mftGenArgs48 = New-MftGenArgs "net48" +$mftGenArgsCore = New-MftGenArgs "core" +$verifyMftGen48 = { Test-MftGen "net48" } +$verifyMftGenCore = { Test-MftGen "core" } +# 配置の確認が終わったら、配信サーバを止める(起動しっぱなしにしない) +$startDeployWeb48 = { [void](Start-DeployWeb "net48") } +$startDeployWebCore = { [void](Start-DeployWeb "core") } +$verifyDeploy48 = { $r = Test-Deploy "net48"; Stop-DeployWeb; return $r } +$verifyDeployCore = { $r = Test-Deploy "core"; Stop-DeployWeb; return $r } + +# ------------------------------------------------------------------ +# HTTP 要求 +# ------------------------------------------------------------------ +# リダイレクトを追わずに状態コードを見たいが、Invoke-WebRequest は +# -MaximumRedirection 0 で 3xx を受け取ると、-SkipHttpErrorCheck を付けていても +# 「The maximum redirection count has been exceeded」で終了エラーになる。 +# ここで捕まえ、3xx を正常な結果として返す。 +# Cookie を引き継ぐため、セッションは呼び出し側で作って渡す。 +function New-WebSession +{ + return New-Object Microsoft.PowerShell.Commands.WebRequestSession +} + +function Invoke-Http +{ + param( + [string]$Uri, + [string]$Method = "GET", + $Body, + $Session + ) + + $p = @{ + Uri = $Uri; Method = $Method; WebSession = $Session + MaximumRedirection = 0 + # 5.1 は既定で Internet Explorer のエンジンを使い、未構成だと解析に失敗する。 + # 7 では受け付けられて無視されるため、常に付けてよい。 + UseBasicParsing = $true + } + # -SkipHttpErrorCheck は PowerShell 7 以降にしかない。 + # 5.1 に渡すとパラメータ束縛で失敗するので付けない。 + # (5.1 では 4xx/5xx が例外になるが、下の catch で状態コードを取り出す) + if ($PSVersionTable.PSVersion.Major -ge 6) { $p.SkipHttpErrorCheck = $true } + if ($Body) { $p.Body = $Body } + + try + { + $r = Invoke-WebRequest @p -ErrorAction Stop + return [pscustomobject]@{ Status = [int]$r.StatusCode; Content = $r.Content; Length = $r.RawContentLength } + } + catch + { + $resp = $_.Exception.Response + if ($resp) { return [pscustomobject]@{ Status = [int]$resp.StatusCode; Content = ""; Length = 0 } } + return [pscustomobject]@{ Status = -1; Content = $_.Exception.Message; Length = 0 } + } +} + +# ------------------------------------------------------------------ +# Web アプリの疎通手順 +# ------------------------------------------------------------------ +# 引数でベース URL を受け取り、@{ Ok = $bool; Detail = $string } を返す。 +# +# <確認の深さを揃える> +# 3 つとも「ログインを通して、認証が要る画面に到達できること」まで見る。 +# 入口ページが 200 を返すだけでは、ホスティングと構成しか確認できない。 +# 認証が要る画面まで通せば、ルーティング・認証・セッションまでを一度に確認できる。 +# +# | 対象 | 認証の実装 | 到達を確認する画面 | +# |----------------------|---------------------|----------------------| +# | MVC_Sample (net48) | FormsAuthentication | /Crud1/Index | +# | MVC_Sample (net10.0) | Cookie 認証 | /Crud1/Index | +# | WebForms_Sample | FormsAuthentication | Aspx/start/menu.aspx | +# +# いずれのサンプルも「ユーザー名が空でなければ認証する」実装のため、資格情報は不要。 + +# MVC_Sample : net48 は FormsAuthentication、net10.0 は Cookie 認証と実装は異なるが、 +# 画面構成と URL は同じなので同じ手順で確認できる。 +# 認証後の応答は net48 が 302(RedirectFromLoginPage)、net10.0 が 200(View を返す) +# と分かれるため、ここでは 4xx/5xx でないことだけを見る。 +$mvcLoginFlow = { + param($base) + + $ses = New-WebSession + + $r1 = Invoke-Http "$base/Home/Login" -Session $ses + if ($r1.Status -ne 200) { return @{ Ok = $false; Detail = "GET /Home/Login = $($r1.Status)" } } + + # ValidateAntiForgeryToken のため、画面からトークンを取り出して送り返す。 + $tok = ([regex]::Match($r1.Content, 'name="__RequestVerificationToken"[^>]*value="([^"]+)"')).Groups[1].Value + if (-not $tok) { return @{ Ok = $false; Detail = "__RequestVerificationToken が取得できない" } } + + # 500 はセッション状態サービスの停止など、環境側の問題であることが多い。 + $body = @{ UserName = "smoke"; Password = "smoke"; normal = "ログイン"; __RequestVerificationToken = $tok } + $r2 = Invoke-Http "$base/Home/Login" -Method POST -Body $body -Session $ses + if ($r2.Status -ge 400) { return @{ Ok = $false; Detail = "POST /Home/Login = $($r2.Status)" } } + + # 認証が要る画面。未認証ならログイン画面へ 302 されるため、200 なら認証が通っている。 + $r3 = Invoke-Http "$base/Crud1/Index" -Session $ses + if ($r3.Status -ne 200) { return @{ Ok = $false; Detail = "GET /Crud1/Index = $($r3.Status)(認証が通っていない)" } } + + return @{ Ok = $true; Detail = "ログイン後 /Crud1/Index = 200" } +} + +# WebForms_Sample (net48) : Web.config で <deny users="?" /> のため全画面が要認証。 +# ログイン後は defaultUrl の menu.aspx へ遷移する。 +$webFormsFlow = { + param($base) + + $ses = New-WebSession + + $r1 = Invoke-Http "$base/Aspx/start/login.aspx" -Session $ses + if ($r1.Status -ne 200) { return @{ Ok = $false; Detail = "GET login.aspx = $($r1.Status)" } } + + # WebForms のポストバックには、画面が発行した状態フィールドをそのまま返す必要がある。 + # __VIEWSTATE が取れること自体、ページのライフサイクルが動いている証拠でもある。 + $fields = @{} + foreach ($n in @("__VIEWSTATE", "__VIEWSTATEGENERATOR", "__EVENTVALIDATION")) + { + $m = [regex]::Match($r1.Content, ('name="' + $n + '"[^>]*value="([^"]*)"')) + if (-not $m.Success) { return @{ Ok = $false; Detail = "$n が取得できない" } } + $fields[$n] = $m.Groups[1].Value + } + + # マスタ ページ配下のため、コントロール名は ctl00$ContentPlaceHolder_A$ が付く。 + # btnButton1 がログイン ボタン(btnButton2 はキャンセル)。 + $fields["ctl00`$ContentPlaceHolder_A`$txtUserID"] = "smoke" + $fields["ctl00`$ContentPlaceHolder_A`$txtPassword"] = "smoke" + $fields["ctl00`$ContentPlaceHolder_A`$btnButton1"] = "ログイン" + + $r2 = Invoke-Http "$base/Aspx/start/login.aspx" -Method POST -Body $fields -Session $ses + if ($r2.Status -ge 400) { return @{ Ok = $false; Detail = "POST login.aspx = $($r2.Status)" } } + + # 認証が要る画面。未認証なら login.aspx へ 302 されるため、200 なら認証が通っている。 + $r3 = Invoke-Http "$base/Aspx/start/menu.aspx" -Session $ses + if ($r3.Status -ne 200) { return @{ Ok = $false; Detail = "GET menu.aspx = $($r3.Status)(認証が通っていない)" } } + + return @{ Ok = $true; Detail = "ログイン後 menu.aspx = 200" } +} + +$targets = @( + # --- バッチ (net48) --- + @{ + Name = "SimpleBatch_sample (net48)"; Bat = "5_Build_Bat_sample.bat" + Exe = "Samples\Bat_sample\SimpleBatch_sample\bin\Debug\SimpleBatch_sample.exe" + Args = $batchArgs; Expect = '\d+件のデータがあります' + } + @{ + Name = "RerunnableBatch_sample (net48)"; Bat = "5_Build_Bat_sample.bat" + Exe = "Samples\Bat_sample\RerunnableBatch_sample\bin\Debug\RerunnableBatch_sample.exe" + Args = $batchArgs; Pre = $clearOrders2; Verify = $verifyOrders2 + } + @{ + Name = "RerunnableBatch_sample2 (net48)"; Bat = "5_Build_Bat_sample.bat" + Exe = "Samples\Bat_sample\RerunnableBatch_sample2\bin\Debug\RerunnableBatch_sample2.exe" + Args = $batchArgs; Pre = $clearOrders2; Verify = $verifyOrders2 + } + @{ + Name = "RerunnableBatch_sample3 (net48)"; Bat = "5_Build_Bat_sample.bat" + Exe = "Samples\Bat_sample\RerunnableBatch_sample3\bin\Debug\RerunnableBatch_sample3.exe" + Args = $batchArgs; Pre = $clearOrders2; Verify = $verifyOrders2 + } + + # --- バッチ (net10.0) --- + @{ + Name = "SimpleBatch_sample (net10.0)"; Bat = "5_Build_BatCore_sample.bat" + Exe = "Samples4NetCore\Legacy\Bat_sample\SimpleBatch_sample\bin\Debug\net10.0\SimpleBatch_sample.dll" + Args = $batchArgs; Expect = '\d+件のデータがあります' + } + @{ + Name = "RerunnableBatch_sample (net10.0)"; Bat = "5_Build_BatCore_sample.bat" + Exe = "Samples4NetCore\Legacy\Bat_sample\RerunnableBatch_sample\bin\Debug\net10.0\RerunnableBatch_sample.dll" + Args = $batchArgs; Pre = $clearOrders2; Verify = $verifyOrders2 + } + @{ + Name = "RerunnableBatch_sample2 (net10.0)"; Bat = "5_Build_BatCore_sample.bat" + Exe = "Samples4NetCore\Legacy\Bat_sample\RerunnableBatch_sample2\bin\Debug\net10.0\RerunnableBatch_sample2.dll" + Args = $batchArgs; Pre = $clearOrders2; Verify = $verifyOrders2 + } + @{ + Name = "RerunnableBatch_sample3 (net10.0)"; Bat = "5_Build_BatCore_sample.bat" + Exe = "Samples4NetCore\Legacy\Bat_sample\RerunnableBatch_sample3\bin\Debug\net10.0\RerunnableBatch_sample3.dll" + Args = $batchArgs; Pre = $clearOrders2; Verify = $verifyOrders2 + } + + # --- CLI (net10.0) --- + # net48 版は System.CommandLine / Sharprompt の .NET Fx サポート終了により + # ドロップされている(5_Build_CLI_sample.bat 参照)。 + # interactive サブコマンドは Prompt を使うため対象外とし、非対話のものを使う。 + @{ + Name = "Simple_CLI (net10.0)"; Bat = "5_Build_CLICore_sample.bat" + Exe = "Samples4NetCore\Legacy\CLI_sample\Simple_CLI\Simple_CLI\bin\Debug\net10.0\Simple_CLI.dll" + Args = @("cmd1", "--an-int", "123"); Expect = 'Sub command cmd1: 123' + } + + # --- DaoGen_Tool(墨壺)の CUI モード --- + # #508 で追加された /HELP と /CUI。GUI 側の確認は手作業に残る。 + # DAODEFGEN → DAOSQLGEN の順に実行し、前段の出力を後段の入力に使う。 + @{ + Name = "DaoGen_Tool /HELP (net48)"; Bat = "4_Build_Framework_Tool.bat" + Exe = "Frameworks\Tools\DaoGen_Tool\bin\Debug\OpenTouryo.DaoGen_Tool.exe" + Args = @("/HELP"); Expect = 'DaoGen_Tool(D層自動生成ツール/墨壺)' + } + @{ + Name = "DaoGen_Tool DAODEFGEN (net48)"; Bat = "4_Build_Framework_Tool.bat" + Exe = "Frameworks\Tools\DaoGen_Tool\bin\Debug\OpenTouryo.DaoGen_Tool.exe" + Args = $daoDefArgs48; Expect = '生成が完了しました。' + Pre = $prepareDaoGen48; Verify = $verifyDaoDef48 + } + @{ + Name = "DaoGen_Tool DAOSQLGEN (net48)"; Bat = "4_Build_Framework_Tool.bat" + Exe = "Frameworks\Tools\DaoGen_Tool\bin\Debug\OpenTouryo.DaoGen_Tool.exe" + Args = $daoSqlArgs48; Expect = '生成が完了しました。' + Verify = $verifyDaoGen48 + } + @{ + Name = "DaoGen_Tool /HELP (net10.0)"; Bat = "4_Build_Framework_ToolCore.bat" + Exe = "Frameworks\Tools\DaoGen_Tool\bin\Debug\net10.0-windows7.0\OpenTouryo.DaoGen_Tool.exe" + Args = @("/HELP"); Expect = 'DaoGen_Tool(D層自動生成ツール/墨壺)' + } + @{ + Name = "DaoGen_Tool DAODEFGEN (net10.0)"; Bat = "4_Build_Framework_ToolCore.bat" + Exe = "Frameworks\Tools\DaoGen_Tool\bin\Debug\net10.0-windows7.0\OpenTouryo.DaoGen_Tool.exe" + Args = $daoDefArgsCore; Expect = '生成が完了しました。' + Pre = $prepareDaoGenCore; Verify = $verifyDaoDefCore + } + @{ + Name = "DaoGen_Tool DAOSQLGEN (net10.0)"; Bat = "4_Build_Framework_ToolCore.bat" + Exe = "Frameworks\Tools\DaoGen_Tool\bin\Debug\net10.0-windows7.0\OpenTouryo.DaoGen_Tool.exe" + Args = $daoSqlArgsCore; Expect = '生成が完了しました。' + Verify = $verifyDaoGenCore + } + + # --- DeployZipPackWithHTTP の CUI モード --- + # #528 で /MFTGEN を追加し、生成 → 配布 → 配置 まで CUI で通せるようになった。 + # マニュフェストを作り、IIS Express で配信し、実際に配置して突き合わせる。 + # ※ /NB を付けないと、配置した EXE が起動して止まる。 + @{ + Name = "DeployZip /MFTGEN (net48)"; Bat = "4_Build_Framework_Tool.bat" + Exe = "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\OpenTouryo.DeployZipPackWithHTTP.exe" + Args = $mftGenArgs48; Expect = 'マニュフェスト ファイルを生成しました。' + Pre = $prepareDeploy48; Verify = $verifyMftGen48 + } + @{ + Name = "DeployZip 配置 (net48)"; Bat = "4_Build_Framework_Tool.bat" + Exe = "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\OpenTouryo.DeployZipPackWithHTTP.exe" + Args = $deployArgs; Expect = '履歴に新規追加しました。' + Pre = $startDeployWeb48; Verify = $verifyDeploy48 + } + @{ + Name = "DeployZip /MFTGEN (net10.0)"; Bat = "4_Build_Framework_ToolCore.bat" + Exe = "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\net10.0-windows7.0\OpenTouryo.DeployZipPackWithHTTP.exe" + Args = $mftGenArgsCore; Expect = 'マニュフェスト ファイルを生成しました。' + Pre = $prepareDeployCore; Verify = $verifyMftGenCore + } + @{ + Name = "DeployZip 配置 (net10.0)"; Bat = "4_Build_Framework_ToolCore.bat" + Exe = "Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\net10.0-windows7.0\OpenTouryo.DeployZipPackWithHTTP.exe" + Args = $deployArgs; Expect = '履歴に新規追加しました。' + Pre = $startDeployWebCore; Verify = $verifyDeployCore + } + + # --- Web アプリ --- + @{ + Name = "MVC_Sample (net48)"; Bat = "10_Build_WebApp_sample.bat" + Kind = "Web"; WebHost = "IISExpress"; Port = 51081 + Site = "Samples\WebApp_sample\MVC_Sample\MVC_Sample" + Need = "aspnet_state" + Flow = $mvcLoginFlow + } + @{ + Name = "WebForms_Sample (net48)"; Bat = "10_Build_WebApp_sample.bat" + Kind = "Web"; WebHost = "IISExpress"; Port = 51082 + Site = "Samples\WebApp_sample\WebForms_Sample\WebForms_Sample" + Need = "aspnet_state" + Flow = $webFormsFlow + } + @{ + Name = "MVC_Sample (net10.0)"; Bat = "10_Build_WebAppCore_sample.bat" + Kind = "Web"; WebHost = "Kestrel"; Port = 51083 + Exe = "Samples4NetCore\Backend\MVC_Sample\MVC_Sample\bin\Debug\net10.0\MVC_Sample.dll" + Flow = $mvcLoginFlow + } +) + +# ------------------------------------------------------------------ +# ビルド +# ------------------------------------------------------------------ +function Invoke-BuildBat([string]$bat) +{ + $path = Join-Path $csRoot $bat + if (-not (Test-Path $path)) + { + Write-Host (" ビルド バッチが見つかりません : {0}" -f $bat) -ForegroundColor Red + return $false + } + + $log = Join-Path $OutputDir ("build_" + ($bat -replace '[^A-Za-z0-9]','_') + ".log") + + Push-Location $csRoot + # バッチ末尾(および途中)の pause に対応するため stdin を与える。 + cmd /c "echo. | call `"$path`"" *>&1 | Out-File $log -Encoding UTF8 + Pop-Location + + return $true +} + +# ------------------------------------------------------------------ +# Web ホストの起動・停止 +# ------------------------------------------------------------------ +# 起動しただけでは応答できないため、ポートが開くまで待ってから疎通する。 +function Wait-Port([int]$port, [int]$timeoutSec = 30) +{ + $sw = [Diagnostics.Stopwatch]::StartNew() + while ($sw.Elapsed.TotalSeconds -lt $timeoutSec) + { + $c = New-Object Net.Sockets.TcpClient + try + { + $c.Connect("127.0.0.1", $port) + if ($c.Connected) { $c.Close(); return $true } + } + catch { } + finally { $c.Dispose() } + Start-Sleep -Milliseconds 300 + } + return $false +} + +function Start-WebHost($t, [string]$log) +{ + if ($t.WebHost -eq "IISExpress") + { + $iis = Join-Path $env:ProgramFiles "IIS Express\iisexpress.exe" + if (-not (Test-Path $iis)) { return $null } + + $site = Join-Path $csRoot $t.Site + return Start-Process $iis ` + -ArgumentList "/path:`"$site`"", "/port:$($t.Port)", "/systray:false" ` + -PassThru -WindowStyle Hidden ` + -RedirectStandardOutput $log -RedirectStandardError "$log.err" + } + else + { + $dll = Join-Path $csRoot $t.Exe + if (-not (Test-Path $dll)) { return $null } + + # コンテンツ ルートを合わせるため、出力フォルダを作業ディレクトリにする。 + return Start-Process "dotnet" ` + -ArgumentList "`"$dll`"", "--urls", "http://localhost:$($t.Port)" ` + -PassThru -WindowStyle Hidden -WorkingDirectory (Split-Path $dll) ` + -RedirectStandardOutput $log -RedirectStandardError "$log.err" + } +} + +# ------------------------------------------------------------------ +# 実行 +# ------------------------------------------------------------------ +$selected = $targets | Where-Object { -not $Only -or $_.Name -like "*$Only*" } + +if (-not $SkipBuild) +{ + foreach ($bat in ($selected | ForEach-Object { $_.Bat } | Select-Object -Unique)) + { + Write-Host ("=== ビルド : {0} ===" -f $bat) -ForegroundColor Cyan + $sw = [Diagnostics.Stopwatch]::StartNew() + [void](Invoke-BuildBat $bat) + $sw.Stop() + Write-Host (" 完了 ({0:N1} 秒)" -f $sw.Elapsed.TotalSeconds) + } +} + +$results = @() + +foreach ($t in $selected) +{ + Write-Host "" + Write-Host ("=== {0} ===" -f $t.Name) -ForegroundColor Cyan + + $safe = ($t.Name -replace '[^A-Za-z0-9]', '_') + $out = Join-Path $OutputDir "$safe.txt" + + # ------------------------------------------------------------------ + # Web アプリ + # ------------------------------------------------------------------ + if ($t.Kind -eq "Web") + { + # 前提サービスの確認 + # ※ サービスの開始はシステムの状態を変えるため、ここでは行わない。 + # 足りない場合は対処方法を示して NG にする。 + if ($t.Need) + { + $svc = Get-Service $t.Need -EA SilentlyContinue + if (-not $svc -or $svc.Status -ne "Running") + { + $msg = "前提サービス {0} が動いていない → Start-Service {0}" -f $t.Need + Write-Host (" {0}" -f $msg) -ForegroundColor Yellow + $results += [pscustomobject]@{ 対象 = $t.Name; 結果 = "前提未達"; 内容 = $msg } + continue + } + } + + $sw = [Diagnostics.Stopwatch]::StartNew() + $proc = Start-WebHost $t $out + + if (-not $proc) + { + Write-Host " Web ホストを起動できません(実行ファイル/IIS Express が無い)" -ForegroundColor Red + $results += [pscustomobject]@{ 対象 = $t.Name; 結果 = "起動不可"; 内容 = "-" } + continue + } + + try + { + Write-Host (" 起動中 ... (PID {0}, port {1})" -f $proc.Id, $t.Port) + if (-not (Wait-Port $t.Port)) + { + Write-Host " ポートが開きません" -ForegroundColor Red + $results += [pscustomobject]@{ 対象 = $t.Name; 結果 = "NG"; 内容 = "ポートが開かない" } + continue + } + + $flow = & $t.Flow "http://localhost:$($t.Port)" + $sw.Stop() + + $verdict = if ($flow.Ok) { "OK" } else { "NG" } + Write-Host (" {0}" -f $flow.Detail) + Write-Host (" {0} ({1:N1} 秒)" -f $verdict, $sw.Elapsed.TotalSeconds) ` + -ForegroundColor $(if ($flow.Ok) { "Green" } else { "Red" }) + + $results += [pscustomobject]@{ 対象 = $t.Name; 結果 = $verdict; 内容 = $flow.Detail } + } + finally + { + # 子プロセスごと確実に落とす。 + Stop-Process -Id $proc.Id -Force -EA SilentlyContinue + } + continue + } + + # ------------------------------------------------------------------ + # プロセス(バッチ・CLI) + # ------------------------------------------------------------------ + $exe = Join-Path $csRoot $t.Exe + if (-not (Test-Path $exe)) + { + Write-Host " 実行ファイルが見つかりません" -ForegroundColor Red + $results += [pscustomobject]@{ 対象 = $t.Name; 結果 = "実行ファイル無し"; 内容 = "-" } + continue + } + + # 事前準備 + if ($t.Pre) + { + try { & $t.Pre } + catch + { + Write-Host (" 事前準備に失敗 : {0}" -f $_.Exception.Message) -ForegroundColor Red + $results += [pscustomobject]@{ 対象 = $t.Name; 結果 = "準備失敗"; 内容 = "-" } + continue + } + } + + # 実行 + # + # <Start-Process で、PowerShell を経由せずに入出力を扱う理由> + # + # 1. stdin を与えないと止まる + # サンプルは終了前に Console.ReadKey() を呼ぶ(SimpleBatch_sample/Program.cs 等)。 + # stdin がコンソールのままだと**本当にキー入力を待つ**。 + # 実測では SimpleBatch_sample (net48) が 386 秒かかった。 + # 空ファイルを与えると、待たずに InvalidOperationException になる + # (この例外は下の判定で除外する)。 + # + # 2. PowerShell のパイプを通すと、stderr が壊れる + # 「| Out-File」で受けると、native の stderr が ErrorRecord になり + # **コンソール幅で折り返される**。折り返しは語の途中にも入るため、 + # 「does not h ave a console」のように**単語が割れて復元できない**。 + # 幅は環境で違うので、後段の除外規則をいくら調整しても直らない。 + # + # Start-Process でファイルへ直接リダイレクトすれば、どちらも起きない。 + # 出力は生のまま残り、環境による差も出ない。 + $err = "$out.err" + Write-Host " 実行中 ..." + $sw = [Diagnostics.Stopwatch]::StartNew() + + if ($exe -like "*.dll") + { + # 「/DAP」のように「/」で始まる引数は dotnet 自身のオプションと紛らわしいため、 + # 「--」で区切って渡す(リポジトリのビルド バッチも同じ渡し方をしている)。 + # 一方 System.CommandLine を使う CLI では「--」以降が未解析トークン扱いになり、 + # サブコマンドが認識されなくなるため、区切らずに渡す。 + $needSep = @($t.Args | Where-Object { $_ -like "/*" }).Count -gt 0 + + $argList = @("`"$exe`"") + if ($needSep) { $argList += "--" } + $argList += @($t.Args) + + Start-Process "dotnet" -ArgumentList $argList -NoNewWindow -Wait ` + -WorkingDirectory (Split-Path $exe) ` + -RedirectStandardInput $emptyIn -RedirectStandardOutput $out -RedirectStandardError $err + } + else + { + $argList = @($t.Args) + + if ($argList.Count -eq 0) + { + # -ArgumentList に空の配列を渡すとエラーになる。 + Start-Process $exe -NoNewWindow -Wait ` + -WorkingDirectory (Split-Path $exe) ` + -RedirectStandardInput $emptyIn -RedirectStandardOutput $out -RedirectStandardError $err + } + else + { + Start-Process $exe -ArgumentList $argList -NoNewWindow -Wait ` + -WorkingDirectory (Split-Path $exe) ` + -RedirectStandardInput $emptyIn -RedirectStandardOutput $out -RedirectStandardError $err + } + } + + $sw.Stop() + + # 標準出力と標準エラーを両方見る。 + # + # **-Encoding UTF8 を必ず付ける。** + # Start-Process は子プロセスの生バイトをそのまま書くため、BOM が付かない。 + # Windows PowerShell 5.1 の Get-Content は BOM が無いと既定の ANSI(日本語環境では + # CP932)で読むため、UTF-8 の日本語が化けて期待値に一致しなくなる。 + # (従来の Out-File -Encoding UTF8 は BOM 付きだったので、たまたま成立していた) + $text = (Get-Content $out -Raw -Encoding UTF8 -EA SilentlyContinue) + "`n" ` + + (Get-Content $err -Raw -Encoding UTF8 -EA SilentlyContinue) + if ($null -eq $text) { $text = "" } + + # 判定 + # + # ※ 末尾の Console.ReadKey() 由来の例外はテスト内容と無関係なので除外する。 + # + # PowerShell は native コマンドの stderr を ErrorRecord にし、 + # **コンソール幅で折り返す**。折り返しで語が分断されると行単位の除外が効かない。 + # 実際 dotnet 起動の 4 件だけが、除外できずに NG になった。 + # 例外 : dotnet.exe : Unhandled exception. ... does not h + # ↑ ここで改行 + # このため、**空白を畳んで 1 行にしてから**除外・判定する。 + # コンソール幅に依存しなくなる。 + $flat = ($text -replace '\s+', ' ') + + # ReadKey 由来の例外を、宣言からスタック トレースまで丸ごと落とす。 + # + # <メッセージ本文で判定しない理由> + # 文言も見出しも環境で変わる。実測した 3 通り。 + # .NET (Core) 英語 : Unhandled exception. System.InvalidOperationException: Cannot read keys ... + # .NET Fx 英語 : Unhandled Exception: System.InvalidOperationException: Cannot read keys ... + # .NET Fx 日本語: Exception.ToString() が失敗したため、例外文字列を表示できません。 + # 見出しは「.」と「:」で違い、日本語環境では**型名すら出ない**。 + # このため本文ではなく、**言語に依存しないスタック トレース**で捕まえる。 + # + # <クラス名も実行環境で違う> + # .NET Fx : at System.Console.ReadKey(Boolean intercept) + # .NET (Core) : at System.ConsolePal.ReadKey(Boolean intercept) + # このため System.〇〇.ReadKey として受ける。 + $flat = $flat -replace ` + '(Unhandled Exception[.:]\s*)?System\.\w+(\.\w+)*Exception[^|]*?at System\.\w+\.ReadKey[^ ]*', '' + + $fatal = @() + $m0 = [regex]::Match($flat, '(Unhandled exception|ハンドルされない例外|System\.\w+Exception).{0,160}') + if ($m0.Success) + { + $fatal = @($m0.Value.Trim()) + } + + $ok = $true + $detail = "" + + if ($fatal) + { + $ok = $false + $detail = ($fatal | Select-Object -First 1).Trim() + Write-Host (" 例外 : {0}" -f $detail) -ForegroundColor Red + } + elseif ($t.Expect -and $text -notmatch $t.Expect) + { + $ok = $false + $detail = "期待する出力が無い : " + $t.Expect + Write-Host (" {0}" -f $detail) -ForegroundColor Red + } + + if ($ok -and $t.Expect) + { + $m = [regex]::Match($text, $t.Expect) + $detail = $m.Value + Write-Host (" 出力 : {0}" -f $m.Value) + } + + if ($ok -and $t.Verify) + { + if (-not (& $t.Verify)) + { + $ok = $false + $detail = "検証に失敗" + Write-Host " 検証に失敗" -ForegroundColor Red + } + } + + $verdict = if ($ok) { "OK" } else { "NG" } + Write-Host (" {0} ({1:N1} 秒)" -f $verdict, $sw.Elapsed.TotalSeconds) ` + -ForegroundColor $(if ($ok) { "Green" } else { "Red" }) + + $results += [pscustomobject]@{ 対象 = $t.Name; 結果 = $verdict; 内容 = $detail } +} + +# ------------------------------------------------------------------ +# サマリ +# ------------------------------------------------------------------ +Write-Host "" +Write-Host "================ サマリ ================" +$results | Format-Table -AutoSize -Wrap | Out-String | Write-Host +Write-Host (" ログ : {0}" -f $OutputDir) + +$ng = @($results | Where-Object { $_.結果 -ne "OK" }) +if ($ng.Count -eq 0) +{ + Write-Host " 全対象 OK" -ForegroundColor Green + exit 0 +} +else +{ + Write-Host (" {0} 件が NG" -f $ng.Count) -ForegroundColor Yellow + exit 1 +} diff --git a/root/programs/BUILDING.md b/root/programs/BUILDING.md new file mode 100644 index 000000000..3eb0abed6 --- /dev/null +++ b/root/programs/BUILDING.md @@ -0,0 +1,774 @@ +# BUILDING.md — 全ビルドの実行と判定 + +対象: `root/programs/CS`(C# 側) +配置: `root/programs` +本書は、リリース時に行っていた「build バッチで全ビルドが通ることを確認」を、 +**合否が出る形に機械化**するための手順と判定基準を記述する(#513 段階 2)。 + +> **ビルド構成そのもの**(bat の一覧、ビルド順、`z_Common.bat` と `z_Common2.bat` の関係、 +> バージョン番号の一元管理、NuGet パッケージ化)は +> [`CS/Frameworks/ANALYSIS.md`](CS/Frameworks/ANALYSIS.md) の **7 章「ビルド」** が一次情報。 +> 本書はその上で「どう実行し、どう合否を判定するか」だけを扱う。 + +--- + +## 1. 使い方 + +```powershell +cd root\programs + +# 全ビルド(0_ExecAllBat.bat 相当)を実行し、合否を一覧表示する +.\1_BuildAll.ps1 + +# 一部のステップだけ実行する(動作確認用) +.\1_BuildAll.ps1 -Only "WebApp_sample" -SkipClean + +# ログの出力先を変える +.\1_BuildAll.ps1 -OutputDir D:\logs + +# 環境に依存して必ず出るエラーを、判定から外す(4 節) +.\1_BuildAll.ps1 -IgnoreErrors "MSB3482" +``` + +終了コードは `0` = 全ステップ OK、`1` = NG あり。 + +| オプション | 内容 | +|---|---| +| `-Only <文字列>` | ステップ名/bat 名の部分一致で対象を絞る | +| `-SkipClean` | クリーン処理(`1_DeleteDir` / `1_DeleteFile`)を省略 | +| `-OutputDir <パス>` | ステップ別ログの保存先(既定 `%TEMP%\OpenTouryoBuildLogs`) | +| `-IgnoreErrors <正規表現…>` | 既知のエラーを合否判定から外す(複数指定可) | + +### `-SkipClean` の注意 + +**リリース判定では使わないこと。** 前回のビルド成果物が残っていると、 +実際にはビルドできない状態でも通ったように見える。 + +`1_DeleteDir.bat` は配下から `packages` `obj` `bin` `bld` `Temp` `PrecompiledWeb` +`MigrationBackup` `.vs` を再帰的に削除する。**Visual Studio は閉じてから実行する** +(`.vs` が削除されるため)。 + +--- + +## 2. なぜラッパーが必要か + +既存のビルド バッチをそのまま呼び出す構成にしてある。 +「何をビルドするか」の正はバッチ側に残り、`1_BuildAll.ps1` は実行と判定のみを担う。 + +ラッパーが必要な理由は次の 3 点。 + +1. **各バッチは MSBuild の終了コードを伝播しない**(`%ERRORLEVEL%` を見ていない) +2. **各バッチの末尾に `pause` がある**(対話入力を待つ) +3. **`-v:d`(詳細)で出力が膨大**(1 ステップで 6,000 行を超えることがある) + +このため、stdin を与えて実行し、出力から `error` / `warning` 行を抽出して判定している。 + +--- + +## 3. 判定基準 + +**エラー行が 1 件でもあれば NG**、無ければ OK。警告は件数を報告するだけで合否に影響しない。 + +エラー・警告の抽出は、次の形式の行を対象とする。 + +``` +xxx.csproj(12,5): error CS1002: ... ← コードあり +Microsoft.NuGet.targets(198,5): error : ... ← コードなし(NuGet の restore 失敗) +``` + +「ビルドに成功しました」等のサマリ文言は**ロケールで変わるため使わない**。 +`error` / `warning` とその後のコードは英語のまま出力されるため、そちらで判定する。 + +同一の指摘が複数プロジェクトから重複して出るため、一意化してから件数を数える。 + +### 既知のエラーの除外 + +`-IgnoreErrors` に指定した正規表現に一致するエラーは、**合否判定から外れる**。 +環境に依存して必ず出るものを、終了コードを汚さずに扱うための仕組み。 + +**除外したものは消えない。** 件数はサマリの `既知` 列に出し、内容も末尾に一覧する。 + +``` + OK エラー 0 / 警告 0 / 既知 1 (8.7 秒) + +======== 既知として除外したエラー ======== + 除外条件 : MSB3482 + [WSClnt_sample (net48)] ... error MSB3482: 署名中にエラーが発生しました: ... +``` + +握り潰しを防ぐための表示なので、**除外件数が想定より多いときは条件が広すぎることを疑う。** + +### 警告について + +**警告 0 にはならない。** 現状の内訳は次のとおりで、いずれもコンパイル警告ではない。 + +| ステップ | 警告数 | 内容 | +|---|---|---| +| NuGet (netcore100) | 52 | `NU1903` 等、パッケージの脆弱性アドバイザリ | +| Business (netcore100) | 38 | 同上 | + +これらは依存パッケージ側の問題であり、ビルドの合否とは切り離している。 +**件数が大きく増減した場合は依存関係の変化を疑う**、という使い方をする。 + +--- + +## 4. 既知の環境依存 + +### WSClientWinCone_sample の署名エラー + +``` +error MSB3482: 署名中にエラーが発生しました: bin\Debug\app.publish\WSClientWinCone_sample.exe +の署名に失敗しました。SignTool Error: No certificates were found that met all the given criteria. +``` + +`WSClientWinCone_sample.csproj` は ClickOnce のマニフェスト署名が有効になっている。 + +```xml +<SignManifests>true</SignManifests> +<ManifestCertificateThumbprint>A69CDE3C92D8862D42E7A239134686E32089B679</ManifestCertificateThumbprint> +<ManifestKeyFile>WSClientWinCone_sample_TemporaryKey.pfx</ManifestKeyFile> +``` + +`.pfx` はリポジトリに同梱されているが、**MSBuild は拇印で証明書ストアを検索する**ため、 +当該証明書が入っていない環境ではビルドできない。 +`_TemporaryKey.pfx` の名のとおり Visual Studio が自動生成した開発用の一時証明書であり、 +同じ `WSClient_sample` 配下の `WSClientWin_sample` / `WSClientWPF_sample` に署名設定は無い。 + +**環境依存であり、コード側の不具合ではない。** ビルドを通すには、 +`.pfx` を証明書ストアにインポートするか、`SignManifests` を `false` にする +(`Install` は `false` のため配布用途でもない)。 + +**CI では証明書を用意できない。** 拇印での検索であるうえ、同梱の `.pfx` は +パスワードで保護されており、実行のたびに作り直される環境には入れられない。 + +**しかも、出るエラーのコードがローカルと CI で違う。** + +| 環境 | コード | 失敗する箇所 | +|---|---|---| +| ローカル | `MSB3482` | マニフェストの署名。`.pfx` が既にキー コンテナへ取り込まれているため、最後まで進む | +| CI | `MSB3325` + `MSB3321` | `ResolveKeySource` によるキー ファイルの取り込み。署名に到達しない | + +``` +error MSB3325: Cannot import the following key file: WSClientWinCone_sample_TemporaryKey.pfx. + The key file may be password protected. ... +error MSB3321: Importing key file "WSClientWinCone_sample_TemporaryKey.pfx" was canceled. +``` + +このため CI では 3 つのコードをまとめて、**当該プロジェクトに限定して**除外している(9 節)。 + +```powershell +-IgnoreErrors 'error MSB(3482|3325|3321):.*WSClientWinCone_sample\.csproj' +``` + +プロジェクト名まで含めているのは、同じコードが他のプロジェクトで出たときに +見逃さないため。コードだけで除外すると範囲が広すぎる。 + +--- + +## 5. 修正の経緯 : nuget.exe の MSBuild 誤検出 + +2026/08/01 時点で、net48 側の 7 ステップ・エラー 14 件が次の 2 種類で失敗していた。 + +``` +error MSB4226: インポートされたプロジェクト "...WebApplications\Microsoft.WebApplication.targets" + が見つかりませんでした。 +error : Your project file doesn't list 'win' as a "RuntimeIdentifier". +``` + +原因は、**`nuget.exe` が MSBuild を自動検出し、同居する SQL Server Management Studio の +MSBuild を選んでいた**こと。ログに次が出ていた。 + +``` +MSBuild 自動検出: 'C:\Program Files\Microsoft SQL Server Management Studio 22\Release\MSBuild\Current\bin' + から MSBuild バージョン '18.8.2.30814' を使用します。 +``` + +その MSBuild には Web アプリ用の `Microsoft.WebApplication.targets` が無く、 +また生成される `project.assets.json` が実際のビルド(Visual Studio の MSBuild)と噛み合わない。 + +`z_Common.bat` は `vswhere` で MSBuild を正しく解決していたが、 +**その値が `nuget.exe` に渡っていなかった**。このため次を追加した。 + +```bat +for %%i in (%BUILDFILEPATH%) do set MSBUILDDIR=%%~dpi +if defined MSBUILDDIR set MSBUILDDIR=%MSBUILDDIR:~0,-1% +set NUGET_MSBUILD=-MSBuildPath "%MSBUILDDIR%" +``` + +末尾の `\` を除去しているのは、`-MSBuildPath "...\"` だと `\"` がエスケープと解釈され、 +引数が壊れるため。この `%NUGET_MSBUILD%` を、`nuget.exe restore` を呼ぶ +**11 バッチ・20 箇所**に付与した。 + +結果、**7 ステップ NG → 1 ステップ NG**(残りは上記の署名エラーのみ)となった。 + +> MSBuild を同梱する製品(SSMS、Build Tools、旧 VS 等)が同居する環境では +> 同種の問題が起こり得る。`nuget.exe` 側にも MSBuild を明示する、という対処が要る。 + +--- + +## 6. 実行結果の例 + +``` +ステップ 結果 エラー 既知 警告 秒 +-------- ---- ------ ---- ---- -- +Clean (net48 基盤) OK 0 0 0 8.30 +NuGet (net48) OK 0 0 0 12.80 +Business (net48) OK 0 0 0 7.90 +... +NuGet (netcore100) OK 0 0 52 22.80 +Business (netcore100) OK 0 0 38 6.30 +... +WSClnt_sample (net48) NG 1 0 0 21.20 +... + + 所要時間 : 5.3 分 + 1 ステップが NG +``` + +`既知` 列は `-IgnoreErrors` で除外した件数。指定しなければ常に `0`。 + +全 31 ステップ(クリーン 8 + 実ビルド 23)で **約 5 分**。 + +--- + +## 7. 単体テストとの関係 + +ビルドが通ったら、単体テストの実行と判定を行う。 +手順は [`TESTING.md`](TESTING.md) を参照。 + +```powershell +.\2_RunAllTests.ps1 +``` + +**必ず `1_BuildAll.ps1` → `2_RunAllTests.ps1` の順で行う。** +`1_BuildAll.ps1` はクリーンを行い、`4_Build_CopyAssemblies.bat` が +テストの参照先(`Build_net48` / `Build_netcore100`)を更新するため、 +逆順ではテストが古いアセンブリを見ることになる。 + +なお `0_ExecAllBat.bat` は `y_Build_TestCode*.bat`(単体テスト)を含まない。 +テスト側のビルドは `2_RunAllTests.ps1` がバッチ経由で行うため、二重に実行する必要はない。 + +## 8. サンプルの疎通確認 + +単体テストが通ったら、サンプル アプリの疎通を確認する。 +手順は [`SMOKETEST.md`](SMOKETEST.md) を参照。 + +```powershell +.\3_SmokeTest.ps1 +``` + +**`1_BuildAll.ps1` はクリーンの繰り返しにより、完走後に net48 サンプルのバイナリを残さない。** +`1_DeleteDir.bat` が配下の `bin` / `obj` を再帰的に削除するため、最後にビルドされた +Core サンプルだけが残る。このため `3_SmokeTest.ps1` は対象を自分でビルドする。 + +### リリース時の実行順 + +```powershell +cd root\programs +.\1_BuildAll.ps1 # 全ビルドの合否 +.\2_RunAllTests.ps1 # 単体テストの回帰 +.\3_SmokeTest.ps1 # サンプルの疎通 +``` + +--- + +## 9. GitHub Actions で回す(#517) + +依存パッケージの更新(Dependabot)を `develop` に入れる前にビルドで確かめるため、 +**受けブランチ `deps` を挟む**。 + +``` +Dependabot が PR を作成(base: develop) + │ + │ ① .github/workflows/dependabot-retarget.yml が base を deps へ書き換え + ▼ + PR(base: deps) + │ + │ ⓪ 人が deps を develop の先端に合わせる ← マージの前に必ず行う + │ ② 人がマージ + ▼ + deps ─── ③ .github/workflows/build-windows.yml が windows-latest で検証 + │ ④ 結果が OK なら、人が PR を作って develop へマージ + ▼ + develop +``` + +①③がワークフロー、⓪②④が人の作業。`AGENTS.md` の線引き(マージは人が行う)に従う。 + +### ⓪ を飛ばしてはいけない + +**`deps` が古いまま②を行うと、③が「`develop` に入る予定の状態」を検証しなくなる。** +`deps` と `develop` の差(他の作業で進んだ分)が混ざるためで、④の PR もその差を巻き込む。 + +```powershell +git fetch origin +git push origin origin/develop:deps # 早送り。できないときは弾かれるので事故にならない +``` + +**早送りできるのは、`deps` に独自コミットが無い間だけ。** +②の後の `deps` は独自コミットを持つため、この形は使えない。 +④で `develop` へ戻すと再び祖先になり、また早送りできる。**この周期を保つ。** + +> ④の直後に⓪を済ませておくと、次の PR が来たときには既に揃っている。 +> ただし、その後に `develop` が別の作業で進むこともあるため、 +> **判断の基準は「④の後」ではなく「②の前」。** + +> ⓪の push 自体が③を起こす(約 12 分)。`develop` の現状を検証する意味はある。 +> 公開リポジトリなので、GitHub ホステッド runner の費用はかからない。 + +### 複数の PR を `deps` に溜める + +**溜めてよい。** `deps` は使い捨てではなく常設のブランチで、②を何回か繰り返してから +④でまとめて `develop` へ戻せる。**それが受けブランチを置いた本来の使い方。** + +``` +PR ─┐ +PR ─┼→ deps(②を繰り返す。マージのたびに③)→ ④ 1 本の PR → develop +PR ─┘ +``` + +**切り分けは失われない。** ③のトリガは `push: branches: [deps]` なので、 +5 本マージすれば③が 5 回走る。どのコミットで赤くなったかが残る。 + +| やり方 | 向き | +|---|---| +| 1 本ずつ③の緑を確認して次へ | 確実。1 本あたり約 12 分 | +| まとめてマージし、最後の③だけ見る | 速い。赤いときに戻す手間がかかる | + +溜めるときの注意が 4 つある。 + +**① `develop` が進んだら取り込む。** 溜めている間に `develop` が動くと④で競合する。 +⓪の基準が「②の前」なのは、この繰り返しでも同じ(**②のたびに⓪を見る**)。 + +**② 出力が変わる更新は `Result*.txt` を同じコミットに入れる。** +`deps` の上で `2_RunAllTests.ps1` を回して再生成する。 +**ソースだけ先にコミットすると③が必ず赤くなる**(③は期待値を `HEAD` から取るため)。 +実際に `System.Security.Cryptography.Xml` は `EncAndDecUtilCUI` の期待値に影響し得る。 + +**③ 同時実行を制御していない。** `build-windows.yml` に `concurrency` の指定が無いため、 +連続してマージすると**古いコミットの run も最後まで走る**(12 分 × 本数)。 +「まとめて最後だけ見る」を常用するなら次を足すと無駄が消える。 + +```yaml +concurrency: + group: build-${{ github.ref }} + cancel-in-progress: true +``` + +**ただし「1 本ずつ確認する」ときは邪魔になる**(確認したい run が消える)。 +運用を決めてから入れること。現状は入れていない。 + +**④ Dependabot が上書き PR を出すことがある。** 溜めている間に次の版が出ると、 +Dependabot は**古い PR を閉じて新しい PR を開く**。既にマージ済みの分は `deps` に残るため、 +**同じパッケージの版が 2 回進む**コミットが並ぶ。害は無いが履歴は読みにくくなる。 + +### 任意のブランチで手動実行する + +`build-windows.yml` は `workflow_dispatch` を持つので、**`deps` 以外のブランチでも同じ検証を回せる。** + +``` +Actions → Build on Windows → Run workflow → Branch: <任意のブランチ> +``` + +実行されるのは**選んだブランチ側の定義**。`deps` への push と同じ内容 +(ビルド → 単体テスト → 疎通)が走る。 + +成立の条件は 2 つ。 + +| 条件 | 内容 | +|---|---| +| `develop`(既定ブランチ)に `workflow_dispatch` があること | 「Run workflow」ボタンの表示条件 | +| **選ぶブランチにも `.github/workflows/build-windows.yml` があること** | 定義はそのブランチから読まれるため | + +2 つ目が実務上の注意になる。**`develop` より前に分岐した古いブランチにはファイルが無い**ので、 +選んでも動かない。先に `develop` を取り込むこと。 + +> **手動実行でもクロス DB にはならない。** 対象は `SQLONLY`(SQL Server のみ)のまま。 +> 各 DBMS は Linux コンテナで、`windows-latest` では動かせない。 +> クロス DB は手元で行う([`TESTING.md`](TESTING.md))。 + +### ワークフローの前提 + +- **`deps` ブランチをあらかじめ作っておく。** `gh pr edit --base` は既存のブランチしか指せない +- **`dependabot-retarget.yml` は `develop`(既定ブランチ)に無いと動かない。** + `pull_request_target` はベース ブランチ側の定義で動くため + +### なぜ `dependabot.yml` の `target-branch` ではないのか + +**セキュリティ アップデートには効かないため。** `target-branch` が効くのはバージョン更新だけで、 +セキュリティ アップデートは常に既定ブランチ(`develop`)へ出る。 +振り替えるには Actions で `gh pr edit --base` するしかない。 + +### なぜ `pull_request_target` なのか + +Dependabot が起こしたイベントでは `GITHUB_TOKEN` が既定で read-only になり、base を書き換えられない。 +`pull_request_target` なら read-write にできる。 + +> **PR のコードを checkout してはいけない。** +> `pull_request_target` はベース ブランチ側の定義を**書き込み権限付きで**動かすため、 +> PR の中身を実行すると、そこに任意のコードを書ける相手へ権限を渡すことになる。 +> `dependabot-retarget.yml` は checkout せず、`gh` コマンドだけを実行し、 +> 権限も `pull-requests: write` の 1 つに絞っている。 + +### CI に載せている範囲 + +| スクリプト | CI | 備考 | +|---|---|---| +| `1_BuildAll.ps1` | **○** | DB を必要としない | +| `2_RunAllTests.ps1` | **○** | SQL Server を runner に導入して対応 | +| `3_SmokeTest.ps1` | **○** | `aspnet_state` を開始すれば動く | + +**リリース時の検証 3 本が、そのまま同じ順で回っている。** + +**対象外は明示しておく。** + +- **GUI アプリケーション**(WinForms / WPF / 各ツールの画面)… `RELEASE.md` 4 節の手作業 +- **SQL Server 以外の DBMS への接続** … 自動テストは `/Dap SQL` しか使わない + (`TestSQLUtility` は 4 DBMS 分の SQL 生成を検証するが、**接続はしない**ので対象内) + +### SQL Server をどう用意するか + +**`LocalServicesOnDocker` の `docker-compose.yml` はそのままでは使えない。** + +```yaml +sqlserver: + image: mcr.microsoft.com/mssql/server:2022-latest # ← Linux イメージ +``` + +`windows-latest` は Linux コンテナを動かせない。Docker は入っているが Windows コンテナ専用で、 +Linux コンテナには Hyper-V による VM が要り、runner 自体が既に入れ子の VM のため +多段のネストができない。 + +**そこで、runner へ直接 SQL Server を入れ、同リポジトリの `instnwnd.sql` だけを使う。** + +| 要素 | 入手先 | +|---|---| +| SQL Server 2022 | `ankane/setup-sqlserver`(**コミットで固定**。`v1` はタグではなくブランチ) | +| `instnwnd.sql`(Microsoft 公式の Northwind DDL、約 1 MB) | `LocalServicesOnDocker`(**コミットで固定**) | +| `CREATE ORDERS2.sql` | 本リポジトリに同梱 | + +初期化で押さえている点は 3 つ。 + +1. **`sa` のパスワードを構成ファイルに合わせる。** + 構成側を CI 用に書き換えると「実際に使われる設定」と乖離するため、DB 側を + `seigi@123`(`app.config` / `appsettings.json` の値)に変更する +2. **照合順序を `Japanese_CI_AS` にする。** + `docker-compose.yml` の `MSSQL_COLLATION` と同じ。`CREATE DATABASE ... COLLATE` で + DB 既定として与える。Northwind の列は `COLLATE` 句を持たないため、各列がこれを継承する +3. **ロードの完了を `Shippers` が 3 行あることで確認し、不完全なら作り直す。** + 起動直後は一部のバッチが失敗して表だけできることがある。 + 判定方法は `LocalServicesOnDocker` の `start-up.sh` に合わせている + +> **`instnwnd.sql` は DB を作らない。** 対象 DB の中で実行するスクリプトなので、 +> 先に `CREATE DATABASE Northwind` が要る。 + +### テストが前提とする環境(DB 以外に 2 つある) + +初回の実行で 6 件すべてが NG になり、次の 2 つが不足していると分かった。 + +#### ① `C:\root` が要る + +**構成ファイルが絶対パスを直書きしている。** + +| ファイル | キー | 値 | +|---|---|---| +| `TestCode/App.config` | `FxXMLMSGDefinition` | `C:\root\files\resource\Xml\MSGDefinition.xml` | +| `TestCode/App.config` | `FxXMLSPDefinition` | `C:\root\files\resource\Xml\SPDefinition.xml` | +| `TestBatch/SimpleBatch/app.config` | `SqlTextFilePath` | `C:\root\files\resource\Sql` | + +無いと、`GetMessage` は**例外を出さずに空を返し**、SimpleBatch は次で落ちる。 + +``` +resource file [C:\...\ShipperCount.sql] was not found. + at Touryo.Infrastructure.Public.IO.ResourceLoader.LoadAsString(...) +``` + +実体はリポジトリ内(`root/files`、984 ファイル / 4.5 MB)にあるので、 +**コピーせずジャンクションで繋ぐ**(実体を 1 つに保つ)。 + +```powershell +New-Item -ItemType Junction -Path 'C:\root' -Target "$env:GITHUB_WORKSPACE\root" +``` + +#### ② 日本語環境が要る(「書式」と「言語」は別物) + +**期待値は日本語環境で生成されている。** runner の既定は `en-US` で、**2 つの軸がずれる。** + +| 軸 | 何が変わるか | 直し方 | +|---|---|---| +| `CurrentCulture` | 日付・数値の**書式** | `Set-Culture ja-JP` | +| `CurrentUICulture` | メッセージの**言語** | 言語パックの導入 | + +**`Set-Culture` は前者しか変えない。** 順に潰す必要がある。 + +##### 書式(`CurrentCulture`) + +``` +期待 : 昭和52年4月24日(日), ggy年M月d日(ddd): <DATE> 0:00:00 +実測 : 昭和52年4月24日(日), ggy年M月d日(ddd): 4/24/1977 12:00:00 AM +``` + +`CompareResult.ps1` の `<DATE>` は `\d{4}/\d{1,2}/\d{1,2}`、つまり +**`1977/4/24` の形にしか一致しない。** `4/24/1977` は素通りする。 + +##### 言語(`CurrentUICulture`) + +**2 種類あるが、根は同じ。** + +**1. `GetMessage` はカルチャでファイルを選び分ける。** + +``` +実測 : GetMessage: - Description corresponding to the message-ID:I0001(normal system) - +期待 : GetMessage: ~メッセージID:I0001に対応する記述(正常系)~ +``` + +`root/files/resource/Xml/` には 3 つある。 + +``` +MSGDefinition.xml ← 英語(既定・フォールバック) +MSGDefinition_ja.xml ← 日本語 +MSGDefinition_zh-CN.xml +``` + +`GetMessage.cs` が `CurrentUICulture` から `_ja` 付きの名前を組み立てる。 +`en-US` では該当が無く、既定の英語版に落ちる。**例外にならないので気付きにくい。** + +> 設定で固定することもできる。`GetMessage.cs` は `FxBusinessMessageCulture`(`appSettings`)が +> あればそれを優先する。ただし構成ファイルを CI の都合で変えると、 +> **`CurrentUICulture` を見る経路自体がテストされなくなる。** + +**2. 暗号系の例外文字列は Windows が返す。** + +``` +実測 : ... System.Security.Cryptography.<B64URL>, Key does not exist. +期待 : ... System.Security.Cryptography.<B64URL>, キーがありません。 +``` + +##### 対処 + +**書式は runner 側で直せる。言語は直せない。** + +```powershell +Set-Culture ja-JP # これは効く(現在のセッションには反映されないので子プロセスで確認する) +``` + +**`CurrentUICulture` を日本語にする手段は、実質存在しない。** 試して駄目だったものを挙げる。 + +| 試したこと | 結果 | +|---|---| +| `Install-Language -Language ja-JP` | **ハング。** Windows Update 経由で取得しようとして応答が返らず、ステップが 16 分以上停止(run 30976630947) | +| `Set-WinUILanguageOverride` | 言語パックの導入が前提のため使えない | +| `HKCU\Control Panel\Desktop\PreferredUILanguages` を直接書く | **無視された。** Windows は未インストールの言語を候補から外す | + +ワークフローの出力で確定している。 + +``` +新しいプロセスの Culture / UICulture : ja-JP / en-US +``` + +そこで、言語に依存する 2 か所を**別々に処理する。** + +**1. `GetMessage` は設定で固定する。** + +`TestCode` の `App.config` と `appsettings.json` に次を足した。 + +```xml +<add key="FxBusinessMessageCulture" value="ja-JP" /> +``` + +`GetMessage.cs` は、この指定があれば `CurrentUICulture` より優先する。 +`ja-JP` → `ja` のフォールバック(`GetMessage.cs` の `currentUICulture.Parent`)で +`MSGDefinition_ja.xml` に解決されるため、**ローカルで起きている経路と同じ**になる。 + +> **これは CI のための小細工ではなく、テストの決定性の問題。** +> 固定しないと「どのマシンで動かすか」で結果が変わる。 + +**2. OS のメッセージは正規化する。** + +`CompareResult.ps1` に規則を足し、**文言だけ**を `<OSMSG>` に潰す。 + +```powershell +@{ Name = 'OSメッセージ' + Pattern = 'キーがありません。|Key does not exist\.|プロバイダーの公開キーは無効です。|Provider''s public key is invalid\.' + Replace = '<OSMSG>' } +``` + +**行ごと落とさないのが要点。** 例外が起きたこと自体は「行の存在」で分かるため、 +行を残しておけば、**例外が起きなくなったときに差分として検知できる。** + +##### 潰した順序 + +段階的に切り分けた。**一度に直そうとすると、どれが効いたのか分からなくなる。** + +| 実行 | 差分 | 何が分かったか | +|---|---|---| +| 1 回目 | 18 / 18 / 19 / 20 / 2 / 4 | `C:\root` の欠落と、ロケールの両方が出ていた | +| 2 回目(`C:\root` + `Set-Culture`) | 4 / 4 / **0** / **0** / 2 / 4 | SimpleBatch は解決。日付も解決。言語だけが残った | +| 3 回目(`PreferredUILanguages`) | 4 / 4 / 0 / 0 / 2 / 4 | **変化なし** → UI 言語は runner 側では直せないと確定 | +| 4 回目(設定 + 正規化) | **すべて 0** | 完了 | + +### `2_RunAllTests.ps1` を CI で回すときの注意 + +**これは回帰テストで、期待値は `HEAD` にコミットされた `Result*.txt`。** +その期待値は開発環境で生成されたものなので、**照合順序・ロケール・タイム ゾーンが +1 つでもずれると差分が出る。** + +サーバー レベルの照合順序までは合わせていない(変更にはインスタンスの再構築が要る)。 +DB レベルだけを合わせているため、`tempdb` を経由する比較などでは差が出る余地が残る。 + +差分が出たときのために、ワークフローは**期待値と実測値の両方を artifact に採取する**。 + +| artifact | 中身 | +|---|---| +| `build-logs` | `1_BuildAll.ps1` のステップ別ログ | +| `test-results` | 期待値(`HEAD` 版)・ビルド ログ・再生成された `Result*.txt` | +| `smoke-logs` | 各対象の標準出力(Web 系は IIS Express の起動ログも含む) | + +### `3_SmokeTest.ps1` の前提 + +**DB は追加不要。** `3_SmokeTest.ps1` も `/DAP SQL` しか使わないため、 +`2_RunAllTests.ps1` のために用意した SQL Server で足りる。 +`Orders2` は `Set up Northwind` で作成済み(無くても `3_SmokeTest.ps1` が作る)。 + +足りないのは 1 つだけだった。 + +```powershell +Start-Service aspnet_state +``` + +**`3_SmokeTest.ps1` は、これを自分では行わない。** サービスの開始はシステムの状態を +変える操作であり、足りない場合は対処方法を示して NG にする設計(`AGENTS.md` の線引き)。 +**runner は使い捨てでこの判断が当てはまらない**ため、ワークフロー側で開始する。 + +IIS Express は同梱されている。 + +``` +[有] C:\Program Files\IIS Express\iisexpress.exe (v10.0.26013.1000) +[有] C:\Program Files (x86)\IIS Express\iisexpress.exe (v10.0.26013.1000) + +[有] aspnet_state : Status=Stopped StartType=Manual + 開始しました : Status=Running +``` + +`3_SmokeTest.ps1` が見るのも `%ProgramFiles%` 側なので、そのまま使える。 + +> **調べ方。** 一時的に `workflow_dispatch` だけのワークフローを置いて実行した。 +> 12 分のビルドを回さずに 10 秒で答えが出る。 +> 同種の疑問が出たら、また作って捨てればよい。 + +### イメージ側の充足状況 + +| 必要なもの | イメージ | +|---|---| +| MSBuild | **Visual Studio 18 Enterprise** | +| .NET Framework 4.8 の参照アセンブリ | あり | +| .NET 10 SDK | あり | +| **IIS Express** | **あり**(`%ProgramFiles%` / `%ProgramFiles(x86)%` の両方) | +| **`aspnet_state`** | **あり**(`StartType=Manual`。開始できることを確認済み) | +| `nuget.exe` | リポジトリに同梱(`root/programs/nuget.exe`) | +| SQL Server | **無し**(LocalDB と `sqlcmd` のみ) | + +`windows-latest` の実体は次のとおり(実行ログで確認)。 + +``` +Image : win25-vs2026 +OS : Microsoft Windows Server 2025 Datacenter (10.0.26100) +Version : win25-vs2026/20260728.188 +``` + +`z_Common.bat` は `vswhere` で MSBuild を解決するため、**エディションが Enterprise でも通る。** +固定パスの並びは Community しか見ていないので、そちらだけでは解決できない。 + +``` +BUILDFILEPATH15 +BUILDFILEPATH16 +BUILDFILEPATH17 +BUILDFILEPATH18 +BUILDFILEPATH "C:\Program Files\Microsoft Visual Studio\18\Enterprise\MSBuild\Current\Bin\MSBuild.exe" +``` + +> **どの README を見ているかを確かめること。** 本書は当初「VS 2022 Enterprise 17.14」と +> 書いていたが、これは `Windows2025-Readme.md`(VS 2022 のイメージ)を見ていたため。 +> `windows-latest` の実体は `windows-2025-vs2026` で、正は `Windows2025-VS2026-Readme.md`。 +> **バージョンや実在に依存する判断は、実行ログで裏を取ってから行う。** + +### `VisualStudioVersion` を固定値から変更した + +`z_Common.bat` が固定値を持っていたのを、`vswhere` から求めるようにした。 + +```bat +@rem 変更前 +set VisualStudioVersion=18.0 +``` + +Web アプリの csproj は、この値で targets のパスを組み立てる。 + +```xml +<VSToolsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> +<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" /> +``` + +固定値 `18.0` は **VS 18 のある環境でしか成立しない。** 例えば VS 2022(17.x)だけの環境に +渡すと `v18.0\WebApplications\` を探し、**5 節と同じ `MSB4226`** になる。 +このため、MSBuild を解決したのと同じ `vswhere` からバージョンを求めるようにした。 + +```bat +for /f "usebackq tokens=1 delims=." %%i in ( + `%VSWHERE% -latest -products * -requires Microsoft.Component.MSBuild -property installationVersion` +) do set VSVER_MAJOR=%%i +if not defined VSVER_MAJOR set VSVER_MAJOR=18 +set VisualStudioVersion=%VSVER_MAJOR%.0 +``` + +VS 18 のある環境では従来どおり `18.0` になるため、**挙動は変わらない。** + +> **結果としては、この変更が無くても CI は通っていた。** runner にも VS 18 が入っており、 +> 固定値 `18.0` と一致していたため(`VisualStudioVersion 18.0` がログに出ている)。 +> ただし一致は偶然で、イメージの更新で崩れる。導出に変えたこと自体は妥当と判断した。 + +### 実測(run 30984111639 : 全ステップ成功) + +> **当時の件数での記録。** その後、単体テストは 8 ケース(#520)、 +> 疎通は 22 件(#528)に増えている。**時間の目安として読むこと。** + +| ステップ | CI | ローカル | +|---|---|---| +| Build all(31 ステップ) | 4 分 56 秒 | 5.8 分 | +| **Install SQL Server** | **5 分 22 秒** | -(導入済み) | +| Set up Northwind | 14 秒 | -(導入済み) | +| Set up C:\root and locale | 11 秒 | -(導入済み) | +| Run all tests(6 件) | 1 分 29 秒 | 1.3 分 | +| Start aspnet_state | 1 秒 | -(手動) | +| Smoke test(18 件) | 2 分 25 秒 | 2.4 分 | +| **合計** | **約 15 分** | 約 9.5 分 | + +**検証そのものの所要はローカルとほぼ同じ。差は環境の用意(約 5 分半)。** +短縮したい場合は `Install SQL Server` が対象になる。 + +疎通 18 件はすべて OK だった。Web 系 3 件(IIS Express の起動、`aspnet_state` を使う +セッション、`__VIEWSTATE` を伴うポストバック、認証後のリダイレクト)も +**追加の調整なしで通っている。** + +``` +MVC_Sample (net48) OK ログイン後 /Crud1/Index = 200 +WebForms_Sample (net48) OK ログイン後 menu.aspx = 200 +MVC_Sample (net10.0) OK ログイン後 /Crud1/Index = 200 +``` + +`CLI_sample (net48)` と `Framework_WSCore` はログが 27 行しかないが、**失敗ではない。** +どちらもバッチ側で意図的に無効化されており、メッセージだけを出して終わる。 + +``` +.NET Fx系のSystem.CommandLine と Sharprompt 問題で一時的?ドロップ +Core系のBinarySerializeの完全廃止対応 +``` + +### アクションのバージョン + +`actions/checkout` と `actions/upload-artifact` は **`@v7`** を使う。 +`@v4` は Node.js 20 を対象としており、次の警告が出る。 + +``` +Node.js 20 is deprecated. The following actions target Node.js 20 but are being +forced to run on Node.js 24: actions/checkout@v4, actions/upload-artifact@v4 +``` diff --git a/root/programs/CHEATSHEET.md b/root/programs/CHEATSHEET.md new file mode 100644 index 000000000..1d7f0d367 --- /dev/null +++ b/root/programs/CHEATSHEET.md @@ -0,0 +1,192 @@ +# チートシート + +**手順だけを並べたもの。** 理由・詳細・落とし穴の背景は、各項のリンク先が一次情報。 + +> ここは**意図的に二重管理**している。手順は「思い出すため」に転記し、 +> **判断が要ることは書かない。** 迷ったらリンク先を読むこと。 + +--- + +## 1. 検証(変更したら必ず) + +```powershell +cd root\programs +.\0_RunAll.ps1 # 1 → 2 → 3 を順に実行する +``` + +個別に回すとき。**順序は固定**(1 のクリーンとアセンブリ配置が 2・3 の前提)。 + +```powershell +.\1_BuildAll.ps1 -IgnoreErrors 'error MSB(3482|3325|3321):.*WSClientWinCone_sample\.csproj' +.\2_RunAllTests.ps1 +.\3_SmokeTest.ps1 +``` + +| | 合格の目安 | 詳細 | +|---|---|---| +| ビルド | 全ステップ OK | [`BUILDING.md`](BUILDING.md) | +| 単体テスト | 8/8 OK、差分 0 | [`TESTING.md`](TESTING.md) | +| 疎通 | 22/22 OK | [`SMOKETEST.md`](SMOKETEST.md) | + +- **`-IgnoreErrors` を付けないと `MSB3482` で NG になる。** ClickOnce の署名で、 + 証明書が無い環境では必ず出る([`BUILDING.md`](BUILDING.md) 4 節)。 + **`0_RunAll.ps1` はこれを渡さない**ので、`1_BuildAll.ps1` が `1` を返すことがある。 + 終了コードだけで判断せず、エラー一覧の内容を見ること +- `2_RunAllTests.ps1` は `Result*.txt` を書き換える。**差分 0 なら中身は同じ** +- 前提(DB・サービス・IIS Express)は [`RELEASE.md`](RELEASE.md) 2 節 + +--- + +## 2. リリース(NuGet 公開) + +**一次情報は [`RELEASE.md`](RELEASE.md) と [`CS/NuGet/README.md`](CS/NuGet/README.md)。** + +``` +1. develop → master へマージ(--no-ff)し、タグをプッシュ +2. .\0_SetVersion.ps1 -Version 3.3.0 +3. コミット & push ← Source Link はこのコミットに固定される +4. CS\0_Release4Nuget.bat ← 版はアセンブリに焼き込まれる +5. CS\NuGet\_NuGetPack.bat ← 版の一致(ソース・DLL)を自動検査 +6. 確認 5 点 ← README.md 2 節 +7. set NUGET_API_KEY=<キー> + CS\NuGet\out\sp\_NuGetPush.bat +8. キーを Revoke(Delete しない) +``` + +### バージョンを上げる + +```powershell +cd root\programs +.\0_SetVersion.ps1 -Version 3.3.0-alpha1 -WhatIf # 変更内容の確認 +.\0_SetVersion.ps1 -Version 3.3.0-alpha1 # 実行 +``` + +`Directory.Build.props` と net48 6 本の `AssemblyInfo.cs` を一括更新する。 +**プレリリース サフィックスはアセンブリの版には入らない。** +→ [`RELEASE.md`](RELEASE.md) フェーズ 0 + +### 公開前の確認 5 点 + +→ [`CS/NuGet/README.md`](CS/NuGet/README.md) 2 節 + +``` +1. .nupkg と .snupkg が対で出ている(.nupkg に pdb が入っていない) +2. PDB が portable(先頭 4 バイトが BSJB) +3. Source Link の URL が入っている(net48 と net10.0 の両方) +4. nuspec の <repository commit> が PDB のコミットと一致 +5. そのコミットが GitHub 上にある(raw URL が 200)+ ワーキング ツリーが綺麗 +``` + +### テスト公開(`Erutcurtsarfni.Oyruot.Public`) + +``` +CS\0_Release4Nuget.bat +CS\NuGet\_T_NuGetPack.bat 3.3.0-alpha2 ← 版は引数で渡す +set NUGET_API_KEY=<キー> +CS\NuGet\out\sp\_T_NuGetPush.bat +``` + +作業ブランチ上で行ってよい。→ [`CS/NuGet/README.md`](CS/NuGet/README.md) 4 節 + +### 生成物を消す + +``` +CS\NuGet\_Cleanup.bat ← in\ と out\ の全パッケージ +CS\NuGet\_Cleanup.bat Touryo.Infrastructure ← その接頭辞だけ +``` + +パック バッチが自動で呼ぶので、通常は不要。→ [`CS/NuGet/README.md`](CS/NuGet/README.md) 6 節 + +--- + +## 3. VB 側のビルド + +``` +root\programs\VB\0_ExecAllBat.bat ← 通し(先に CS 側を建てる) +``` + +- 先頭で `cd "..\CS"` して C# 側の `2_Build_NuGet_net48.bat` を呼ぶ。**VB は C# の成果物に依存する** +- **個別実行では見つからない不具合がある。** `1_DeleteDir.bat` が `obj` / `packages` を + 消した後にだけ露見するものがあるため、**通しで確かめること**(#533) +- 合格の目安 : ビルド成功 22 / 失敗 0 + +--- + +## 4. ツールを CLI で使う + +**引数の一覧は README に無い。`/HELP` が一次情報。** + +| ツール | 場所 | +|---|---| +| `DaoGen_Tool`(墨壺) | [`README.md`](CS/Frameworks/Tools/DaoGen_Tool/README.md) | +| `DeployZipPackWithHTTP` | [`README.md`](CS/Frameworks/Tools/DeployZipPackWithHTTP/README.md) | + +終了コードだけで判断せず、**生成物の存在も確認する**(パス区切りを誤ると成功を返しつつ別の場所に出る)。 + +--- + +## 5. コードを書く前に + +**規約は [`CODING.md`](CODING.md)、領域ごとの事情は各 `ANALYSIS.md`。** + +| | | +|---|---| +| ファイル ヘッダ・更新者名・Copyright ブロック | [`CODING.md`](CODING.md) 1 節 | +| `ArgumentException` だけ引数の順が違う | [`CODING.md`](CODING.md) 3 節 | +| フレームワーク本体 | [`CS/Frameworks/ANALYSIS.md`](CS/Frameworks/ANALYSIS.md) | +| net48 サンプル | [`CS/Samples/ANALYSIS.md`](CS/Samples/ANALYSIS.md) | +| netcore サンプル | [`CS/Samples4NetCore/ANALYSIS.md`](CS/Samples4NetCore/ANALYSIS.md) | + +### `.bat` を書くとき + +- **リリース・公開に使う bat は非 ASCII を書かない**(コメントも英語)。BOM も不要 +- **`chcp` を bat の中で使わない** +- 非 ASCII が**外部プログラムへ渡す引数**なら消せない。その場合は + コンソールのコード ページに合わせる(Shift-JIS・BOM なし) +- 改行は **CRLF** + +→ [`CODING.md`](CODING.md) 4 節 + +### `.ps1` を書くとき + +- **UTF-8 BOM 付き** +- **PowerShell 5.1 と 7 の両方で動くこと。** 変更したら 5.1 でも実行する + +```powershell +powershell.exe -NoProfile -Command "Set-Location 'root\programs'; .\3_SmokeTest.ps1" +``` + +→ [`CODING.md`](CODING.md) 5 節 + +--- + +## 6. よく踏む落とし穴 + +| 症状 | 原因 | 対処 | +|---|---|---| +| `'xxx' is not recognized` が大量に出る | bat の非 ASCII とコード ページ | ASCII 化。[`CODING.md`](CODING.md) 4 節 | +| `MSB4226`(`Microsoft.WebApplication.targets`) | nuget が別製品の MSBuild を拾った | `nuget.exe restore ... %NUGET_MSBUILD%` | + +**NuGet パッケージ作成の落とし穴は +[`CS/NuGet/README.md`](CS/NuGet/README.md) 9 節**にまとめてある。 + +``` +.snupkg だけ 403 / F11 でローカルが開く / nuspec と PDB のコミット不一致 +リビルド忘れ / net48 だけ効かない / 公開したコミットが消えた +``` + +**上 5 つは公開前に机上で分かる。** 2 節の確認 5 点を省かないこと。 + +--- + +## 7. エージェントとして守ること + +**一次情報は [`AGENTS.md`](../../AGENTS.md)。** + +- **Git 操作をしない**(`add` / `commit` / `push` / `checkout` / `switch` / `branch` / + `reset` / `restore` / `stash`)。参照系(`status` / `diff` / `log` / `show` 等)は自由 +- **GitHub への投稿は、文面を提示して承認を得てから。** `gh` で行い、`--body-file` を使う。 + アカウントは `OsscJpDevInfra`(`gh auth status` で確認) +- **Issue のクローズ・ラベル・アサイン、PR の作成やマージは人が行う** +- **NuGet への push は人のみ**(外部公開で取り消しが困難) +- 前提となるサービスや DB の状態が足りないときは、**勝手に変えず対処方法とともに報告する** diff --git a/root/programs/CODING.md b/root/programs/CODING.md new file mode 100644 index 000000000..7bc232a76 --- /dev/null +++ b/root/programs/CODING.md @@ -0,0 +1,246 @@ +# コーディング規約 + +**既存コードに合わせること。** + +この文書は `root/programs/` 配下(C# / VB / bat / ps1)に共通で適用する。 +領域ごとの分析・ビルド手順・落とし穴は、各領域の `ANALYSIS.md` にある。 + +| 対象 | 文書 | +|---|---| +| フレームワーク本体 | [`CS/Frameworks/ANALYSIS.md`](CS/Frameworks/ANALYSIS.md) | +| net48 サンプル | [`CS/Samples/ANALYSIS.md`](CS/Samples/ANALYSIS.md) | +| netcore サンプル | [`CS/Samples4NetCore/ANALYSIS.md`](CS/Samples4NetCore/ANALYSIS.md) | + +> **既存箇所の一括置換はしない。** 下位互換の維持が最優先のため +> ([`Contributing.ja.md`](../../Contributing.ja.md))、新規・修正箇所から適用する。 + +--- + +## 1. ファイル ヘッダ(**新規追加時も必須**。ただし新規と既存で書式が異なる) + +### 新規ファイルに付けるヘッダ(これが現行の書式) + +```csharp +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// ...(定型 15 行) +// +#endregion + +//********************************************************************************** +//* クラス名 :CallController +//* クラス日本語名 :クライアント ライブラリ +//* +//* 作成者 :xxx +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/07/31 xxx 新規作成 +//********************************************************************************** +``` + +※ 更新者は ClaudeCode:玄人 幸道、GitHubCopilot:後輩 郎党 で。 + +> **`Copyright (C) ... Hitachi Solutions,Ltd.` のブロックは、新規ファイルには付けない。** +> 開発元が企業からコミュニティに移ったため。 +> Apache License の region と、クラス名・日本語名・更新履歴のブロックは従来どおり必要。 + +### 既存ファイルの場合 + +既存ファイルの先頭には次の Copyright ブロックが付いている。**これは削除せず、そのまま残す。** + +```csharp +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** +``` + +**既存ファイルを変更した場合は、更新履歴に 1 行追記するのがこのリポジトリの慣習。** + +## 2. その他の規約 + +- **コメント・XML ドキュメントは日本語**。`<summary>` は全 public/protected メンバに付与 + (`DocumentationFile` を出力しているため、欠けると警告)。 +- `#region` / `#endregion` による細かいブロック分割が徹底されている(`BaseController` は 100 以上)。 +- `<remarks>自由に利用できる。</remarks>` … 業務コードから直接呼んでよい API の目印。 + `<remarks>業務コード親クラス1から利用される派生の末端</remarks>` … オーバーライド専用の目印。 +- 拡張ポイントは **`UOC_` プレフィクス**(`FxLiteral.UOC_METHOD_HEADER`)。 + P層の集約イベント ハンドラも `UOC_<ControlId>_Click` のような命名規則でリフレクション解決される。 +- 定数は `FxLiteral`(Framework, 777 行)/ `MyLiteral`(Business)/ `PubLiteral`(Public)に集約。 + **文字列リテラル直書きではなく、これらに定数を追加する。** +- **利用者に見せる文言は `Resources` の `.resx` に置く**(国際化のため)。 + `FxLiteral` 等は「変わらない値」、`.resx` は「訳し分ける文言」で、役割が違う。 + **フレームワークにもツールにもある。** 対応は次のとおり。 + + | 場所 | リソース | 取り出し方 | + |---|---|---| + | `Infrastructure/Public/Resources/` | `PublicExceptionMessageResource` | `PublicExceptionMessage.XXX`(プロパティ名がキー) | + | `Infrastructure/Framework/Resources/` | `FrameworkExceptionMessageResource` | `FrameworkExceptionMessage.XXX` | + | `Infrastructure/Business/Resources/` | `MyBusiness{Application,System}ExceptionMessageResource` | 同上 | + | `Tools/*/Resources/` | `Resource` | `ResourceMgr.GetString("キー")` | + + **`.resx` は 2 つ 1 組。** 既定(英語)と `*.ja-JP.resx`(日本語)の**両方**に足す。 + `*.Designer.cs` も更新が要る(VS でデザイナを開けば再生成される)。 + + 例外メッセージには別系統もある。**`MSGDefinition.xml` / `MSGDefinition_ja-JP.xml`** + を `GetMessage.GetMessageDescription("I0011")` で引く形で、 + こちらは `root/files/resource/Xml/` と各ツールの配下にある。**既存に合わせること。** +- 命名: `Base*`(Framework 提供の抽象)→ `My*`(Business 層テンプレート、アプリで改変前提)。 + アプリ側は `LayerB` / `LayerD` / `TestParameterValue` / `TestReturnValue` を実装(`Samples/` 参照)。 +- 変数はプライベート フィールド `_xxx` + 明示的プロパティ(自動プロパティは新しい箇所のみ)。 + +## 3. 引数を検査する例外(`ArgumentException` だけ引数の順が違う) + +**3 つとも「引数名」を渡すが、渡す位置が違う。** +`ArgumentException` **だけメッセージが先**で、ここが取り違えの温床になる。 + +| 例外 | 第 1 引数 | 第 2 引数 | +|---|---|---| +| `ArgumentNullException` | **引数名** | メッセージ | +| `ArgumentOutOfRangeException` | **引数名** | 実際の値(3 引数版)→ メッセージ | +| `ArgumentException` | **メッセージ** | **引数名** | + +`ArgumentException("userId")` と書くと、**引数名ではなくメッセージが "userId" になる**。 +引数名を伝えたいなら第 2 引数に置く。 + +```csharp +throw new ArgumentNullException(nameof(bytes)); +throw new ArgumentOutOfRangeException("ecc", ecc, "Invalid"); +throw new ArgumentException("Length is less than 128 bits.", "cek"); // 引数名は第 2 +``` + +既存コードは 148 箇所すべてこの規約どおり +(`ArgumentException` は 139 箇所あり、大半はメッセージのみ。 +メッセージは `PublicExceptionMessage` の定数を使う)。 + +**引数名は `nameof` で書く。** 引数名を変えたときに追随するため。 +文字列リテラルだと乖離しても誰も気付かない。実際、`ArrayOperator.GetLongFromByte` は +分割時(2019/05/28)の旧名 `"bytData"` が残り、**存在しない引数名**を渡していた +(2026/08/06 に修正、#522)。 + +> **既存箇所の一括置換はしない。** 下位互換の維持が最優先のため +> ([`Contributing.ja.md`](../../Contributing.ja.md))、新規・修正箇所から適用する。 + +## 4. bat ファイルの文字コード + +**非 ASCII 文字(日本語)を含む `.bat` は UTF-8 BOM 付きにする。** + +BOM が無いと、cmd.exe がバッチをバイト オフセットで読み進める際に文字境界がずれ、 +**`@rem` コメントの途中から先がコマンドとして実行される**ことがある +(`'xxx' は、内部コマンドまたは外部コマンド…として認識されていません` が出る)。 + +| BOM | 起動 CP=932 | 起動 CP=65001 | +|---|---|---| +| なし | エラーなし | **エラーあり(間欠)** | +| **あり** | **エラーなし** | **エラーなし** | + +- 実害は「紛らわしいエラー表示」に留まり、**後続の実コマンドは飛ばない**。 +- 純粋に ASCII のみの bat に BOM は不要(差分ノイズになるだけ)。 + + **日本語を書き足すときに BOM の有無を確認すること。** + +`root/programs/CS/` 配下で非 ASCII を含む bat は、すべて BOM 付きになっている。 + +### BOM は万能ではない。危ない bat は ASCII のみにする(#532) + +**BOM を付けても、対話コンソール(CP=932)で解析ずれが起きることがある。** + +#531 で、NuGet の push bat(UTF-8 BOM + CRLF + `chcp` なし)を +利用者が cmd から実行したところ、日本語の `@rem` が実行されて次が出た。 + +``` +'onfig' is not recognized as an internal or external command, +'…ても、そちらは消えない。' is not recognized as an internal or external command, +'NuGet.Config' is not recognized as an internal or external command, +``` + +- **非対話(`cmd /c`)では再現しない。** 手元で確認しても出ないため気付けない +- **`chcp 65001` を入れても直らない。** + むしろコードページが途中で変わる分、条件が増える +- 上の表(BOM あり=エラーなし)は**目安であって保証ではない** + +**実害は紛らわしいエラー表示に留まり、後続の実コマンドは飛ばない** +(#531 でも、エラー表示の後で push 自体は成功していた)。 +とはいえ、公開作業中に大量のエラーが出るのは危険である。 + +> **重要な bat(リリース・公開に使うもの)は、非 ASCII を一切書かない。** +> コメントも英語にする。ASCII のみなら BOM は不要で、 +> どのコードページから起動しても壊れない。 +> +> `root\programs\CS\NuGet\*.bat` と `root\programs\CS\0_Release4Nuget.bat` は +> この方針にしてある(各ファイルの先頭に `NOTE: keep this file pure ASCII` と記載)。 + +**日本語を `echo` する場合も同じ。** +cmd.exe は BOM 付き UTF-8 でも、内容をコンソールのコードページで解釈するため、 +CP=932 では文字化けする(`chcp` を入れても、それ自体が解析ずれの種になる)。 + +### 例外 : 非 ASCII が「引数」である bat(#532) + +**ASCII 化できるのは、非 ASCII がコメントか表示のときだけ。** +外部プログラムに**引数として渡す**文字列が日本語なら、消しようがない。 + +| 非 ASCII の役割 | 対処 | +|---|---| +| コメント・`echo` | **ASCII 化する。** リリース・公開に使う bat は必ず | +| **外部プログラムへ渡す引数** | **消せない。** コンソールのコードページに合わせて符号化する(この環境では **Shift-JIS・BOM なし**) | + +`root\programs\bak\BackupCICDLog\z_GrepResult*.bat` がこれに当たる。 + +```bat +rem このファイルは、SJISでないと動かない。 +set PATH=C:\Program Files (x86)\sakura;%PATH% +sakura -GREPMODE -GKEY="ビルドに" -GFOLDER="." -GFILE="*.log" -GOPT=P -GCODE=4 +``` + +検索キーワードは、cmd.exe がバッチのバイト列を読んで `sakura.exe` の +コマンドラインへ渡す。**UTF-8 で保存すると、CP=932 のコンソールでは +文字化けしたキーワードが渡り、grep が何も見つけない。** + +**エラーにならず、静かに結果が空になる**ため、解析ずれより気付きにくい。 +**この 3 本は Shift-JIS のままにしてある。BOM を付けてはならない。** + +> `-GCODE` は**検索対象ファイル**の文字コード指定であって、 +> バッチ自身の符号化とは別である。 + +## 5. ps1 ファイルの文字コードと、PowerShell 5.1 / 7 の両対応 + +**`.ps1` は Windows PowerShell 5.1 と PowerShell 7 の両方で動くこと。** + +開発時は `pwsh`(7)で確認しがちだが、利用者は `powershell.exe`(5.1)で実行する。 +7 だけで確認すると 5.1 で落ちる。既踏の落とし穴は次の 4 点。 + +| 事象 | 原因 | 対処 | +|---|---|---| +| 構文エラー・文字化け(`繧ケ繝・ャ繝・`) | 5.1 は BOM 無しの `.ps1` を **ANSI(Shift_JIS)**として読む | **UTF-8 BOM 付き**で保存する | +| 同じファイルなのに差分が出る | `Get-Content` の既定エンコードが 5.1 は ANSI、7 は UTF-8 | **`-Encoding UTF8`** を明示する | +| HTTP が常に失敗(状態コード `-1`) | `-SkipHttpErrorCheck` は **7 以降にしかない** | バージョンを見て付け外しする | +| 実行中に画面がクリアされ、それまでの結果が消える | 子プロセスの `chcp 65001` はコンソール全体に影響する | スクリプト冒頭で先に切り替える | + +```powershell +# 7 専用の引数は、バージョンを見て付け外しする +if ($PSVersionTable.PSVersion.Major -ge 6) { $p.SkipHttpErrorCheck = $true } + +# コンソールのコード ページと、PowerShell の出力エンコードは別物。判定を分けること +if ((cmd /c chcp) -notmatch '65001') { cmd /c chcp 65001 | Out-Null } +if ([Console]::OutputEncoding.CodePage -ne 65001) +{ + [Console]::OutputEncoding = New-Object Text.UTF8Encoding $false +} +``` + +- **`.bat` は「非 ASCII を含むときだけ」BOM 付き**(8.4)だが、 + **`.ps1` は非 ASCII を含むなら必ず BOM 付き**。5.1 が既定で ANSI として読むため。 +- 5.1 の `[Console]::OutputEncoding` は**起動時の値のまま**で、実行中にコード ページが + 変わっても追随しない。同じ画面で 2 回目を実行したときに化ける原因になる。 +- **変更したら 5.1 でも実行して確かめること。** + +```powershell +powershell.exe -NoProfile -Command "Set-Location 'root\programs'; .\3_SmokeTest.ps1" +``` + +検証スクリプト側での具体的な適用例は +[`SMOKETEST.md`](SMOKETEST.md) 「PowerShell 5.1 と 7 の両対応」を参照。 + +--- diff --git a/root/programs/CS/0_ExecAllBat.bat b/root/programs/CS/0_ExecAllBat.bat index 04b288f5d..80cfcba7b 100644 --- a/root/programs/CS/0_ExecAllBat.bat +++ b/root/programs/CS/0_ExecAllBat.bat @@ -12,7 +12,7 @@ timeout 5 echo | call 1_DeleteDir.bat echo | call 1_DeleteFile.bat -echo | call 2_Build_NuGet_nettcore100.bat +echo | call 2_Build_NuGet_netcore100.bat echo | call 3_Build_Business_netcore100.bat echo | call 3_Build_BusinessRichClient_netcore100.bat diff --git a/root/programs/CS/0_Release4Nuget.bat b/root/programs/CS/0_Release4Nuget.bat index a2e6fa2f1..2f3e53230 100644 --- a/root/programs/CS/0_Release4Nuget.bat +++ b/root/programs/CS/0_Release4Nuget.bat @@ -1,3 +1,32 @@ +@echo off +@rem -------------------------------------------------- +@rem Build for the NuGet packages (#531) +@rem +@rem Pass DEBUG_TYPE=portable. z_Common.bat honours the value when the +@rem caller has already set it. z_Common.bat used to be edited by hand +@rem and reverted afterwards, which risked publishing with "full" when +@rem the revert was forgotten. +@rem +@rem - a .snupkg is only accepted when the PDB is portable +@rem - the Source Link information also lives in the portable PDB +@rem +@rem NOTE: keep this file pure ASCII (#532). +@rem -------------------------------------------------- +set DEBUG_TYPE=portable + +@rem -------------------------------------------------- +@rem Normalize the source paths recorded in the PDB to /_/... (#531). +@rem +@rem - the published package no longer carries the local paths of the +@rem machine that built it +@rem - Visual Studio opens the file at the path in the PDB when it exists, +@rem so an absolute path means Source Link is never used on the build +@rem machine. Normalizing lets it be verified there as well. +@rem +@rem z_Common.bat defaults this to false, so ordinary builds are unaffected. +@rem -------------------------------------------------- +set CI_BUILD=true + @echo on timeout 5 @@ -8,9 +37,9 @@ echo | call 2_Build_NuGet_net48.bat timeout 5 echo | call 1_DeleteDir.bat -echo | call 2_Build_NuGet_nettcore80.bat +echo | call 2_Build_NuGet_netcore100.bat @echo on timeout 5 -echo | call 4_Build_CopyAssemblies.bat +echo | call 4_Build_CopyAssemblies.bat \ No newline at end of file diff --git a/root/programs/CS/10_Build_WebAppCore_sample.bat b/root/programs/CS/10_Build_WebAppCore_sample.bat index 56e4393c1..20eb10f27 100644 --- a/root/programs/CS/10_Build_WebAppCore_sample.bat +++ b/root/programs/CS/10_Build_WebAppCore_sample.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -19,12 +19,8 @@ rem -------------------------------------------------- rem Batch build of MVC_Sample. rem -------------------------------------------------- -set CURRENTDIR=%cd% -cd "Samples4NetCore\Backend\MVC_Sample\MVC_Sample" -if exist "node_modules" rd /s /q "node_modules" -call RestoreLib1.bat -call RestoreLib2.bat -cd %CURRENTDIR% +@rem npm / grunt によるクライアント ライブラリの復元は廃止した。 +@rem (wwwroot\lib 配下をリポジトリに直接格納する方式に移行済み) dotnet restore "Samples4NetCore\Backend\MVC_Sample\MVC_Sample.sln" dotnet msbuild %COMMANDLINE% "Samples4NetCore\Backend\MVC_Sample\MVC_Sample.sln" diff --git a/root/programs/CS/10_Build_WebApp_sample.bat b/root/programs/CS/10_Build_WebApp_sample.bat index fbd9753a8..5770bb537 100644 --- a/root/programs/CS/10_Build_WebApp_sample.bat +++ b/root/programs/CS/10_Build_WebApp_sample.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of WebForms_Sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\WebApp_sample\WebForms_Sample\WebForms_Sample.sln" +..\nuget.exe restore "Samples\WebApp_sample\WebForms_Sample\WebForms_Sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\WebApp_sample\WebForms_Sample\WebForms_Sample.sln" pause @@ -26,7 +26,7 @@ pause rem -------------------------------------------------- rem Batch build of MVC_Sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\WebApp_sample\MVC_Sample\MVC_Sample.sln" +..\nuget.exe restore "Samples\WebApp_sample\MVC_Sample\MVC_Sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\WebApp_sample\MVC_Sample\MVC_Sample.sln" pause diff --git a/root/programs/CS/1_DeleteDir.bat b/root/programs/CS/1_DeleteDir.bat index 05ed92469..99f1dc138 100644 --- a/root/programs/CS/1_DeleteDir.bat +++ b/root/programs/CS/1_DeleteDir.bat @@ -1,4 +1,4 @@ -@echo off +@echo off set DIRECTORIES=packages, obj, bin, bld, Temp, PrecompiledWeb, MigrationBackup, .vs @echo -------------------------------------------------- diff --git a/root/programs/CS/2_Build_NuGet_net48.bat b/root/programs/CS/2_Build_NuGet_net48.bat index 5d6e15523..783f351e2 100644 --- a/root/programs/CS/2_Build_NuGet_net48.bat +++ b/root/programs/CS/2_Build_NuGet_net48.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -18,10 +18,10 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Build the batch Infrastructure(Nuget48) rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Infrastructure\Nuget_net48.sln" +..\nuget.exe restore "Frameworks\Infrastructure\Nuget_net48.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Infrastructure\Nuget_net48.sln" -..\nuget.exe restore "Frameworks\Infrastructure\Nuget_RichClient_net48.sln" +..\nuget.exe restore "Frameworks\Infrastructure\Nuget_RichClient_net48.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Infrastructure\Nuget_RichClient_net48.sln" pause diff --git a/root/programs/CS/3_Build_Business_net48.bat b/root/programs/CS/3_Build_Business_net48.bat index 39ccf9e81..a0f86bfda 100644 --- a/root/programs/CS/3_Build_Business_net48.bat +++ b/root/programs/CS/3_Build_Business_net48.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -19,7 +19,7 @@ rem -------------------------------------------------- rem Build the Infrastructures rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Infrastructure\Business_net48.sln" +..\nuget.exe restore "Frameworks\Infrastructure\Business_net48.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Infrastructure\Business_net48.sln" pause diff --git a/root/programs/CS/4_Build_Framework_Tool.bat b/root/programs/CS/4_Build_Framework_Tool.bat index fcce053e2..993686ecc 100644 --- a/root/programs/CS/4_Build_Framework_Tool.bat +++ b/root/programs/CS/4_Build_Framework_Tool.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of DPQuery_Tool. rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Tools\DPQuery_Tool\DPQuery_Tool.sln" +..\nuget.exe restore "Frameworks\Tools\DPQuery_Tool\DPQuery_Tool.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Tools\DPQuery_Tool\DPQuery_Tool.sln" pause @@ -26,10 +26,18 @@ pause rem -------------------------------------------------- rem Batch build of DaoGen_Tool. rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Tools\DaoGen_Tool\DaoGen_Tool.sln" +..\nuget.exe restore "Frameworks\Tools\DaoGen_Tool\DaoGen_Tool.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Tools\DaoGen_Tool\DaoGen_Tool.sln" pause +rem -------------------------------------------------- +rem Batch build of DeployZipPackWithHTTP. +rem -------------------------------------------------- +..\nuget.exe restore "Frameworks\Tools\DeployZipPackWithHTTP\DeployZipPackWithHTTP.sln" %NUGET_MSBUILD% +%BUILDFILEPATH% %COMMANDLINE% "Frameworks\Tools\DeployZipPackWithHTTP\DeployZipPackWithHTTP.sln" + +pause + rem ------------------------------------------------------- endlocal diff --git a/root/programs/CS/4_Build_Framework_ToolCore.bat b/root/programs/CS/4_Build_Framework_ToolCore.bat index a33ae808e..6e22def44 100644 --- a/root/programs/CS/4_Build_Framework_ToolCore.bat +++ b/root/programs/CS/4_Build_Framework_ToolCore.bat @@ -31,5 +31,13 @@ call dotnet msbuild %COMMANDLINE% "Frameworks\Tools\DaoGen_Tool\DaoGen_ToolCore. pause +rem -------------------------------------------------- +rem Batch build of DeployZipPackWithHTTP. +rem -------------------------------------------------- +call dotnet restore "Frameworks\Tools\DeployZipPackWithHTTP\DeployZipPackWithHTTPCore.sln" +call dotnet msbuild %COMMANDLINE% "Frameworks\Tools\DeployZipPackWithHTTP\DeployZipPackWithHTTPCore.sln" + +pause + rem ------------------------------------------------------- endlocal diff --git a/root/programs/CS/5_Build_2CS_sample.bat b/root/programs/CS/5_Build_2CS_sample.bat index a6ca71725..38b66e6a9 100644 --- a/root/programs/CS/5_Build_2CS_sample.bat +++ b/root/programs/CS/5_Build_2CS_sample.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of 2CSClientWin_sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\2CS_sample\2CSClientWin_sample\2CSClientWin_sample.sln" +..\nuget.exe restore "Samples\2CS_sample\2CSClientWin_sample\2CSClientWin_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\2CS_sample\2CSClientWin_sample\2CSClientWin_sample.sln" pause @@ -26,7 +26,7 @@ pause rem -------------------------------------------------- rem Batch build of GenDaoAndBatUpd_sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\2CS_sample\GenDaoAndBatUpd_sample\GenDaoAndBatUpd_sample.sln" +..\nuget.exe restore "Samples\2CS_sample\GenDaoAndBatUpd_sample\GenDaoAndBatUpd_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\2CS_sample\GenDaoAndBatUpd_sample\GenDaoAndBatUpd_sample.sln" pause @@ -34,7 +34,7 @@ pause rem -------------------------------------------------- rem Batch build of TimeStamp_sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\2CS_sample\TimeStamp_sample\TimeStamp_sample.sln" +..\nuget.exe restore "Samples\2CS_sample\TimeStamp_sample\TimeStamp_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\2CS_sample\TimeStamp_sample\TimeStamp_sample.sln" pause @@ -42,7 +42,7 @@ pause rem -------------------------------------------------- rem Batch build of 2CSClientWPF_sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\\2CS_sample\2CSClientWPF_sample\2CSClientWPF_sample.sln" +..\nuget.exe restore "Samples\\2CS_sample\2CSClientWPF_sample\2CSClientWPF_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\\2CS_sample\2CSClientWPF_sample\2CSClientWPF_sample.sln" pause diff --git a/root/programs/CS/5_Build_Bat_sample.bat b/root/programs/CS/5_Build_Bat_sample.bat index 11f4c5d0e..1627c678d 100644 --- a/root/programs/CS/5_Build_Bat_sample.bat +++ b/root/programs/CS/5_Build_Bat_sample.bat @@ -18,6 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of SimpleBatch_sample. rem -------------------------------------------------- +..\nuget.exe restore "Samples\Bat_sample\SimpleBatch_sample\SimpleBatch_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\Bat_sample\SimpleBatch_sample\SimpleBatch_sample.sln" pause @@ -25,6 +26,7 @@ pause rem -------------------------------------------------- rem Batch build of RerunnableBatch_sample. rem -------------------------------------------------- +..\nuget.exe restore "Samples\Bat_sample\RerunnableBatch_sample\RerunnableBatch_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\Bat_sample\RerunnableBatch_sample\RerunnableBatch_sample.sln" pause @@ -32,6 +34,7 @@ pause rem -------------------------------------------------- rem Batch build of RerunnableBatch_sample2. rem -------------------------------------------------- +..\nuget.exe restore "Samples\Bat_sample\RerunnableBatch_sample2\RerunnableBatch_sample2.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\Bat_sample\RerunnableBatch_sample2\RerunnableBatch_sample2.sln" pause @@ -39,6 +42,7 @@ pause rem -------------------------------------------------- rem Batch build of RerunnableBatch_sample3. rem -------------------------------------------------- +..\nuget.exe restore "Samples\Bat_sample\RerunnableBatch_sample3\RerunnableBatch_sample3.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\Bat_sample\RerunnableBatch_sample3\RerunnableBatch_sample3.sln" pause diff --git a/root/programs/CS/5_Build_CLI_sample.bat b/root/programs/CS/5_Build_CLI_sample.bat index f32353d67..84a94647a 100644 --- a/root/programs/CS/5_Build_CLI_sample.bat +++ b/root/programs/CS/5_Build_CLI_sample.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. diff --git a/root/programs/CS/6_Build_WSSrv_sample.bat b/root/programs/CS/6_Build_WSSrv_sample.bat index 2d5ae92d7..8c9f18697 100644 --- a/root/programs/CS/6_Build_WSSrv_sample.bat +++ b/root/programs/CS/6_Build_WSSrv_sample.bat @@ -24,6 +24,7 @@ md "Samples\WS_sample\Build" rem -------------------------------------------------- rem Batch build of WSServer_sample. rem -------------------------------------------------- +..\nuget.exe restore "Samples\WS_sample\WSServer_sample\WSServer_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\WS_sample\WSServer_sample\WSServer_sample.sln" xcopy /E /Y "Samples\WS_sample\WSServer_sample\bin\%BUILD_CONFIG%" "Samples\WS_sample\Temp\%BUILD_CONFIG%\" diff --git a/root/programs/CS/7_Build_Framework_WS.bat b/root/programs/CS/7_Build_Framework_WS.bat index f6964b626..2965cce5c 100644 --- a/root/programs/CS/7_Build_Framework_WS.bat +++ b/root/programs/CS/7_Build_Framework_WS.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of ServiceInterface(ASPNETWebService). rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Infrastructure\ServiceInterface\ASPNETWebService\ASPNETWebService.sln" +..\nuget.exe restore "Frameworks\Infrastructure\ServiceInterface\ASPNETWebService\ASPNETWebService.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Infrastructure\ServiceInterface\ASPNETWebService\ASPNETWebService.sln" pause @@ -34,7 +34,7 @@ pause rem -------------------------------------------------- rem Batch build of ServiceInterface(WCFService). rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Infrastructure\ServiceInterface\WCFService\WCFService.sln" +..\nuget.exe restore "Frameworks\Infrastructure\ServiceInterface\WCFService\WCFService.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Infrastructure\ServiceInterface\WCFService\WCFService.sln" pause diff --git a/root/programs/CS/7_Build_Framework_WSCore.bat b/root/programs/CS/7_Build_Framework_WSCore.bat index 11e2561a9..292d576a8 100644 --- a/root/programs/CS/7_Build_Framework_WSCore.bat +++ b/root/programs/CS/7_Build_Framework_WSCore.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. diff --git a/root/programs/CS/8_Build_WSClnt_sample.bat b/root/programs/CS/8_Build_WSClnt_sample.bat index b67fefb9a..08c51dadd 100644 --- a/root/programs/CS/8_Build_WSClnt_sample.bat +++ b/root/programs/CS/8_Build_WSClnt_sample.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of WSClientWin_sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\WS_sample\WSClient_sample\WSClientWin_sample\WSClientWin_sample.sln" +..\nuget.exe restore "Samples\WS_sample\WSClient_sample\WSClientWin_sample\WSClientWin_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\WS_sample\WSClient_sample\WSClientWin_sample\WSClientWin_sample.sln" pause @@ -26,7 +26,7 @@ pause rem -------------------------------------------------- rem Batch build of WSClientWPF_sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\WS_sample\WSClient_sample\WSClientWPF_sample\WSClientWPF_sample.sln" +..\nuget.exe restore "Samples\WS_sample\WSClient_sample\WSClientWPF_sample\WSClientWPF_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\WS_sample\WSClient_sample\WSClientWPF_sample\WSClientWPF_sample.sln" pause @@ -41,7 +41,7 @@ pause rem -------------------------------------------------- rem Batch build of WSClientWinCone_sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\WS_sample\WSClient_sample\WSClientWinCone_sample\WSClientWinCone_sample.sln" +..\nuget.exe restore "Samples\WS_sample\WSClient_sample\WSClientWinCone_sample\WSClientWinCone_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\WS_sample\WSClient_sample\WSClientWinCone_sample\WSClientWinCone_sample.sln" pause diff --git a/root/programs/CS/99_BuildLibsAtOtherRepos.bat b/root/programs/CS/99_BuildLibsAtOtherRepos.bat index e7524a966..e42530f1d 100644 --- a/root/programs/CS/99_BuildLibsAtOtherRepos.bat +++ b/root/programs/CS/99_BuildLibsAtOtherRepos.bat @@ -1,5 +1,14 @@ @echo off +@rem ************************************************** +@rem [注意] このバッチは現在動作しません(未保守)。 +@rem 呼び出している net45 / net46 / net47 / netstd20 / +@rem netcore20 / netcore30 用のバッチは既に存在しません。 +@rem xcopy 元の Build_net45 ... Build_netcore30 も生成されません。 +@rem 現行の targetFramework は net48 / netcore100 です。 +@rem 使用する場合は全面的な見直しが必要です。 +@rem ************************************************** + @rem 本バッチファイルの作成にあたり、以下のサイトを参考にしました。 @rem 【Bat】【vim】香り屋Vimをダウンロードしてインストールまでするbatファイル - Qiita @rem https://qiita.com/koryuohproject/items/beed1a28ad6a1f60256d diff --git a/root/programs/CS/99_BuildLibsAtOtherReposInTimeOfDev.bat b/root/programs/CS/99_BuildLibsAtOtherReposInTimeOfDev.bat index b6e7feda0..8de9dcef1 100644 --- a/root/programs/CS/99_BuildLibsAtOtherReposInTimeOfDev.bat +++ b/root/programs/CS/99_BuildLibsAtOtherReposInTimeOfDev.bat @@ -1,5 +1,14 @@ @echo off +@rem ************************************************** +@rem [注意] このバッチは現在動作しません(未保守)。 +@rem 呼び出している net45 / net46 / net47 / netstd20 / +@rem netcore20 / netcore30 用のバッチは既に存在しません。 +@rem xcopy 元の Build_net45 ... Build_netcore30 も生成されません。 +@rem 現行の targetFramework は net48 / netcore100 です。 +@rem 使用する場合は全面的な見直しが必要です。 +@rem ************************************************** + @rem 本バッチファイルの作成にあたり、以下のサイトを参考にしました。 @rem 【Bat】【vim】香り屋Vimをダウンロードしてインストールまでするbatファイル - Qiita @rem https://qiita.com/koryuohproject/items/beed1a28ad6a1f60256d diff --git a/root/programs/CS/Frameworks/ANALYSIS.md b/root/programs/CS/Frameworks/ANALYSIS.md new file mode 100644 index 000000000..bd56b0017 --- /dev/null +++ b/root/programs/CS/Frameworks/ANALYSIS.md @@ -0,0 +1,619 @@ +# ANALYSIS.md — Open棟梁 フレームワーク本体(CS/Frameworks)コード分析 + +対象: `root/programs/CS/Frameworks` / ブランチ: `develop` +最終更新: 2026-07-31 + +本書は **コーディング・エージェントが本リポジトリで作業する際の Context** を目的とした分析結果である。 +「どこに何があるか」「どの規約に従うべきか」「何を壊しやすいか」を記す。 + +--- + +## 1. これは何か + +`Open棟梁 (OpenTouryo)` は、日立ソリューションズ発の .NET 用アプリケーション・フレームワーク(Apache-2.0)。 +2007年から継続開発されており、**P層(画面)/B層(業務ロジック)/D層(データアクセス)の3層モデル**と、 +**「UOC」= User Own Coding(利用者が実装する拡張ポイント)** という設計思想が全体を貫く。 + +- 上流ドキュメント: `OpenTouryoDocuments` リポジトリ(本リポジトリ外) +- 配布形態: NuGet パッケージ(`Touryo.Infrastructure.*` / アセンブリ名 `OpenTouryo.*`) +- プロジェクト・ポリシーは **リポジトリ ルートの `AGENTS.md`(`CLAUDE.md` はそれへのポインタ)** に定義済み。 + → **エージェントは git 操作(add/commit/push/checkout/branch/reset/restore/stash)を行わない。** + 作業結果はワーキング ツリーに残し、変更内容を報告するに留める。 + +--- + +## 2. ディレクトリとアセンブリの対応 + +### 2.1 `Infrastructure/`(フレームワーク本体) + +| ディレクトリ | アセンブリ | ルート名前空間 | 役割 | +|---|---|---|---| +| `Public/` | `OpenTouryo.Public` | `Touryo.Infrastructure.Public` | 汎用ライブラリ。フレームワーク非依存で単体利用可 | +| `Public/Security/` | `OpenTouryo.Public.Security` | `...Public.Security` | 暗号・署名・JWT/JWS/JWE・鍵交換・パスワードハッシュ | +| `Public/Db/Dam*/` | `OpenTouryo.Dam*` | `...Public.Db` | DBMS 別データアクセス制御(Dam)の別アセンブリ | +| `Framework/` | `OpenTouryo.Framework` | `...Framework` | フレームワーク中核(P/B/D の親クラス、通信、認証、例外) | +| `Framework/RichClient/` | `OpenTouryo.Framework.RichClient` | `...Framework.RichClient` | WinForms/WPF 向け | +| `Business/` | `OpenTouryo.Business` | `...Business` | **業務フレームワーク=テンプレート層**。アプリ側でカスタマイズ前提 | +| `Business/RichClient/` | `OpenTouryo.Business.RichClient` | `...Business.RichClient` | 同上(リッチクライアント) | +| `CustomControl/` | `OpenTouryo.CustomControl` | `...CustomControl` | ASP.NET Web Forms カスタム コントロール(net48 のみ) | +| `CustomControl/RichClient/` | `OpenTouryo.CustomControl.RichClient` | `...CustomControl.RichClient` | WinForms カスタム コントロール | +| `ServiceInterface/` | — | — | サービス公開ホスト(ASP.NET WebAPI / WCF-TCP)。net48 のみ | + +ファイル数の目安: Public 188 / Framework 76 / CustomControl 50 / Business 42 / ServiceInterface 10。 + +### 2.2 `Tools/` — 開発支援 GUI ツール(WinForms) + +- `DaoGen_Tool` : DB スキーマから D層 Dao クラス+SQL(XML) を自動生成 +- `DPQuery_Tool` : DPQ(動的パラメタライズド・クエリ)XML の編集・検証 +- `DeployZipPackWithHTTP` : ZIP を HTTP で配布し、クライアントで展開する(#528 で復元) + +> `DeployZipPackWithHTTP` は `ZipperV2` / `UnZipperV2` を使う唯一の利用者。 +> **ZIP 部品を変えたら、このツールのビルドと疎通も確かめること** +> (`4_Build_Framework_Tool.bat` / `4_Build_Framework_ToolCore.bat` に入れてある)。 +> **実行方法・マニフェストの書式・疎通の手順は +> [`README.md`](Tools/DeployZipPackWithHTTP/README.md) が一次情報。** +> IIS Express で完結するので、IIS を立てなくても確かめられる。 + +### 2.3 `Tests/` — テスト(**xUnit/NUnit ではない**) + +| 名前 | 内容 | 専用の文書 | +|---|---|---| +| `TestCode` | コンソール EXE。`Program.cs` から `Test*.Root()` を順次呼ぶ手動確認型。期待値は `Result48.txt` / `ResultCore100.txt` と比較。**DB には接続しない** | [`README.md`](Tests/TestCode/README.md) | +| `TestDataAccess` | データ アクセスのテスト(#520)。`TestCode` と同じ構成だが**DB に接続する**。`/MODE` で対象 DBMS を切り替える(既定は SQL Server のみ) | [`README.md`](Tests/TestDataAccess/README.md) | +| `TestLog` | ログ出力確認(log4net/NLog、1〜3) | — | +| `TestBatch` | バッチ起動確認 | — | +| `EncAndDecUtil` / `EncAndDecUtilCUI` | 暗号・署名ユーティリティの GUI/CUI 確認 | — | + +**`TestCode` と `TestDataAccess` は専用の `README.md` を持つ。** +「何をテストしているか」「ケースを書き足すときの決まり」「ケース設計の根拠」は +そちらが一次情報。`TESTING.md` は 8 ケース全体の運用を扱い、この詳細は持たない。 + +**テストを書き足す前に `TestCode/README.md` を読むこと。** +結果ファイルとの比較で判定するため、**環境で変わる値を出してはならない**という制約がある +(例外はメッセージを出さず型名だけ、日時は固定値、`csproj` は net48 / core100 の両方を直す)。 + +**重要:** テスト プロジェクトはフレームワークを `ProjectReference` ではなく +**`HintPath` で `Infrastructure/Build_netcore100/net10.0/*.dll` を参照**する。 +→ **フレームワークを先にビルドしないとテストは古い DLL を見る。** +また `net48` / `core100` の 2 プロジェクトが `..\*.cs` を `Link` で共有する(実体は 1 つ)。 + +--- + +## 3. アーキテクチャ:呼び出しフロー + +``` +[P層] 画面コード + BaseController(Web Forms) / BaseMVController(MVC5) / BaseMVControllerCore(ASP.NET Core MVC) + ↓ MyBase*Controller(Business層のテンプレート)を継承してアプリが実装 + ↓ +[通信] CallController.Invoke(serviceName, parameterValue) + ↓ ProtocolNameService でプロトコル解決(TMProtocolDefinition.xml) + ↓ InProcessNameService で assembly/class 解決(TMInProcessDefinition.xml) + ↓ Latebind.InvokeMethod → "DoBusinessLogic" + ↓ +[B層] BaseLogic.DoBusinessLogic(parameterValue, iso) + ├ UOC_ConnectionOpen … Dam 生成/Connection Open/BeginTransaction + ├ UOC_PreAction … ACCESS ログ等 + ├ UOC_DoAction … ★業務処理。MyFcBaseLogic は "UOC_" + MethodName へ Latebind 振り分け + ├ UOC_AfterAction + ├ Commit(_dam と _dams[key] すべて) + ├ UOC_AfterTransaction + └ catch → Rollback → UOC_ABEND(例外種別ごとに 3 オーバーロード) + finally → ConnectionClose + ↓ +[D層] BaseDao ← MyBaseDao ← CmnDao / アプリ個別 Dao + ↓ +[DAM] BaseDam ← DamSqlSvr / DamODBC / DamOLEDB / DamMySQL / DamPstGrS / DamManagedOdp / DamDB2 / DamHiRDB +``` + +### 3.1 引数・戻り値クラス + +`BaseParameterValue`(`ScreenId` / `ControlId` / `MethodName` / `ActionType`、すべて読み取り専用) +→ `MyParameterValue`(+ `MyUserInfo User`)→ `_3TierParameterValue`(検索条件・ソート・ページング等) + +`BaseReturnValue`(`ErrorFlag` / `ErrorMessageID` / `ErrorMessage` / `ErrorInfo`) +→ `MyReturnValue` → `_3TierReturnValue` + +- `[Serializable]`。WS 越えのため。 +- `ActionType` は `"SQL%common"` のように **`%` 区切りの複合文字列**。 + 先頭要素が **データ プロバイダ選択キー**(`SQL`/`OLE`/`ODB`/`ODP`/`MCN`/`NPS`/`DB2`/`HIR`)として + `MyBaseLogic.UOC_ConnectionOpen` / `MyFcBaseLogic.UOC_ConnectionOpen` で分岐する。 + +### 3.2 自動振り分け(重要なマジック) + +`MyFcBaseLogic.UOC_DoAction` は `"UOC_" + parameterValue.MethodName` を **リフレクションで呼ぶ**。 +戻り値は `ref` では戻らない(例外時に失われる)ため、**`this.ReturnValue` プロパティ経由で受け渡す**。 + +```csharp +private void UOC_SelectCount(TestParameterValue p) // private でよい +{ + TestReturnValue r = new TestReturnValue(); + this.ReturnValue = r; // ★必ず冒頭で設定する + ... +} +``` + +`ReturnValue` の setter は `WasCalledFromDoBusinessLogic` フラグを見ており、 +`DoBusinessLogic` 経由でない呼び出しでは `FrameworkException` を投げる。 + +### 3.3 例外モデル + +| 例外 | 意味 | `DoBusinessLogic` の挙動 | +|---|---|---| +| `BusinessApplicationException` | 業務例外(想定内) | Rollback → `ErrorFlag=true` を戻り値に設定 → **リスローしない** | +| `BusinessSystemException` | 業務システム例外 | Rollback → `UOC_ABEND` → **リスロー** | +| `Exception`(その他) | 想定外 | Rollback → `UOC_ABEND(ref)` → **リスローしない**(UOC 側で必要なら throw) | +| `FrameworkException` | フレームワーク内部エラー | 上位へ | + +すべて `messageID` プロパティを持つ(`Information` は `BusinessApplicationException` のみ)。 + +--- + +## 4. データアクセス(Open棟梁の中核的な差別化要素) + +### 4.1 3 つのクエリ形態(`DbEnum.QueryStatusEnum`) + +- **SPQ** 静的パラメタライズド・クエリ … `.sql` ファイル +- **DPQ** 動的パラメタライズド・クエリ … `.xml` ファイル。`<WHERE>` / `<IF>` / `<ELSE>` で + **パラメタが設定されている条件行だけを動的に組み立てる**(SQL インジェクション耐性を保ったまま動的 WHERE を実現) + +```xml +<ROOT> + SELECT [ShipperID],[CompanyName] FROM [Shippers] + <WHERE> + WHERE + <IF>AND [ShipperID] = @ShipperID<ELSE>AND [ShipperID] IS NULL</ELSE></IF> + <IF>AND [CompanyName] LIKE @CompanyName_Like</IF> + </WHERE> +</ROOT> +``` + +サンプルは `root/files/resource/Sql/`(`sqlserver` / `oracle` / `mysql` / `pstgrs` / `db2` / `hirdb` / `ole_odbc` 別サブディレクトリあり)。 + +### 4.2 Dam / Dao の責務 + +- `BaseDam`(3198 行、`Public/Db/BaseDam.cs`)… SQL ロード、パラメタ記号変換(`@`/`:`/`?`)、DPQ 展開、 + トランザクション制御、コマンド タイムアウトを担う。DBMS 差異はここに集約。 +- `BaseDao` … `SetSqlByFile` / `SetSqlByCommand` / `SetParameter` / `ExecSelectFill_DT` / + `ExecSelect_DR` / `ExecSelectScalar` / `ExecInsUpDel_NonQuery` を `protected` で提供。 + UOC は `UOC_PreQuery` / `UOC_AfterQuery(sql)` / `UOC_AfterQuery(sql, ex)`。 +- `MyBaseDao` … `SetSqlByFile2`(`appSettings:sqlTextFilePath` を基点にパス解決。 + `MyBaseDao.UseEmbeddedResource = true` で埋め込みリソースへ切替)+ SQLTRACE ログ・性能測定。 +- `CmnDao` … Dao クラスを書かずに使える汎用 Dao。パラメタを `Dictionary` に溜め、実行直前に反映。 + `BaseDao` のメソッドを `new` で隠蔽して `public` 化している(**`override` ではない点に注意**)。 +- `_3TierEngine`(1452 行)… `_3TierParameterValue` の検索条件辞書から SQL を生成する CRUD エンジン。 + `DaoGen_Tool` が生成するコードとセットで使う。 + +### 4.3 分離レベル + +`DbEnum.IsolationLevelEnum`: `NotConnect`(接続しない) / `NoTransaction` / `ReadUncommitted` / +`ReadCommitted` / `RepeatableRead` / `Serializable` / `Snapshot` / `DefaultTransaction` / `User`。 +`User` は「B層テンプレート側で決める」の意で、`MyBaseLogic` では `ReadCommitted` にフォールバックする。 + +--- + +## 5. 設定(XML 定義ファイル + appSettings) + +### 5.1 XML 定義ファイル(`root/files/resource/Xml/`) + +| appSettings キー | ファイル | 用途 | +|---|---|---| +| `FxXMLMSGDefinition` | `MSGDefinition[_ja/_zh-CN].xml` | メッセージ ID → 文言(`GetMessage`) | +| `FxXMLSPDefinition` | `SPDefinition.xml` | 共有プロパティ(`GetSharedProperty`) | +| `FxXMLSCDefinition` | `SCDefinition.xml` | 画面遷移定義(`BaseController` の遷移チェック) | +| `FxXMLTCDefinition` | `TCDefinition.xml` | トランザクション定義(`TransactionControl`)。接続文字列キー+分離レベル(`nc/nt/uc/rc/rr/sz/ss/df`) | +| `FxXMLTMInProcessDefinition` | `TMInProcessDefinition.xml` | インプロセス名前解決(論理名→assembly/class) | +| `FxXMLTMProtocolDefinition` | `TMProtocolDefinition.xml` | プロトコル/URL/タイムアウト/プロパティ | + +読み込み順は **埋め込みリソース → 物理ファイル → 未設定なら空 XML(OFF 扱い)→ それ以外はエラー**。 +パスには `%ENV%` 形式の環境変数を展開できる(`StringVariableOperator.BuiltStringIntoEnvironmentVariable`)。 + +### 5.2 主な appSettings キー(`Fx` プレフィクス) + +- 画面制御: `FxSessionTimeOutCheck` `FxDoubleTransmissionCheck` `FxScreenTransitionMode` + `FxScreenTransitionCheck` `FxErrorScreenPath` `FxOKMessageDialogPath` `FxYesNoMessageDialogPath` + `FxDialogFramePath` `Fx*IconPath` `Fx*MaxQueueLength` `FxDefault*Style` `FxCacheControl` +- コントロール接頭辞(集約イベント ハンドラの識別に使う): `FxPrefixOfButton` `FxPrefixOfTextBox` … 等 15 種 +- DB: `FxSqlCacheSwitch` `FxSqlCommandTimeout` `FxSqlDotnetTypeInfo` `FxSqlEncoding` `FxSqlTraceLog` +- ログ: `FxLog4NetConfFile` / `LogLib`(`"nlog"` で NLog、既定は log4net) +- 国際化: `FxExceptionMessageCulture` `FxBusinessMessageCulture` +- 実行環境: `FxContainerization`(**true のとき環境変数を appSettings より優先**。JSON キーの `:` は `__` で表現) +- `_3TierEngine` 用: `MethodNameHeaderS/FooterS` `MethodNameHeaderD/FooterD` + `MethodLabel_Ins/Sel/Upd/Del/SelCnt` `UpdateParamHeader/Footer` `LikeParamHeader/Footer` +- Dao: `sqlTextFilePath` / 接続文字列 `ConnectionString_SQL|OLE|ODBC|ODP|MCN|NPS|DB2|HIR` + +### 5.3 設定の読み取り API + +`Public/Util/GetConfigParameter.cs` に集約。 +- net48: `System.Configuration`(`app.config` / `web.config`) +- .NET (Core): `Microsoft.Extensions.Configuration`。**使用前に `GetConfigParameter.InitConfiguration(...)` が必須** + (`IConfiguration` / `IConfigurationBuilder` / JSON ファイル名 / 引数なし=`appsettings.json` の 4 オーバーロード)。 + JSON は `"appSettings": { ... }` セクション配下に置く慣習。 + +--- + +## 6. マルチ ターゲットと条件コンパイル(**最も事故りやすい箇所**) + +### 6.1 ターゲット + +| 系統 | csproj 命名 | TFM | +|---|---|---| +| .NET Framework | `*_net48.csproj` / `*_net48.sln` | `v4.8`(旧形式 csproj) | +| .NET | `*_netcore100.csproj` / `*_netcore100.sln` | `net10.0`(SDK 形式) | +| リッチクライアント (.NET) | 同上 | `net10.0-windows7.0` | + +出力先は `Infrastructure/Build_net48/` と `Infrastructure/Build_netcore100/net10.0/`(`.gitignore` 対象)。 + +### 6.2 プリプロセッサ シンボル + +| シンボル | 定義のされ方 | 意味 | +|---|---|---| +| `NETCOREAPP` | **.NET SDK が net10.0 に暗黙定義**(csproj の記述に依存しない) | 「.NET (Core) ビルド」=実質「非 net48」 | +| `NETSTD` | `Framework` / `Public.Security` / `Dam*` の `DefineConstants` に**明示** | 歴史的経緯(下記) | +| `NET48` | net48 側 | .NET Framework 固有 | +| `NETCOREAPP2_0` | 旧コード内に残存 | 実質デッド分岐 | +| `PERFORMANCE_LOG_SWITCH` | 任意 | 性能ログ | + +#### なぜ 2 つあるのか(歴史的経緯) + +かつては **.NET Standard でビルドされるライブラリ**と **.NET Core でビルドされるライブラリ**が +併存しており、その区別が `NETSTD` / `NETCOREAPP` だった。 +**現在は .NET Standard 版が全て .NET Core(net10.0)に統一された**ため、この区別は意味を失っている。 + +#### 現在の実際の成立状況(実測) + +**`NETCOREAPP` は .NET SDK が net10.0 ターゲットに自動的に定義する暗黙シンボル**であり、 +`<DefineConstants>` に書かれていなくても **全 netcore100 プロジェクトで真**になる +(同条件の最小プロジェクトを作って `#warning` で確認済み)。 + +| プロジェクト | `NETCOREAPP` | `NETSTD` | +|---|---|---| +| `Public` / `Business` / `Business.RichClient` / `CustomControl.RichClient` / `Framework.RichClient` | ✓(暗黙) | **✗** | +| `Framework` / `Public.Security` / `Dam*` | ✓(暗黙) | ✓(明示) | +| net48 の全プロジェクト | ✗ | ✗ | + +したがって現状は次が成り立つ。 + +- `#if NETCOREAPP` … netcore100 ビルドで**常に真**。 +- `#if (NETSTD || NETCOREAPP)` … `#if NETCOREAPP` と**完全に等価**。 +- `#if NETSTD` … `NETSTD` を明示定義した 3 系統でのみ真。**それ以外では偽になる。** + +#### 注意点 + +**`NETSTD` を明示していないプロジェクト(`Public` / `Business` / `*.RichClient`)の中で +素の `#if NETSTD` を書くと、黙って net48 側の分岐に落ちる。** +実測では該当箇所は 0 件(下表のとおり、書き分けは現状すべて正しい)だが、コード追加時の落とし穴になる。 + +| プロジェクト | `(NETSTD \|\| NETCOREAPP)` | `NETSTD` 単独 | `NETCOREAPP` 単独 | +|---|---:|---:|---:| +| `Public` | 36 | 0 | 2 | +| `Public.Security` | 0 | 83 | 0 | +| `Framework` | 21 | 8 | 1 | +| `Framework.RichClient` | 0 | 0 | 1 | +| `Business` | 0 | 0 | 6 | +| `Business.RichClient` | 0 | 0 | 4 | +| `CustomControl.RichClient` | 0 | 0 | 27 | + +> **整理の余地**: 上記のとおり 3 つの書き方はすべて `NETCOREAPP`(=非 net48)と等価に帰着する。 +> `<DefineConstants>` から `NETSTD` を削除し、`#if NETSTD` / `#if (NETSTD || NETCOREAPP)` を +> `#if NETCOREAPP` に統一すれば、このシンボル体系は 1 本化できる(対象 約 150 箇所)。 +> 機械的だが影響範囲が広いため、実施は別途判断。 + +### 6.3 csproj の `Compile Remove` によるファイル除外 + +SDK 形式 csproj はワイルドカード込みなので、**プラットフォーム非対応ファイルを `Compile Remove` で明示的に外している**。 +新規ファイルを追加すると **net10.0 側に自動で含まれてしまう**ため、Windows 専用 API を使う場合は +`Compile Remove` の追加が必要。主な除外例: + +- `Public_netcore100`: `Win32/**` `WinProc/**` `Security/**` `Db/Dam*/**`、 + `IO/BinarySerialize.cs` `IO/Zip*.cs` `Log/CustomEventLog.cs` `Log/SecurityEventLog.cs` + `Db/DamOLEDB.cs` `Db/DamOraClient.cs` `Util/SharedMemory.cs` +- `Framework_netcore100`: `RichClient/**`、`Presentation/BaseController.cs`(Web Forms) + `Presentation/BaseMasterController.cs` `Presentation/BaseMVController.cs` `Presentation/FxEventArgs.cs` + `Transmission/IWCFTCPSvcForFx.cs` `Util/FxSessionUtil.cs` `Util/FxHttpQueryStringIndex.cs` +- `Business_netcore100`: `Csp/**` `RichClient/**`、 + **`Business/MyBaseLogic.cs` と `Business/_3TierEngine.cs` / `Common/_3Tier*Value.cs`**、 + `Presentation/MyBaseController.cs` `MyBaseMVController.cs` `MyBaseAsyncApiController.cs` 他 +- `Public.Security_netcore100`: `IdentityImpersonation.cs` `KeyExg/EcdhCng*.cs` + +→ **`_3TierEngine` と `MyBaseLogic` は net48 専用**。.NET (Core) 側で使うのは `MyFcBaseLogic` 系。 + +### 6.4 net48 専用の機能 + +- ASP.NET Web Forms 一式(`BaseController` 4836 行、`CustomControl/`) +- `CallController` のリモート プロトコル(`FxEnum.TmProtocol` は .NET (Core) では `InProcess` のみ): + ASP.NET WS / WCF-HTTP / WCF-TCP / ASP.NET WebAPI(JSON-RPC) +- `ServiceInterface/`(WCF ホスト、ASP.NET WebAPI ホスト) + +--- + +## 7. ビルド + +`root/programs/CS/` 直下の連番 `.bat` をダブルクリック実行する運用(`_Please run with a double-click...txt`)。 + +| bat | 内容 | +|---|---| +| `2_Build_NuGet_net48.bat` / `2_Build_NuGet_netcore100.bat` | `Nuget_*.sln` + `Nuget_RichClient_*.sln` をビルド(=フレームワーク本体) | +| `3_Build_Business_*.bat` / `3_Build_BusinessRichClient_*.bat` | Business 層 | +| `4_Build_CopyAssemblies.bat` / `4_Build_Framework_Tool*.bat` | 成果物コピー・ツール | +| `5〜8_*` | サンプル各種 | +| `y_Build_TestCode*.bat` | テスト | +| `0_ExecAllBat.bat` | 全実行 | +| `z_Common.bat` / `z_Common2.bat` | ビルド ツールのパス解決(各 bat が冒頭で `call` する) | + +.NET (Core) 側は `dotnet restore` → `dotnet msbuild` を呼ぶだけなので、 +**エージェントは bat を経由せず直接 `dotnet build "Frameworks\Infrastructure\Nuget_netcore100.sln"` してよい。** +net48 側は MSBuild / devenv が必要(Windows + VS 前提)。 + +`dotnet build Nuget_netcore100.sln` は **0 エラー / 20 警告**。 +警告はすべて NuGet 脆弱性警告(12 節)で、コンパイル警告ではない。 + +#### `z_Common.bat` と `z_Common2.bat`(MSBuild 版 / devenv 版) + +両者は **`%BUILDFILEPATH%`(ビルド ツールのパス)と `%COMMANDLINE%`(ビルド引数)という +同じインターフェイスを提供する差し替え可能な対**であり、呼び出し側の bat は +`call` するファイルを変えるだけでビルド ツールを切り替えられる設計になっている。 + +| | ビルド ツール | `%COMMANDLINE%` | +|---|---|---| +| `z_Common.bat` | MSBuild.exe | `/p:Configuration=<構成> /p:DebugType=<型> /p:ContinuousIntegrationBuild=<真偽> /p:DeterministicSourcePaths=<真偽> -v:d` | +| `z_Common2.bat` | devenv.com / devenv.exe | `/build <構成>`(devenv 構文) | + +`z_Common.bat` の次の 2 つは、**呼び出し側が先に設定していればその値を尊重する**(#531)。 +NuGet パッケージ用のビルド(`0_Release4Nuget.bat`)だけが既定と異なる値を渡す。 + +| 変数 | 既定 | `0_Release4Nuget.bat` | 目的 | +|---|---|---|---| +| `DEBUG_TYPE` | `full` | `portable` | `.snupkg` は portable PDB でなければ受け付けられない | +| `CI_BUILD` | `false` | `true` | PDB のソース パスを `/_/...` に正規化する | + +`CI_BUILD` は `ContinuousIntegrationBuild` と `DeterministicSourcePaths` の +**両方**に渡している。前者から後者への変換は `Microsoft.NET.Sdk` のターゲットが +行うため、**旧形式 csproj には効かない**(Source Link の自動組み込みが効かないのと +同じ構図。渡さないと **net48 側だけ絶対パスのまま残る**)。 + +**以前は `z_Common.bat` を手で書き換えて戻す運用だった。** +戻し忘れると `full` のまま公開してしまうため、呼び出し側から渡す形にした。 + +`ContinuousIntegrationBuild` を有効にすると、PDB に**ビルドしたマシンの +ローカル パスが残らない**。これは体裁の問題ではない。Visual Studio は +**PDB のパスにファイルが在れば、それを開く**ため、絶対パスのままだと +**ビルドしたマシンでは Source Link を通らず、動作確認にならない**。 +詳細は [`NuGet/README.md`](../NuGet/README.md)。 + +`z_Common2.bat` は、**MSBuild.exe ではエラーになるが devenv.com では通る、というケースが +散在していた時期に、ビルド ツールを devenv へ差し替えるために用意されたもの**。 +現在はどの bat からも呼ばれておらず、変数定義にも不具合が残っているため、そのままでは動作しない +(詳細はファイル冒頭のコメント参照)。**通常は `z_Common.bat` を使う。** + +`z_Common.bat` は `vswhere` で MSBuild を解決し、見つからなければ明示エラーで停止する +(固定パス群はフォールバックとして存置)。エディションに依存しない。 + +### 7.1 ビルド順(厳守) + +``` +Public → Public.Security → Framework → Business → Tools / Tests / Samples +``` + +**`4_Build_CopyAssemblies.bat`(`Build_net48` → `Build\` の xcopy)を飛ばすと、 +net48 のサンプルとツールが一切ビルドできない。** +`Frameworks\Infrastructure\Build\` を `HintPath` 参照するプロジェクトが CS/VB 合わせて **42 件**あるため +(`Samples/*` の全 net48 サンプル、`Tools/DaoGen_Tool`・`DPQuery_Tool`、`Tests/TestLog*`)。 +`0_ExecAllBat.bat` が `2_`/`3_` → `4_CopyAssemblies` → `5_`〜`10_`(サンプル)の順で呼ぶのはこのため。 + +`Build\` に入るのは **net48 の成果物のみ**で、.NET (Core) 側に相当物は無い +(`Samples4NetCore` は `Build_netcore100\net10.0\` を直接参照する)。この非対称は設計どおり。 + +### 7.2 バージョン番号の一元管理 + +**`Infrastructure/Directory.Build.props` の `OpenTouryoVersion` が唯一の定義箇所。** + +```xml +<PropertyGroup> + <OpenTouryoVersion>3.0.0</OpenTouryoVersion> + <Company>Hitachi Solutions</Company> +</PropertyGroup> +``` + +| 反映先 | 仕組み | +|---|---| +| SDK 形式アセンブリ(7 個) | 各 csproj の `<Version>$(OpenTouryoVersion)</Version>` | +| NuGet パッケージ | nuspec は `<version>$version$</version>` と `<dependency id="Touryo.Infrastructure.*" version="$version$" />`。`_NuGetPack.bat` が props から値を読み `nuget pack -Properties version=...` で渡す | + +- **旧形式 csproj(`*_net48.csproj`)には効かない。** `Microsoft.Common.props` をインポートしないため。 + net48 のバージョンは各プロジェクトの `Properties\AssemblyInfo.cs` が持つ。 +- **`Business` 系は 1.0.0 で別系統。** `Business/Properties/AssemblyInfo.cs` が `AssemblyVersion("1.0.0.0")` であり、 + Public / Framework / Public.Security の 3.0.0.0 とは意図的に分けている。 + そのため `Directory.Build.props` では `<Version>` を全体に設定せず、 + `OpenTouryoVersion` という独自プロパティをパッケージ対象の 7 プロジェクトだけが参照する形にしている。 + +> **注意**: `Directory.Build.props` の XML コメント内にハイフン 2 個の連続(`--`)を書くと +> XML として不正になり、MSBuild がプロジェクトの読み込みに失敗する。区切り線に使わないこと。 + +### 7.3 NuGet パッケージ化 + +`root/programs/CS/NuGet/`(`*.nuspec` + `_NuGetPack.bat`、`in/` に DLL を staging)。 +手順は [`NuGet/README.md`](../NuGet/README.md) を参照。 + +- **nuspec の `<dependencies>` は csproj の `PackageReference` と一致している**(余分・不足・版ズレなし)。 + 依存を増減したら nuspec 側も合わせること。 +- パッケージ自身と `Touryo.Infrastructure.*` の相互依存のバージョンは `$version$` トークンで自動追随する(7.2 節)。 +- `Symbol_Framework.RichClient.nuspec` のみ、`net10.0-windows7.0` ビルドを `lib\net10.0` に配置している(12 節)。 + +--- + +## 8. コーディング規約 + +**[`CODING.md`](../../CODING.md) に移した(`root/programs/CODING.md`)。** + +ファイル ヘッダの書式と更新者名、`ArgumentException` 系の引数の順、 +`.bat` / `.ps1` の文字コードは、いずれもそちらが一次情報である。 + +`root/programs/` 配下に共通で効く規約であり、 +本書(Frameworks の分析)に置くと他領域から参照しにくいため分離した。 + +| | `CODING.md` の節 | +|---|---| +| ファイル ヘッダ(**新規と既存で書式が違う**) | 1 | +| その他の規約(コメント・リソース・命名) | 2 | +| 引数を検査する例外 | 3 | +| bat ファイルの文字コード | 4 | +| ps1 の文字コードと PowerShell 5.1 / 7 の両対応 | 5 | +## 9. Public 層の主なユーティリティ(再実装しないこと) + +| 名前空間 | 主なクラス | +|---|---| +| `Public.Db` | `BaseDam` `SQLUtility` `DbEnum` `Dam*` | +| `Public.Dto` | `DTTable/DTRow/DTColumn`(マーシャリング可能な自前 DataTable)、`DataToPoco` `PocoToPoco` `DataToDictionary` | +| `Public.Str` | `CustomEncode`(Base64/Hex/URL) `StringChecker` `FormatChecker` `StringConverter` `FormatConverter` `CheckCharCode` `JIS2k4Checker` | +| `Public.Security` | `SymmetricCryptography` `ASymmetricCryptography` `GetHash` `GetKeyedHash` `MsgAuthCode` `DigitalSign*` `PrivacyEnhancedMail`、`Jwt/`(JWS RS/ES/HS 256-512、JWE RSA1_5+A128CBC-HS256 / RSA-OAEP+AES-GCM、`JwkSet`、鍵コンバータ)、`Aead/`、`KeyExg/`(ECDH/RSA)、`Pwd/GetPasswordHashV1/V2` | +| `Public.Log` | `LogIF`(静的 façade)。ロガー名は慣習的に `"ACCESS"` と `"SQLTRACE"`。バックエンドは `LogLib` 設定で log4net / NLog | +| `Public.Reflection` | `Latebind`(フレームワークの動的呼び出しの心臓部)、`MyAssemblies` | +| `Public.FastReflection` | `AccessorCacher` `CompiledExpressionCreater` `InstanceCreator<T>` `EnumToString*Extensions` | +| `Public.IO` | `ResourceLoader` `EmbeddedResourceLoader` `DeflateCompression` `ExponentialBackoff` `ZipperV2/UnZipperV2` | +| `Public.Util` | `GetConfigParameter` `PerformanceRecorder` `RandomValueGenerator` `EnvInfo` `PubCmnFunction` | +| `Public.Diagnostics` | `MyDebug`(`OutputDebugAndConsole`)`ObjectInspector` `StackFrameOperator` | +| `Public.Win32` / `WinProc` | P/Invoke 群(net48 のみ) | + +--- + +## 10. 認証まわり(`Framework/Authentication/`) + +比較的新しく、直近も更新されている領域(`fixed #503` / `#504` は `SAML2Client.cs`)。 + +- `OAuth2AndOIDCClient` … Authorization Code / PKCE(S256) / Client Credentials / ROPC / + Refresh / UserInfo / Revoke / Introspect / JWT Bearer / Device AuthZ / CIBA / Request Object / JWK Set。 + **すべて `static async Task<string>`(生 JSON を返す)**。`HttpClient` は `static` プロパティで差し替え可能。 +- `OAuth2AndOIDCConst` / `OAuth2AndOIDCEnum` / `OAuth2AndOIDCParams` / `CmnClientParams` +- トークン型: `CmnJwtToken` `AccessToken` `IdToken` `JwtAssertion` `RequestObject` `ResponseObject` `ClaimsInRO` +- `JwkSetStore` … JWK Set のキャッシュ +- SAML2: `SAML2Client`(`CreateRedirectRequest` / `CreatePostRequest` / `VerifyResponse`)、 + `SAML2Bindings` `SAML2Const` `SAML2Enum` `SAML2Params` +- 依存: `jose-jwt` 5.1.1 / `BouncyCastle.NetCore` 2.2.1(`Public.Security`) + +--- + +## 11. 主要な依存パッケージ(netcore100) + +| プロジェクト | パッケージ | +|---|---| +| Public | `log4net` 3.3.0, `NLog` 5.5.0, `Microsoft.Data.SqlClient` 6.0.1, `System.Data.Odbc` 9.0.4, `Newtonsoft.Json` 13.0.3, `Microsoft.Extensions.Configuration*` 9.0.4, `Zipangu` 1.1.8 | +| Public.Security | `jose-jwt` 5.1.1, `BouncyCastle.NetCore` 2.2.1, `System.Security.Cryptography.Xml` 9.0.18, `Newtonsoft.Json` 13.0.3 | +| Framework | `Microsoft.AspNetCore.{Http,Http.Extensions,Mvc,Session}` 2.3.0, `Microsoft.Extensions.PlatformAbstractions` 1.1.0 | +| Business | `Microsoft.AspNetCore.Authentication{,.Cookies}` 2.3.0, `Microsoft.AspNetCore.{Http,Mvc}` 2.3.0, `System.Security.Cryptography.Xml` 9.0.18, `Newtonsoft.Json` 13.0.3 ほか | + +**注意 1:** `Microsoft.AspNetCore.*` は **2.3.0(互換シム パッケージ)** を使い続けている。 +net10.0 のフレームワーク参照(`Microsoft.AspNetCore.App`)ではない。安易に上げると壊れる可能性が高い。 + +**注意 2:** `System.Security.Cryptography.Xml` は **4 箇所すべてを同じ版で揃える**こと。 +Dependabot が 1 プロジェクトずつしか上げないため、放っておくと版が割れて NU1903 が残る +(12 節に advisory と該当箇所を挙げてある)。 + +依存は Dependabot で随時更新される。**上表は目安であり、正確な値は csproj を直接見ること。** + +--- + +## 12. 落とし穴 / 既知の不整合(作業前に把握しておく) + +1. **`4_Build_CopyAssemblies.bat` を飛ばすと net48 のサンプル・ツールが全滅する**(7.1 節)。 +2. **`Compile Remove` を忘れると .NET (Core) ビルドが壊れる**(6.3 節)。 +3. **`CmnDao` は `new` による隠蔽**であって override ではない。`BaseDao` 型変数経由で呼ぶと親の実装が走る。 +4. **`ReturnValue` を設定し忘れると戻り値が null** になる(3.2 節)。例外時も同様。 +5. **`_dams` ディクショナリと `_dam` の二重管理**。Commit/Rollback/Close は両方に対して行われる。 + 複数 DB を使う場合は `SetDam(key, dam)` を使い、`GetDam(key)` で取り出す。 +6. **`BaseController.cs`(4836 行)と `BaseDam.cs`(3198 行)は巨大**。 + 変更時は該当 `#region` に閉じた修正に留め、全体リファクタは避ける(互換性維持が最優先の設計)。 +7. **VB 版ミラーが存在**: `root/programs/VB/Frameworks/Infrastructure/` に + `Business` / `CustomControl` / `ServiceInterface` の VB.NET 版がある(`Public` / `Framework` は C# 版を共有)。 + Business 層テンプレートの仕様を変えると **VB 側も追随が必要**。 +8. **作業ツリーに未追跡の生成物が残る**。`Build*/` と `ServiceInterface/*/dll/` は `.gitignore` 済み。 + 残るのは `*.cer`(テスト生成物)と `SAML2Client.cs.bak`(残骸)で、いずれもコミット対象ではない。 +9. `Public/Security/MyDebug.cs` は `Public/Diagnostics/MyDebug.cs` の**派生クラス**(重複ではない。 + アセンブリ分割の都合)。 +10. `TMProtocolDefinition2.xml` など「2」付きの定義ファイルが並存する。用途は用例違い。 +11. **`System.Security.Cryptography.Xml` は 9.0.18 で揃える**(NU1903 / 高、2026/08/08 に解消)。 + + 2 件の advisory が出ており、**9.0.15 では片方しか直っていない**。 + + | Advisory | 影響(9 系) | 修正版 | + |---|---|---| + | `GHSA-23rf-6693-g89p`(CVE-2026-50648) | `>= 9.0.0, <= 9.0.17` | **9.0.18** | + | `GHSA-37gx-xxp4-5rgx`(CVE-2026-33116) | `>= 9.0.0, <= 9.0.14` | 9.0.15 | + + 参照は次の 4 箇所。**すべて netcore100 側だけ**である。 + + ``` + Public/Security/Public.Security_netcore100.csproj + Business/Business_netcore100.csproj + Tests/EncAndDecUtilCUI/core100/EncAndDecUtilCUICore.csproj + NuGet/Symbol_Public.Security.nuspec + ``` + + > **net48 は、このパッケージを参照しない。** .NET Framework は + > `System.Security.dll` を BCL として持つため(`<Reference Include="System.Security" />`)。 + > 「net48 / netcore100 の両方を直す」という一般則は、**このパッケージには当てはまらない。** + + **Dependabot は 1 プロジェクトずつしか上げない。** #507 が `Public.Security` だけを + 9.0.15 にし、#510 がテスト プロジェクトだけを 9.0.18 にしたため、 + 一時 4 箇所が 3 通りの版に割れていた(84 警告)。 + **セキュリティ更新は、Dependabot の PR を取り込んだら他の参照も揃えること。** + 揃えておけば「もう脆弱でない」ため、同じ箇所への PR が後から来て競合することも無い + (運用は [`BUILDING.md`](../../BUILDING.md) 9 節)。 +12. **結果ファイル比較のテストは、検算しないと不具合を「正」として固定する。** + `ArrayOperator.GetLongFromByte` は桁の重みを `256 * j`(掛け算)で求めており、 + **3 byte 目から誤った値**を返していた(2026/08/06 に修正、#522)。 + 1〜2 byte は `256 * 1 == 256 ^ 1` でたまたま一致するため、呼び出し元 + (`CheckCharCode` → Shift_JIS の 1〜2 byte)では顕在化していなかった。 + **期待値を作るときは、出力をそのまま貼らず実装から検算し、境界を跨いだケースを置く** + ([`Tests/TestCode/README.md`](Tests/TestCode/README.md))。 +13. **`Public/IO` に、ビルド対象外の旧 ZIP 部品が残っている**。 + `ZipBase.cs` / `Zipper.cs` / `UnZipper.cs` は DotNetZip(非推奨・既知脆弱性 + `GHSA-xhg6-9j5j-w4vf`)に依存しており、**net48 / netcore100 の両方で除外**してある。 + - net48 … 列挙形式のため `<Compile>` に載っていない + - netcore100 … `<Compile Remove="IO\Zipper.cs" />` 等で明示的に除外 + + **現役は `ZipperV2` / `UnZipperV2`**(SharpZipLib、#524)。 + 旧ファイルを直しても何も起きない。**触るなら V2 の方。** + I/F 互換は無いが、**引数の並びと名前、列挙体のメンバ名は旧に合わせて**ある。 + 自己解凍書庫・選択条件の文字列・`StatusMSG` は落とした(代替は `ExtractedFiles`)。 +14. **`Symbol_Framework.RichClient.nuspec` の lib TFM が不正確**。 + `net10.0-windows7.0` ビルドを `lib\net10.0` に配置している。本来は `lib\net10.0-windows` が正しく、 + 現状は Linux 上の net10.0 消費者も解決してしまう。直すとパッケージ解決セマンティクスが変わるため据え置き。 + +--- + +## 13. サンプル(フレームワークの正しい使い方の参照先) + +> **詳細な分析は各ディレクトリの ANALYSIS.md を参照:** +> - `../Samples/ANALYSIS.md`(net48 版サンプル) +> - `../Samples4NetCore/ANALYSIS.md`(.NET 10 版サンプル) + +| パス | 内容 | +|---|---| +| `Samples/WebApp_sample/` | ASP.NET Web Forms / MVC5(net48) | +| `Samples/2CS_sample/` | 2層 C/S(WinForms / WPF) | +| `Samples/Bat_sample/` | バッチ(`SimpleBatch` / `RerunnableBatch` 1〜3) | +| `Samples/CLI_sample/` `Samples/WS_sample/` | CLI / Web サービス | +| `Samples4NetCore/Backend/MVC_Sample` `ASPNETWebService` | .NET (Core) 版 | +| `Samples4NetCore/Legacy/` | 上記の .NET (Core) 移植版 | + +典型的な B層実装は `Samples/Bat_sample/SimpleBatch_sample/Business/LayerB.cs`(`MyFcBaseLogic` 継承)。 +「テンプレ」`#region` に `UOC_メソッド名` という雛形がそのまま残っているのが本フレームワークの流儀。 + +--- + +## 14. エージェント向け作業チェックリスト + +- [ ] `AGENTS.md` のポリシー遵守(**git 操作をしない**) +- [ ] 変更対象が net48 / netcore100 / 両方のどれか判定(`Compile Remove` を確認) +- [ ] 条件コンパイルは **`#if NETCOREAPP`(=非 net48)を使う**。 + `#if NETSTD` は `Framework` / `Public.Security` / `Dam*` でしか真にならないので新規には使わない(6.2 節) +- [ ] 新規 .cs にはヘッダ コメント(Apache License / クラス名・日本語名・更新履歴)を付与。 + **Copyright ブロックは新規には付けない**(8.1 節) +- [ ] 既存 .cs 変更時は更新履歴に 1 行追記 +- [ ] public/protected メンバに日本語 `<summary>` を付与(DocumentationFile 出力のため) +- [ ] 文字列リテラルは `FxLiteral` / `MyLiteral` / `PubLiteral` に定数として追加 +- [ ] ビルド確認: `dotnet build Frameworks/Infrastructure/Nuget_netcore100.sln` + (net48 は MSBuild 必須) +- [ ] テスト実行前に **フレームワークを先にビルド**(`Build_netcore100/net10.0/*.dll` を HintPath 参照するため) +- [ ] Business 層テンプレートを変えたら VB 版ミラーの追随要否を報告 diff --git a/root/programs/CS/Frameworks/Infrastructure/Business/Business_netcore100.csproj b/root/programs/CS/Frameworks/Infrastructure/Business/Business_netcore100.csproj index 436310300..9a2dbe718 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Business/Business_netcore100.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Business/Business_netcore100.csproj @@ -64,7 +64,7 @@ <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.3.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.4" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> - <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.4" /> + <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.18" /> </ItemGroup> <ItemGroup> diff --git a/root/programs/CS/Frameworks/Infrastructure/Business/Presentation/MyBaseMVControllerCore.cs b/root/programs/CS/Frameworks/Infrastructure/Business/Presentation/MyBaseMVControllerCore.cs index a35534586..4927409fb 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Business/Presentation/MyBaseMVControllerCore.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Business/Presentation/MyBaseMVControllerCore.cs @@ -31,11 +31,14 @@ //* 2018/07/19 西野 大介 復元後のユーザー情報をSessionに設定するコードを追加 //* 2018/08/08 西野 大介 MyMVCCoreFilterAttributeをFilterAttributeとして設定 //* 2021/05/23 西野 大介 キャッシュ制御ヘッダの二重追加エラーの対応 +//* 2026/07/31 玄人 幸道 net48版から移植漏れのアクセスログ出力点を追加 +//* (View、OnResultExecuting、OnResultExecuted) //********************************************************************************** using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; @@ -74,15 +77,45 @@ namespace Touryo.Infrastructure.Business.Presentation { /// <summary>画面コード親クラス2</summary> /// <remarks>(オーバーライドして)自由に利用できる。</remarks> + /// <remarks> + /// IResultFilter を実装しているのは、ASP.NET Core の Controller が + /// IActionFilter / IAsyncActionFilter しか実装しておらず、 + /// OnResultExecuting / OnResultExecuted を override できないため。 + /// コントローラが IResultFilter を実装していると、MVC が ControllerResultFilter を + /// 自動的にフィルタ パイプラインへ追加し、本クラスの実装を呼び出す。 + /// (フィルタ属性ではなくコントローラ側に実装するのは、属性インスタンスが + ///  リクエスト間で共有され、性能測定用の状態を持たせられないため。) + /// </remarks> [MyMVCCoreFilter()] - public class MyBaseMVControllerCore : BaseMVControllerCore + public class MyBaseMVControllerCore : BaseMVControllerCore, IResultFilter { - /// <summary>性能測定</summary> + /// <summary>性能測定(アクション実行区間)</summary> private PerformanceRecorder perfRec; + /// <summary>性能測定(結果実行=レンダリング区間)</summary> + /// <remarks> + /// アクション実行区間の perfRec とは別インスタンスにする。 + /// .NET (Core) 版の PerformanceRecorder は Stopwatch ベースで、 + /// EndsPerformanceRecord の後に再度 Ends を呼んでも値が変わらないため、 + /// perfRec を使い回すとレンダリング区間が測定できないため。 + /// </remarks> + private PerformanceRecorder perfRecOfResult; + /// <summary>UserInfo</summary> protected MyUserInfo UserInfo; + /// <summary>ログのユーザ名・IPアドレス部を生成する</summary> + /// <returns>",ユーザ名,IPアドレス"</returns> + /// <remarks> + /// Session が OFF の場合は UserInfo が null のままになり得るため、 + /// ログ出力が原因で例外を出さないよう null を考慮する。 + /// </remarks> + private string GetLogUserPart() + { + return "," + (this.UserInfo != null ? this.UserInfo.UserName : "") + + "," + (this.UserInfo != null ? this.UserInfo.IPAddress : ""); + } + #region OnAction ///// <summary> @@ -204,6 +237,129 @@ public override async Task OnActionExecutionAsync(ActionExecutingContext context #endregion + #region View + + /// <summary> + /// 応答にビューを表示する ViewResult オブジェクトを作成します。 + /// Controller.View メソッド (Microsoft.AspNetCore.Mvc) + /// https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.aspnetcore.mvc.controller.view + /// </summary> + /// <param name="viewName">ビュー名</param> + /// <param name="model">モデル</param> + /// <returns>ViewResult オブジェクト</returns> + /// <remarks> + /// net48 版はマスタ ページを取る View(IView, object) / View(string, string, object) を + /// オーバーライドしているが、ASP.NET Core にマスタ ページの概念は無い。 + /// Core では他の View オーバーロードが最終的に本メソッドへ集約されるため、ここだけで足りる。 + /// </remarks> + [NonAction] + public override ViewResult View(string viewName, object model) + { + ViewResult vr = base.View(viewName, model); + + // View() / View(model) で呼ばれた場合、ViewName は null になる + // (実行時にアクション名で解決されるため)。その場合はアクション名を使う。 + string vn = string.IsNullOrEmpty(vr.ViewName) ? this.ActionName : vr.ViewName; + string[] temp = vn.Split('.'); + + // ------------ + // メッセージ部 + // ------------ + // ユーザ名, IPアドレス, + // レイヤ, 画面名, コントロール名, 処理名 + // 処理時間(実行時間), 処理時間(CPU時間) + // エラーメッセージID, エラーメッセージ等 + // ------------ + string strLogMessage = + this.GetLogUserPart() + + "," + "----->>" + + "," + this.ControllerName + + "," + this.ActionName + " -> " + temp[temp.Length - 1]; + + LogIF.InfoLog("ACCESS", strLogMessage); + + return vr; + } + + #endregion + + #region OnResult + + /// <summary> + /// アクション メソッドによって返されたアクション結果が実行される前に呼び出されます。 + /// Controller.OnResultExecuting メソッド (Microsoft.AspNetCore.Mvc) + /// https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.aspnetcore.mvc.controller.onresultexecuting + /// </summary> + /// <param name="context"> + /// 型: Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext + /// 現在の要求およびアクション結果に関する情報。 + /// </param> + public void OnResultExecuting(ResultExecutingContext context) + { + // 結果実行(レンダリング)区間の性能測定を開始する。 + this.perfRecOfResult = new PerformanceRecorder(); + this.perfRecOfResult.StartsPerformanceRecord(); + + // ------------ + // メッセージ部 + // ------------ + // ユーザ名, IPアドレス, + // レイヤ, 画面名, コントロール名, 処理名 + // 処理時間(実行時間), 処理時間(CPU時間) + // エラーメッセージID, エラーメッセージ等 + // ------------ + string strLogMessage = + this.GetLogUserPart() + + "," + "----->" + + "," + this.ControllerName + + "," + this.ActionName + "(OnResultExecuting)"; + + LogIF.DebugLog("ACCESS", strLogMessage); + } + + /// <summary> + /// アクション メソッドによって返されたアクション結果が実行された後に呼び出されます。 + /// Controller.OnResultExecuted メソッド (Microsoft.AspNetCore.Mvc) + /// https://docs.microsoft.com/ja-jp/dotnet/api/microsoft.aspnetcore.mvc.controller.onresultexecuted + /// </summary> + /// <param name="context"> + /// 型: Microsoft.AspNetCore.Mvc.Filters.ResultExecutedContext + /// 現在の要求およびアクション結果に関する情報。 + /// </param> + public void OnResultExecuted(ResultExecutedContext context) + { + // OnResultExecuting より前にエラーが発生した場合は、 + // perfRecOfResult が null の場合があるので、null 対策コードを挿入する。 + if (this.perfRecOfResult == null) + { + // null の場合、新しいインスタンスを生成し、性能測定開始。 + this.perfRecOfResult = new PerformanceRecorder(); + this.perfRecOfResult.StartsPerformanceRecord(); + } + + this.perfRecOfResult.EndsPerformanceRecord(); + + // ------------ + // メッセージ部 + // ------------ + // ユーザ名, IPアドレス, + // レイヤ, 画面名, コントロール名, 処理名 + // 処理時間(実行時間), 処理時間(CPU時間) + // エラーメッセージID, エラーメッセージ等 + // ------------ + string strLogMessage = + this.GetLogUserPart() + + "," + "<-----" + + "," + this.ControllerName + + "," + this.ActionName + "(OnResultExecuted)" + + "," + this.perfRecOfResult.ExecTime + + "," + this.perfRecOfResult.CpuTime; + + LogIF.DebugLog("ACCESS", strLogMessage); + } + + #endregion + #region 情報取得用 /// <summary>ユーザ情報を取得する</summary> diff --git a/root/programs/CS/Frameworks/Infrastructure/Directory.Build.props b/root/programs/CS/Frameworks/Infrastructure/Directory.Build.props new file mode 100644 index 000000000..f487db1b4 --- /dev/null +++ b/root/programs/CS/Frameworks/Infrastructure/Directory.Build.props @@ -0,0 +1,50 @@ +<Project> + + <!-- + ********************************************************************************** + * ファイル名 :Directory.Build.props + * ファイル日本語名:Infrastructure 配下の共通ビルド プロパティ + * + * 作成者 :玄人 幸道 + * 更新履歴 : + * + * 日時 更新者 内容 + * 2026/07/31 玄人 幸道 新規作成(バージョン番号の一元管理) + ********************************************************************************** + + ■ 適用範囲 + 本ファイルは MSBuild が Microsoft.Common.props 経由で自動インポートするため、 + Infrastructure 配下の「SDK 形式」csproj(*_netcore100.csproj)にのみ適用される。 + 旧形式 csproj(*_net48.csproj、ToolsVersion=12.0)は Microsoft.Common.props を + インポートしないため影響を受けない。net48 のバージョンは従来どおり + 各プロジェクトの Properties\AssemblyInfo.cs が持つ。 + + ■ OpenTouryoVersion を変更したときに追随が必要な箇所 + (1) 各 *_net48.csproj の Properties\AssemblyInfo.cs の AssemblyVersion + (Public / Framework / Public.Security は 3.0.0.0。 + Business は意図的に 1.0.0.0 で別系統なので追随しない) + (2) NuGet パッケージ側は自動追随する。 + ..\..\NuGet\_NuGetPack.bat が本ファイルから値を読み取り、 + nuget pack に -Properties version=... として渡すため、 + nuspec 側は $version$ トークンのままでよい。 + + ■ 注意 + XML コメント内にハイフン 2 個の連続を書くと XML として不正になり、 + MSBuild がプロジェクトの読み込みに失敗する。区切り線に使わないこと。 + --> + + <PropertyGroup> + + <!-- ================================================================ + Open棟梁のリリース バージョン(唯一の定義箇所) + ここを書き換えれば、SDK 形式アセンブリと NuGet パッケージの + 双方に反映される。 + ================================================================ --> + <OpenTouryoVersion>3.3.0-alpha1</OpenTouryoVersion> + + <!-- 全アセンブリ共通のメタデータ --> + <Company>Hitachi Solutions</Company> + + </PropertyGroup> + +</Project> diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/Authentication/SAML2Client.cs b/root/programs/CS/Frameworks/Infrastructure/Framework/Authentication/SAML2Client.cs index f3b726f49..ceb5cd5f4 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/Authentication/SAML2Client.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/Authentication/SAML2Client.cs @@ -53,18 +53,22 @@ public class SAML2Client /// <param name="assertionConsumerService">string</param> /// <param name="relayState">string</param> /// <param name="id">out string</param> + /// <param name="hashAlgorithmName">HashAlgorithmName</param> /// <returns>queryString</returns> public static string CreateRedirectRequest( SAML2Enum.RequestOrResponse createRoR, SAML2Enum.ProtocolBinding protocolBinding, SAML2Enum.NameIDFormat nameIDFormat, - string iss, string assertionConsumerService, string relayState, out string id) - { + string iss, string assertionConsumerService, string relayState, out string id, + HashAlgorithmName? hashAlgorithmName = null) // 既定値の変更 SHA1 → SHA256 + { // DigitalSignX509 - DigitalSignX509 dsX509 = new DigitalSignX509(CmnClientParams.RsaPfxFilePath, CmnClientParams.RsaPfxPassword, HashAlgorithmName.SHA1); + HashAlgorithmName han = hashAlgorithmName ?? HashAlgorithmName.SHA256; + DigitalSignX509 dsX509 = new DigitalSignX509( + CmnClientParams.RsaPfxFilePath, CmnClientParams.RsaPfxPassword, han); // SamlRequestの生成 - + string samlRequest = SAML2Bindings.CreateRequest( iss, protocolBinding, nameIDFormat, assertionConsumerService, out id).OuterXml; @@ -119,6 +123,7 @@ public static string CreatePostRequest( /// <param name="nameIDFormat">SAML2Enum.NameIDFormat</param> /// <param name="authnContextClassRef">SAML2Enum.AuthnContextClassRef</param> /// <param name="samlResponse2">XmlDocument</param> + /// <param name="hashAlgorithmName">HashAlgorithmName</param> /// <returns>bool</returns> public static bool VerifyResponse( string queryString, string samlResponse, @@ -127,7 +132,8 @@ public static bool VerifyResponse( out SAML2Enum.StatusCode? statusCode, out SAML2Enum.NameIDFormat? nameIDFormat, out SAML2Enum.AuthnContextClassRef? authnContextClassRef, - out XmlDocument samlResponse2) + out XmlDocument samlResponse2, + HashAlgorithmName? hashAlgorithmName = null) // 既定値の変更 SHA1 → SHA256 { bool verified = false; @@ -177,7 +183,8 @@ public static bool VerifyResponse( #region 検証 // Metadata利用を検討 - DigitalSignX509 dsX509 = new DigitalSignX509(CmnClientParams.RsaCerFilePath, "", HashAlgorithmName.SHA1); + HashAlgorithmName han = hashAlgorithmName ?? HashAlgorithmName.SHA256; + DigitalSignX509 dsX509 = new DigitalSignX509(CmnClientParams.RsaCerFilePath, "", han); if (!string.IsNullOrEmpty(queryString)) { diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/Framework_net48.csproj b/root/programs/CS/Frameworks/Infrastructure/Framework/Framework_net48.csproj index ebe201930..440940f8c 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/Framework_net48.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/Framework_net48.csproj @@ -41,7 +41,13 @@ <BootstrapperEnabled>true</BootstrapperEnabled> <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> <RestorePackages>true</RestorePackages> - </PropertyGroup> + <!--Source Link(#531) + .NET 8 以降の SDK は Source Link を自動で組み込むが、**旧形式 csproj には効かない** + (Microsoft.Common.props を通らないため)。net48 側は明示的に入れる。 + これが無いと、利用者は lib\net48 を参照したときにソースへ踏み込めない。--> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> +</PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> @@ -189,4 +195,13 @@ <PostBuildEvent> </PostBuildEvent> </PropertyGroup> + <ItemGroup> + <!--Source Link(#531)。**ビルド時にだけ使う**ので PrivateAssets=all にし、 + NuGet パッケージの依存関係には出さない。--> + <PackageReference Include="Microsoft.SourceLink.GitHub"> + <Version>10.0.301</Version> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + </ItemGroup> </Project> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/Framework_netcore100.csproj b/root/programs/CS/Frameworks/Infrastructure/Framework/Framework_netcore100.csproj index 97834fbad..27bd63b45 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/Framework_netcore100.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/Framework_netcore100.csproj @@ -4,8 +4,7 @@ <TargetFramework>net10.0</TargetFramework> <RootNamespace>Touryo.Infrastructure.Framework</RootNamespace> <AssemblyName>OpenTouryo.Framework</AssemblyName> - <Version>3.0.0.0</Version> - <Company>Hitachi Solutions</Company> + <Version>$(OpenTouryoVersion)</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/Properties/AssemblyInfo.cs b/root/programs/CS/Frameworks/Infrastructure/Framework/Properties/AssemblyInfo.cs index d58ba6c76..424827906 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/Properties/AssemblyInfo.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/Properties/AssemblyInfo.cs @@ -62,4 +62,4 @@ // // すべての値を指定するか、下のように '*' を使ってリビジョンおよびビルド番号を // 既定値にすることができます: -[assembly: AssemblyVersion("3.0.0.0")] +[assembly: AssemblyVersion("3.3.0.0")] diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Framework.RichClient_net48.csproj b/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Framework.RichClient_net48.csproj index b3ac52283..39a2c44f8 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Framework.RichClient_net48.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Framework.RichClient_net48.csproj @@ -40,7 +40,13 @@ <IsWebBootstrapper>false</IsWebBootstrapper> <UseApplicationTrust>false</UseApplicationTrust> <BootstrapperEnabled>true</BootstrapperEnabled> - </PropertyGroup> + <!--Source Link(#531) + .NET 8 以降の SDK は Source Link を自動で組み込むが、**旧形式 csproj には効かない** + (Microsoft.Common.props を通らないため)。net48 側は明示的に入れる。 + これが無いと、利用者は lib\net48 を参照したときにソースへ踏み込めない。--> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> +</PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> @@ -120,4 +126,13 @@ <PostBuildEvent> </PostBuildEvent> </PropertyGroup> + <ItemGroup> + <!--Source Link(#531)。**ビルド時にだけ使う**ので PrivateAssets=all にし、 + NuGet パッケージの依存関係には出さない。--> + <PackageReference Include="Microsoft.SourceLink.GitHub"> + <Version>10.0.301</Version> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + </ItemGroup> </Project> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Framework.RichClient_netcore100.csproj b/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Framework.RichClient_netcore100.csproj index 727448c34..7631e77f3 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Framework.RichClient_netcore100.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Framework.RichClient_netcore100.csproj @@ -9,7 +9,7 @@ <StartupObject /> <RootNamespace>Touryo.Infrastructure.Framework.RichClient</RootNamespace> <AssemblyName>OpenTouryo.Framework.RichClient</AssemblyName> - <Version>3.0.0.0</Version> + <Version>$(OpenTouryoVersion)</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Properties/AssemblyInfo.cs b/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Properties/AssemblyInfo.cs index 010376904..a553c88ee 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Properties/AssemblyInfo.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient/Properties/AssemblyInfo.cs @@ -63,4 +63,4 @@ // すべての値を指定するか、下のように '*' を使ってビルドおよびリビジョン番号を // 既定値にすることができます: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.0.0.0")] +[assembly: AssemblyVersion("3.3.0.0")] diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/Util/FxCmnFunction.cs b/root/programs/CS/Frameworks/Infrastructure/Framework/Util/FxCmnFunction.cs index 1dac15ae6..c309f44f5 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/Util/FxCmnFunction.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/Util/FxCmnFunction.cs @@ -55,6 +55,7 @@ //* 2018/01/31 西野 大介 ネストしたユーザ コントロールに対応(senderで親UCを確認する) //* 2018/03/29 西野 大介 .NET Standard対応で、削除機能に関連するメソッドを削除 //* 2018/03/29 西野 大介 .NET Standard対応で、HttpCookieのポーティング +//* 2026/08/10 玄人 幸道 Cookie に Secure 属性を設定(HTTPS のときのみ。CodeQL 対応) //********************************************************************************** using Touryo.Infrastructure.Framework.Exceptions; @@ -964,6 +965,11 @@ public static void CreateCookieForSessionTimeoutDetection() // HttpOnly属性を設定 cookieOptions.HttpOnly = true; + // Secure属性を設定(CodeQL: Cookie 'Secure' attribute is not set to true) + // HTTPSのときだけ立てる。無条件にtrueにすると、HTTPで動かす + // 開発環境やサンプルでブラウザがCookieを保存しなくなるため。 + cookieOptions.Secure = MyHttpContext.Current.Request.IsHttps; + // 設定 responseCookies.Set( FxHttpCookieIndex.SESSION_TIMEOUT, @@ -998,6 +1004,11 @@ public static void DeleteCookieForSessionTimeoutDetection() // HttpOnly属性を設定 cookieOptions.HttpOnly = true; + // Secure属性を設定(CodeQL: Cookie 'Secure' attribute is not set to true) + // HTTPSのときだけ立てる。無条件にtrueにすると、HTTPで動かす + // 開発環境やサンプルでブラウザがCookieを保存しなくなるため。 + cookieOptions.Secure = MyHttpContext.Current.Request.IsHttps; + // 設定 responseCookies.Set(FxHttpCookieIndex.SESSION_TIMEOUT, "", cookieOptions); } @@ -1032,6 +1043,11 @@ HttpCookie newCookie // HttpOnly属性を設定 newCookie.HttpOnly = true; + // Secure属性を設定(CodeQL: Cookie 'Secure' attribute is not set to true) + // HTTPSのときだけ立てる。無条件にtrueにすると、HTTPで動かす + // 開発環境やサンプルでブラウザがCookieを保存しなくなるため。 + newCookie.Secure = HttpContext.Current.Request.IsSecureConnection; + // セッションタイムアウト検出用Cookie(データ有) return newCookie; } @@ -1066,6 +1082,11 @@ HttpCookie newCookie // HttpOnly属性を設定 newCookie.HttpOnly = true; + // Secure属性を設定(CodeQL: Cookie 'Secure' attribute is not set to true) + // HTTPSのときだけ立てる。無条件にtrueにすると、HTTPで動かす + // 開発環境やサンプルでブラウザがCookieを保存しなくなるため。 + newCookie.Secure = HttpContext.Current.Request.IsSecureConnection; + // セッションタイムアウト検出用Cookie(データ空) return newCookie; } diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/Util/GetMessage.cs b/root/programs/CS/Frameworks/Infrastructure/Framework/Util/GetMessage.cs index 008b0971c..5c5e2a11f 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/Util/GetMessage.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/Util/GetMessage.cs @@ -40,6 +40,8 @@ //* 2014/02/07 Rituparna Biswas Changes Made In GetMessageDescription for Internationalization //* 2014/02/19 西野 大介 取り込み(細かな修正) //* 2017/08/11 西野 大介 2014年のInternationalizationのrefactoringを実施 +//* 2026/08/01 玄人 幸道 定義ファイルの探索を ResourceLoader.ResolveFilePath に統一した。 +//* ※ 存在チェックと読み込みで同じ実パスを使うようにした。 //********************************************************************************** @@ -257,20 +259,30 @@ private static bool LoadFromFile(string filePath) return true; } - else if (ResourceLoader.Exists(filePath, false)) - { - XmlDocument xMLMSG = new XmlDocument(); - - // Load - xMLMSG.Load(StringVariableOperator.BuiltStringIntoEnvironmentVariable(filePath)); - // Save - GetMessage.DicMSG[filePath] = GetMessage.FillDictionary(xMLMSG); - - return true; - } else { - return false; + // ↓↓↓【変更】↓↓↓ + // リソース ローダで実パスを解決する。 + // ※ 以前は Exists で存在チェックした後、生のパスで開いていたため、 + // ResolveFilePath の探索結果(EXEの配置フォルダ基準)を活かせなかった。 + string msgFilePath = ResourceLoader.ResolveFilePath(filePath); + + if (msgFilePath != null) + { + XmlDocument xMLMSG = new XmlDocument(); + + // Load + xMLMSG.Load(msgFilePath); + // Save(キーは解決前のパス=設定値のまま) + GetMessage.DicMSG[filePath] = GetMessage.FillDictionary(xMLMSG); + + return true; + } + else + { + return false; + } + // ↑↑↑【変更】↑↑↑ } } diff --git a/root/programs/CS/Frameworks/Infrastructure/Framework/Util/GetSharedProperty.cs b/root/programs/CS/Frameworks/Infrastructure/Framework/Util/GetSharedProperty.cs index 817bc715f..8922ebaf1 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Framework/Util/GetSharedProperty.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Framework/Util/GetSharedProperty.cs @@ -1,4 +1,4 @@ -//********************************************************************************** +//********************************************************************************** //* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. //********************************************************************************** @@ -32,6 +32,8 @@ //* 2010/09/24 西野 大介 ジェネリック対応(XMLのDictionary化) //* nullチェック方法、Contains → ContainsKeyなどに注意 //* 2011/01/19 西野 大介 環境変数の組み込み処理に対応 +//* 2026/08/01 玄人 幸道 定義ファイルの探索を ResourceLoader.ResolveFilePath に統一した。 +//* ※ 存在チェックと読み込みで同じ実パスを使うようにした。 //********************************************************************************** using System; @@ -125,13 +127,17 @@ public SharedPropertyManager() #region リソース ローダでチェック(ここで落とすとハンドルされないので落とさない。) - if (ResourceLoader.Exists( - GetConfigParameter.GetConfigValue(FxLiteral.XML_SP_DEFINITION), false)) + // ↓↓↓【変更】↓↓↓ + // リソース ローダで実パスを解決する。 + // ※ 以前は Exists で存在チェックした後、生のパスで開いていたため、 + // ResolveFilePath の探索結果(EXEの配置フォルダ基準)を活かせなかった。 + string xmlSPFilePath = ResourceLoader.ResolveFilePath( + GetConfigParameter.GetConfigValue(FxLiteral.XML_SP_DEFINITION)); + + if (xmlSPFilePath != null) { // 共有情報定義(XmlDocument)を[リソース]で初期化 - xMLSP.Load( - StringVariableOperator.BuiltStringIntoEnvironmentVariable( - GetConfigParameter.GetConfigValue(FxLiteral.XML_SP_DEFINITION))); + xMLSP.Load(xmlSPFilePath); //// 戻す //return; @@ -140,6 +146,7 @@ public SharedPropertyManager() { // 何もしない。 } + // ↑↑↑【変更】↑↑↑ #endregion } diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/DamManagedOdp_net48.csproj b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/DamManagedOdp_net48.csproj index 274392233..4375a4ccb 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/DamManagedOdp_net48.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/DamManagedOdp_net48.csproj @@ -41,7 +41,13 @@ <BootstrapperEnabled>true</BootstrapperEnabled> <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> <RestorePackages>true</RestorePackages> - </PropertyGroup> + <!--Source Link(#531) + .NET 8 以降の SDK は Source Link を自動で組み込むが、**旧形式 csproj には効かない** + (Microsoft.Common.props を通らないため)。net48 側は明示的に入れる。 + これが無いと、利用者は lib\net48 を参照したときにソースへ踏み込めない。--> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> +</PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> @@ -92,4 +98,13 @@ <Target Name="AfterBuild"> </Target> --> + <ItemGroup> + <!--Source Link(#531)。**ビルド時にだけ使う**ので PrivateAssets=all にし、 + NuGet パッケージの依存関係には出さない。--> + <PackageReference Include="Microsoft.SourceLink.GitHub"> + <Version>10.0.301</Version> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + </ItemGroup> </Project> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/DamManagedOdp_netcore100.csproj b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/DamManagedOdp_netcore100.csproj index 0b0636512..d8eb8ebdd 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/DamManagedOdp_netcore100.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/DamManagedOdp_netcore100.csproj @@ -3,8 +3,7 @@ <TargetFramework>net10.0</TargetFramework> <AssemblyName>OpenTouryo.DamManagedOdp</AssemblyName> <RootNamespace>Touryo.Infrastructure.Public.Db</RootNamespace> - <Version>3.0.0.0</Version> - <Company>Hitachi Solutions</Company> + <Version>$(OpenTouryoVersion)</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/Properties/AssemblyInfo.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/Properties/AssemblyInfo.cs index 90adb995a..b0f01eb0b 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/Properties/AssemblyInfo.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp/Properties/AssemblyInfo.cs @@ -62,4 +62,4 @@ // // すべての値を指定するか、下のように '*' を使ってリビジョンおよびビルド番号を // 既定値にすることができます: -[assembly: AssemblyVersion("3.0.0.0")] +[assembly: AssemblyVersion("3.3.0.0")] diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/DamMySQL_net48.csproj b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/DamMySQL_net48.csproj index d53ea67bb..437549f1a 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/DamMySQL_net48.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/DamMySQL_net48.csproj @@ -41,7 +41,13 @@ <BootstrapperEnabled>true</BootstrapperEnabled> <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir> <RestorePackages>true</RestorePackages> - </PropertyGroup> + <!--Source Link(#531) + .NET 8 以降の SDK は Source Link を自動で組み込むが、**旧形式 csproj には効かない** + (Microsoft.Common.props を通らないため)。net48 側は明示的に入れる。 + これが無いと、利用者は lib\net48 を参照したときにソースへ踏み込めない。--> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> +</PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> @@ -107,4 +113,13 @@ <Target Name="AfterBuild"> </Target> --> + <ItemGroup> + <!--Source Link(#531)。**ビルド時にだけ使う**ので PrivateAssets=all にし、 + NuGet パッケージの依存関係には出さない。--> + <PackageReference Include="Microsoft.SourceLink.GitHub"> + <Version>10.0.301</Version> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + </ItemGroup> </Project> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/DamMySQL_netcore100.csproj b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/DamMySQL_netcore100.csproj index 30379dd39..ee81073ee 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/DamMySQL_netcore100.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/DamMySQL_netcore100.csproj @@ -3,8 +3,7 @@ <TargetFramework>net10.0</TargetFramework> <AssemblyName>OpenTouryo.DamMySQL</AssemblyName> <RootNamespace>Touryo.Infrastructure.Public.Db</RootNamespace> - <Version>3.0.0.0</Version> - <Company>Hitachi Solutions</Company> + <Version>$(OpenTouryoVersion)</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/Properties/AssemblyInfo.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/Properties/AssemblyInfo.cs index 406e470f4..9753a0ed0 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/Properties/AssemblyInfo.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL/Properties/AssemblyInfo.cs @@ -62,4 +62,4 @@ // // すべての値を指定するか、下のように '*' を使ってリビジョンおよびビルド番号を // 既定値にすることができます: -[assembly: AssemblyVersion("3.0.0.0")] \ No newline at end of file +[assembly: AssemblyVersion("3.3.0.0")] \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamPstGrS/DamPstGrS_netcore100.csproj b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamPstGrS/DamPstGrS_netcore100.csproj index fbb9b1028..f644bd0d6 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamPstGrS/DamPstGrS_netcore100.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamPstGrS/DamPstGrS_netcore100.csproj @@ -3,8 +3,7 @@ <TargetFramework>net10.0</TargetFramework> <AssemblyName>OpenTouryo.DamPstGrS</AssemblyName> <RootNamespace>Touryo.Infrastructure.Public.Db</RootNamespace> - <Version>3.0.0.0</Version> - <Company>Hitachi Solutions</Company> + <Version>$(OpenTouryoVersion)</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Db/SQLUtility.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Db/SQLUtility.cs index 9eff8bfec..b4199995c 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Db/SQLUtility.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Db/SQLUtility.cs @@ -35,6 +35,7 @@ //* 2014/01/30 Sai Krishna added code for batch processing supporting MySQL //* 2014/01/30 Santoshkumar added code for batch processing supporting DB2 //* 2014/03/04 Santoshkumar Modified code for converting char data type for batch processing supporting DB2 and Oracle +//* 2026/08/02 玄人 幸道 GetUpdateSQLParts:複合主キーで誤ったUPDATE文を生成する問題を修正 //********************************************************************************** using System; @@ -373,50 +374,100 @@ public string[] GetUpdateSQLParts(DataTable dt, string[] primaryKeys) } } - // As per the PostGreSQL and MySQL syntax for batch update - // we have to use a "CASE ... WHEN ... THEN" while updating multiple records. + // 生成できないケースは、ここで打ち切る(DBMSによらず共通)。 + // + // ・更新対象列が無い … SET句が空のSQLは構文エラーになる。 + // ・主キーが無い … 行を特定できず、WHERE句が無いと全行更新になる。 + // + // 打ち切らずに進むと、末尾の切り詰め処理が初期値のStringBuilderを削るため、 + // "SE" や "WH" といった壊れた文字列を返してしまう。 + if (colSet.Count == 0 || colWhere.Count == 0) + { + return list.ToArray(); + } + + // PostgreSQL・MySQLには、1文で複数行を別々の値に更新する構文が無いため、 + // 「CASE ... WHEN ... THEN」で行ごとの値を切り替える。 + // 他のDBMS(else側)は1行1文を行数分returnするが、こちらは1文にまとめる。 + // + // <生成される UPDATE 文の全体像> + // + // 本メソッドが返すのは "SET ... WHERE ..." の部分のみで、 + // 呼び出し側が "UPDATE <テーブル名>" を前置して1文を組み立てる。 + // + // UPDATE "Orders" ← 呼び出し側が付与 + // SET "Qty" = CASE + // WHEN "OrderID" = 1 AND "ProductID" = 10 THEN 100 + // WHEN "OrderID" = 2 AND "ProductID" = 20 THEN 200 + // ELSE "Qty" ← 対象外の行は現状維持 + // END, + // "Note" = CASE + // WHEN "OrderID" = 1 AND "ProductID" = 10 THEN 'a' + // WHEN "OrderID" = 2 AND "ProductID" = 20 THEN 'b' + // ELSE "Note" + // END + // WHERE ("OrderID" = 1 AND "ProductID" = 10) ← 主キーの組み合わせで絞る + // OR ("OrderID" = 2 AND "ProductID" = 20) + // + // <構造> + // ・更新対象列(主キー以外)ごとに CASE 式を1つ作る。 + // ・CASE の WHEN は入力DataTableの行数分並び、行を主キーで特定して値を与える。 + // ・WHERE は同じ主キーの組み合わせをORで並べ、更新対象の行だけに限定する。 + // + // <複合主キーの扱い> + // 主キーが複数列ある場合、WHEN も WHERE も「列ごとに独立」ではなく + // 「組み合わせ(AND)」で判定しなければならない。 + // 列ごとに独立させると、WHERE が直積になって更新対象でない行に一致し、 + // さらに CASE も先に一致した枝が勝つため、誤った行に誤った値が入る。 + // + // <ELSE を付ける理由> + // CASE はどの WHEN にも一致しないと NULL を返す。 + // WHERE で対象行に限定しているため通常は一致するが、 + // NULL 上書きという最悪の失敗を避けるため、保険として自身の列を指定する。 if (this._dbms == DbEnum.DBMSType.PstGrS || this._dbms == DbEnum.DBMSType.MySQL) { sbSet = new StringBuilder("SET "); sbWhere = new StringBuilder("\r\nWHERE "); - int count = 0; - // 更新対象列 + // 更新対象列(主キー以外)ごとに CASE 式を作る。 + bool isFirstSet = true; foreach (string set in colSet) { - sbSet.Append(set + " = CASE"); + if (!isFirstSet) + { + sbSet.Append(",\r\n "); + } + isFirstSet = false; - foreach (string where in colWhere) + sbSet.Append(this.OpeningBracket + set + this.ClosingBracket + " = CASE"); + + // 行ごとに「主キーの組み合わせ = その行の値」を条件とする。 + foreach (DataRow dr in dt.Rows) { - if (count < colWhere.Count) - sbWhere.Append(where + " IN ("); - foreach (DataRow dr in dt.Rows) - { - sbSet.Append( - " WHEN " + where + " =" + this.ConvertParameterToSQL(dr[where]) - + " THEN " + this.ConvertParameterToSQL(dr[set]) + "\r\n"); + sbSet.Append("\r\n WHEN " + this.GetPrimaryKeyCondition(dr, colWhere) + + " THEN " + this.ConvertParameterToSQL(dr[set])); + } - // パラメタをSQLに変換する。 - if (count < colWhere.Count) - sbWhere.Append(this.ConvertParameterToSQL(dr[where]) + ", "); - } - // Sharpen last comma and AND - if (count < colWhere.Count) - { - sbWhere.Remove((sbWhere.Length - 2), 2); - sbWhere.Append(") AND "); - } - count++; + // どのWHENにも一致しない行は、現在の値を保つ。 + sbSet.Append("\r\n ELSE " + this.OpeningBracket + set + this.ClosingBracket); + sbSet.Append("\r\n END"); + } + + // WHERE は主キーの組み合わせをORで並べ、更新対象の行だけに限定する。 + bool isFirstWhere = true; + foreach (DataRow dr in dt.Rows) + { + if (!isFirstWhere) + { + sbWhere.Append("\r\n OR "); } - // Adding END to the CASE - sbSet.Append(" END,\r\n"); + isFirstWhere = false; + + sbWhere.Append("(" + this.GetPrimaryKeyCondition(dr, colWhere) + ")"); } - // Removing Last AND. - tempWhere = sbWhere.ToString().Substring(0, sbWhere.Length - 4); tempSet = sbSet.ToString(); - // Removing Last END. - tempSet = tempSet.Substring(0, tempSet.Length - 3); + tempWhere = sbWhere.ToString(); // 結合して追加。 list.Add(tempSet + " " + tempWhere); @@ -464,6 +515,34 @@ public string[] GetUpdateSQLParts(DataTable dt, string[] primaryKeys) return list.ToArray(); } + /// <summary>1行を特定する主キーの条件式を生成する。</summary> + /// <param name="dr">対象行</param> + /// <param name="primaryKeys">主キー列名のリスト</param> + /// <returns>条件式(例: "OrderID" = 1 AND "ProductID" = 10 )</returns> + /// <remarks> + /// 複合主キーの場合は、列ごとに独立させず AND で結合する。 + /// 独立させると行を一意に特定できず、意図しない行に一致する。 + /// </remarks> + private string GetPrimaryKeyCondition(DataRow dr, List<string> primaryKeys) + { + StringBuilder sb = new StringBuilder(); + + bool isFirst = true; + foreach (string pk in primaryKeys) + { + if (!isFirst) + { + sb.Append(" AND "); + } + isFirst = false; + + sb.Append(this.OpeningBracket + pk + this.ClosingBracket + + " = " + this.ConvertParameterToSQL(dr[pk])); + } + + return sb.ToString(); + } + /// <summary>パラメタをSQLに変換する。</summary> /// <param name="obj">パラメタ</param> /// <returns>SQL化したパラメタ</returns> diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Dto/DataToDictionary.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Dto/DataToDictionary.cs index 8d1809e58..1ea7e6feb 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Dto/DataToDictionary.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Dto/DataToDictionary.cs @@ -30,6 +30,7 @@ //* 2018/07/23 西野 大介 新規作成 //* 2018/10/03 西野 大介 性能対策 //* 2018/10/23 西野 大介 微調整 +//* 2026/08/06 玄人 幸道 コンストラクタの引数の取り違えを修正(#522) //********************************************************************************** using System; @@ -62,8 +63,13 @@ public DataToDictionary() { } public DataToDictionary(Dictionary<string, string> mapping, string dateTimeFormat, string timeSpanFormat) { this.Mapping = mapping; - this.DateTimeFormat = timeSpanFormat; - this.TimeSpanFormat = dateTimeFormat; + + // 2026/08/06 まで、この 2 行は代入先が入れ替わっていた(#522)。 + // dateTimeFormat が TimeSpanFormat に入るため DateTimeFormat が空のままになり、 + // **日時が書式ではなく Ticks で出力される**(DataTableToDictionary の分岐)。 + // 例外にならず値の形だけが変わるため、気付きにくい。 + this.DateTimeFormat = dateTimeFormat; + this.TimeSpanFormat = timeSpanFormat; } #region DataTable diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ResourceLoader.cs b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ResourceLoader.cs index 54c9830ab..8bc9b932c 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ResourceLoader.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ResourceLoader.cs @@ -30,6 +30,10 @@ //* 2007/xx/xx 西野 大介 新規作成 //* 2009/03/13 西野 大介 存在チェック処理メソッドを追加 //* 2011/01/14 西野 大介 環境変数の組み込み処理に対応 +//* 2026/08/01 玄人 幸道 ResolveFilePathメソッドを追加し、探索処理を集約した。 +//* 相対パスがカレント ディレクトリ基準で見つからない場合、 +//* AppContext.BaseDirectory(EXEの配置フォルダ)基準で再探索する。 +//* ※ CLIが任意のカレント ディレクトリから起動される問題への対応。 //********************************************************************************** using System; @@ -46,6 +50,59 @@ namespace Touryo.Infrastructure.Public.IO /// <remarks>自由に利用できる。</remarks> public static class ResourceLoader { + // ↓↓↓【追加】↓↓↓ + + #region パス解決 + + /// <summary>[リソース ファイル]の実パスを解決する</summary> + /// <param name="loadfilepath">[リソース ファイル]へのパス</param> + /// <returns>見つかった実パス。見つからない場合は null。</returns> + /// <remarks> + /// 自由に利用できる。 + /// 探索順は下記のとおり。 + /// (1) 指定されたパス(絶対パス、または カレント ディレクトリ基準の相対パス) + /// (2) AppContext.BaseDirectory(EXEの配置フォルダ)基準の相対パス + /// (1) を優先するため、従来動作していた構成の挙動は変わらない。 + /// (2) は、CLIが任意のカレント ディレクトリから起動される場合への対応。 + /// ※ AppContext.BaseDirectoryは、PublishSingleFile(単一ファイル発行)でも + /// 正しい値を返す(Assembly.Locationは空文字になるため使用しない)。 + /// </remarks> + public static string ResolveFilePath(string loadfilepath) + { + // 環境変数の組み込み処理に対応 + loadfilepath = StringVariableOperator.BuiltStringIntoEnvironmentVariable(loadfilepath); + + if (string.IsNullOrEmpty(loadfilepath)) + { + // 指定なし + return null; + } + + // (1) 指定されたパスで探す。 + if (File.Exists(loadfilepath)) + { + return loadfilepath; + } + + // (2) 見つからない場合、EXEの配置フォルダ基準で探す(相対パスの場合のみ)。 + if (!Path.IsPathRooted(loadfilepath)) + { + string loadfilepath2 = Path.Combine(AppContext.BaseDirectory, loadfilepath); + + if (File.Exists(loadfilepath2)) + { + return loadfilepath2; + } + } + + // 見つからない。 + return null; + } + + #endregion + + // ↑↑↑【追加】↑↑↑ + #region 存在チェック /// <summary>存在チェックのみのメソッド</summary> @@ -55,11 +112,8 @@ public static class ResourceLoader /// <remarks>自由に利用できる。</remarks> public static bool Exists(string loadfilepath, bool throwException) { - // 環境変数の組み込み処理に対応 - loadfilepath = StringVariableOperator.BuiltStringIntoEnvironmentVariable(loadfilepath); - - // 存在チェック - if (File.Exists(loadfilepath)) + // 存在チェック(【変更】探索処理を ResolveFilePath に集約した) + if (ResourceLoader.ResolveFilePath(loadfilepath) != null) { // 存在する。 return true; @@ -90,28 +144,8 @@ public static bool Exists(string filePath, string fileName, bool throwException) // パス文字結合 string loadfilepath = Path.Combine(filePath, fileName); - // 環境変数の組み込み処理に対応 - loadfilepath = StringVariableOperator.BuiltStringIntoEnvironmentVariable(loadfilepath); - - // 存在チェック - if (File.Exists(loadfilepath)) - { - // 存在する。 - return true; - } - else - { - // 存在しない。 - if (throwException) - { - throw new ArgumentException(String.Format( - PublicExceptionMessage.RESOURCE_FILE_NOT_FOUND, loadfilepath)); - } - else - { - return false; - } - } + // 存在チェック(【変更】探索処理を ResolveFilePath に集約した) + return ResourceLoader.Exists(loadfilepath, throwException); } #endregion @@ -125,15 +159,15 @@ public static bool Exists(string filePath, string fileName, bool throwException) /// <remarks>自由に利用できる。</remarks> public static string LoadAsString(string loadfilepath, Encoding enc) { - // 環境変数の組み込み処理に対応 - loadfilepath = StringVariableOperator.BuiltStringIntoEnvironmentVariable(loadfilepath); + // 存在チェック(【変更】探索処理を ResolveFilePath に集約した) + string resolvedPath = ResourceLoader.ResolveFilePath(loadfilepath); StreamReader sr = null; try { // 存在チェック - if (File.Exists(loadfilepath)) + if (resolvedPath != null) { // 存在する。 } @@ -145,7 +179,7 @@ public static string LoadAsString(string loadfilepath, Encoding enc) } // 開く - sr = new StreamReader(loadfilepath, enc); + sr = new StreamReader(resolvedPath, enc); // 読む return sr.ReadToEnd(); @@ -176,15 +210,15 @@ public static string LoadAsString(string filePath, string fileName, Encoding enc // パス文字結合 string loadfilepath = Path.Combine(filePath, fileName); - // 環境変数の組み込み処理に対応 - loadfilepath = StringVariableOperator.BuiltStringIntoEnvironmentVariable(loadfilepath); + // 存在チェック(【変更】探索処理を ResolveFilePath に集約した) + string resolvedPath = ResourceLoader.ResolveFilePath(loadfilepath); StreamReader sr = null; try { // 存在チェック - if (File.Exists(loadfilepath)) + if (resolvedPath != null) { // 存在する。 } @@ -196,7 +230,7 @@ public static string LoadAsString(string filePath, string fileName, Encoding enc } // 開く - sr = new StreamReader(loadfilepath, enc); + sr = new StreamReader(resolvedPath, enc); // 読む return sr.ReadToEnd(); diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/IO/UnZipperV2.cs b/root/programs/CS/Frameworks/Infrastructure/Public/IO/UnZipperV2.cs new file mode 100644 index 000000000..53ff5f978 --- /dev/null +++ b/root/programs/CS/Frameworks/Infrastructure/Public/IO/UnZipperV2.cs @@ -0,0 +1,297 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :UnZipperV2 +//* クラス日本語名 :SharpZipLibを使用した解凍クラス +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/08 玄人 幸道 新規作成(#524) +//********************************************************************************** + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using ICSharpCode.SharpZipLib.Zip; + +namespace Touryo.Infrastructure.Public.IO +{ + /// <summary>SharpZipLibを使用した解凍クラス</summary> + /// <remarks> + /// 旧 UnZipper(DotNetZip)の代替(#524)。 + /// **引数の並びと名前は旧に合わせてある。** 型だけが自前の列挙型に変わる。 + /// + /// **StatusMSG は無い。** 旧の呼び出し元(DeployZipPackWithHTTP)は + /// StatusMSG のログ文言("extract file ...")を解析して解凍先の一覧を得ていたが、 + /// DotNetZip 固有の文字列であり再現できない。 + /// **ExtractedFiles で受け取ること。** + /// </remarks> + public class UnZipperV2 : ZipBaseV2 + { + #region ExtractedFiles + + /// <summary>解凍したファイルのパス</summary> + private List<string> _extractedFiles = new List<string>(); + + /// <summary>解凍したファイルのパス</summary> + /// <remarks> + /// 旧 StatusMSG の解析で得ていたものの代替。 + /// **ExtractFileFromZip のたびに作り直す**(前回の内容は残らない)。 + /// 上書きせず飛ばしたファイルは含まない。 + /// </remarks> + public string[] ExtractedFiles + { + get { return this._extractedFiles.ToArray(); } + } + + #endregion + + #region ExtractFileFromZip + + /// <summary>ZIPファイルを解凍</summary> + /// <param name="zipFileName">ZIPファイル名</param> + /// <param name="directoryToUnZip">解凍先</param> + /// <param name="selectionDlgt">ファイル選択デリゲード</param> + /// <param name="selectionCriteriaInfo">ファイル選択基準情報</param> + /// <param name="extractExistingFile">上書き時の動作</param> + /// <param name="enc">エンコーディング</param> + /// <param name="zipPassword">パスワード</param> + public void ExtractFileFromZip( + string zipFileName, + string directoryToUnZip, + SelectionDelegate selectionDlgt, + object selectionCriteriaInfo, + ExtractExistingFileActionV2 extractExistingFile, + Encoding enc, + string zipPassword) + { + // ファイル選択基準 + base.SetSelectionCriteria(selectionDlgt, selectionCriteriaInfo); + + this._extractedFiles = new List<string>(); + + using (FileStream fs = File.OpenRead(zipFileName)) + using (ZipFile zip = new ZipFile(fs, false, base.GetStringCodec(enc))) + { + if (!string.IsNullOrEmpty(zipPassword)) { zip.Password = zipPassword; } + + ZipProgressEventArgsV2 e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Extracting_Started, zipFileName); + e.EntriesTotal = (int)zip.Count; + base.OnExtractProgress(e); + + int processed = 0; + + foreach (ZipEntry entry in zip) + { + // ディレクトリのエントリは、ファイルの展開時に必要に応じて作る。 + if (!entry.IsFile) { continue; } + + // 解凍対象ファイルを選択(ファイル選択デリゲードを使用) + if (base.SelectionDlgt(entry.Name, base.SelectionCriteriaInfo)) + { + if (!this.ExtractEntry(zip, entry, zipFileName, directoryToUnZip, + extractExistingFile, (int)zip.Count, processed)) + { + // ハンドラが Cancel を立てたので、以降を処理しない。 + break; + } + } + + processed++; + } + + e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Extracting_Completed, zipFileName); + e.EntriesTotal = (int)zip.Count; + e.EntriesProcessed = processed; + base.OnExtractProgress(e); + } + } + + #endregion + + #region private + + /// <summary>1エントリを解凍する</summary> + /// <param name="zip">ZipFile</param> + /// <param name="entry">ZipEntry</param> + /// <param name="zipFileName">書庫のファイル名</param> + /// <param name="directoryToUnZip">解凍先</param> + /// <param name="extractExistingFile">上書き時の動作</param> + /// <param name="entriesTotal">エントリの総数</param> + /// <param name="entriesProcessed">処理済みのエントリ数</param> + /// <returns>処理を続けるならtrue(ハンドラがCancelを立てたらfalse)</returns> + private bool ExtractEntry( + ZipFile zip, + ZipEntry entry, + string zipFileName, + string directoryToUnZip, + ExtractExistingFileActionV2 extractExistingFile, + int entriesTotal, + int entriesProcessed) + { + string path = UnZipperV2.GetSafePath(directoryToUnZip, entry.Name); + + #region 既存ファイルの扱い + + if (File.Exists(path)) + { + ExtractExistingFileActionV2 action = extractExistingFile; + + if (action == ExtractExistingFileActionV2.InvokeExtractProgressEvent) + { + // ハンドラに問い合わせる。 + ZipProgressEventArgsV2 ask = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Extracting_ExtractEntryWouldOverwrite, zipFileName); + ask.EntriesTotal = entriesTotal; + ask.EntriesProcessed = entriesProcessed; + ask.CurrentEntryName = entry.Name; + ask.ExtractLocation = directoryToUnZip; + ask.IsQuery = true; + + // 既定は「上書きしない」。ハンドラが何もしなければ安全側に倒れる。 + ask.ExtractExistingFile = ExtractExistingFileActionV2.DoNotOverwrite; + + base.OnExtractProgress(ask); + + if (ask.Cancel) { return false; } + + action = ask.ExtractExistingFile; + + // 問い合わせを返されても、また問い合わせない(無限になるため)。 + if (action == ExtractExistingFileActionV2.InvokeExtractProgressEvent) + { + action = ExtractExistingFileActionV2.DoNotOverwrite; + } + } + + if (action == ExtractExistingFileActionV2.Throw) + { + throw new IOException(path); + } + else if (action == ExtractExistingFileActionV2.DoNotOverwrite) + { + ZipProgressEventArgsV2 skip = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Extracting_ExtractEntryWouldOverwrite, zipFileName); + skip.EntriesTotal = entriesTotal; + skip.EntriesProcessed = entriesProcessed; + skip.CurrentEntryName = entry.Name; + skip.ExtractLocation = directoryToUnZip; + skip.IsQuery = false; + base.OnExtractProgress(skip); + + return true; + } + } + + #endregion + + string dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + { + Directory.CreateDirectory(dir); + } + + ZipProgressEventArgsV2 e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Extracting_BeforeExtractEntry, zipFileName); + e.EntriesTotal = entriesTotal; + e.EntriesProcessed = entriesProcessed; + e.CurrentEntryName = entry.Name; + e.TotalBytesToTransfer = entry.Size; + base.OnExtractProgress(e); + + byte[] buffer = new byte[81920]; + long transferred = 0; + + using (Stream src = zip.GetInputStream(entry)) + using (FileStream dst = File.Create(path)) + { + int read = src.Read(buffer, 0, buffer.Length); + + while (0 < read) + { + dst.Write(buffer, 0, read); + transferred += read; + + e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Extracting_EntryBytesWritten, zipFileName); + e.EntriesTotal = entriesTotal; + e.EntriesProcessed = entriesProcessed; + e.CurrentEntryName = entry.Name; + e.TotalBytesToTransfer = entry.Size; + e.BytesTransferred = transferred; + base.OnExtractProgress(e); + + read = src.Read(buffer, 0, buffer.Length); + } + } + + // 更新日時を書庫の値に合わせる。 + File.SetLastWriteTime(path, entry.DateTime); + + this._extractedFiles.Add(path); + + e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Extracting_AfterExtractEntry, zipFileName); + e.EntriesTotal = entriesTotal; + e.EntriesProcessed = entriesProcessed + 1; + e.CurrentEntryName = entry.Name; + e.TotalBytesToTransfer = entry.Size; + e.BytesTransferred = transferred; + base.OnExtractProgress(e); + + return true; + } + + /// <summary>解凍先のパスを求める</summary> + /// <param name="directoryToUnZip">解凍先</param> + /// <param name="entryName">エントリ名</param> + /// <returns>解凍先のパス</returns> + /// <remarks> + /// **解凍先の外に出るエントリ名を弾く(Zip Slip 対策)。** + /// エントリ名は書庫を作った側が自由に決められるため、 + /// "../" を含めて任意の場所へ書かせることができる。 + /// 旧実装が使っていた DotNetZip は、この脆弱性 + /// (GHSA-xhg6-9j5j-w4vf)で非推奨になった。**同じ轍を踏まない。** + /// </remarks> + private static string GetSafePath(string directoryToUnZip, string entryName) + { + string root = Path.GetFullPath(directoryToUnZip); + string path = Path.GetFullPath(Path.Combine(root, entryName)); + + // 区切り文字を足してから比較する。 + // 足さないと "C:\dir" と "C:\dir2" が前方一致してしまう。 + string prefix = root.EndsWith(Path.DirectorySeparatorChar.ToString()) + ? root : root + Path.DirectorySeparatorChar; + + if (!path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + { + throw new IOException(entryName); + } + + return path; + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipBaseV2.cs b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipBaseV2.cs new file mode 100644 index 000000000..c2d6b2743 --- /dev/null +++ b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipBaseV2.cs @@ -0,0 +1,264 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :ZipBaseV2 +//* クラス日本語名 :SharpZipLib部品ベース クラス +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/08 玄人 幸道 新規作成(#524) +//********************************************************************************** + +using System; +using System.Text; + +using ICSharpCode.SharpZipLib.Zip; + +namespace Touryo.Infrastructure.Public.IO +{ + /// <summary>SharpZipLib部品ベース クラス</summary> + /// <remarks> + /// 旧 ZipBase(DotNetZip)の代替(#524)。 + /// DotNetZip は非推奨かつ既知脆弱性(GHSA-xhg6-9j5j-w4vf)があるため、 + /// SharpZipLib で作り直したもの。**旧クラスは残してあるが、ビルド対象外。** + /// + /// <旧から落とした機能> + /// ・自己解凍書庫(SaveSelfExtractor)… SharpZipLib に相当が無い。 + /// 呼び出し元(DeployZipPackWithHTTP)にも消費経路が無いことを確認済み。 + /// ・選択条件の文字列("name = *.txt" 等)… DotNetZip 独自の DSL。 + /// SelectionDelegate に一本化した。 + /// ・StatusMSG … DotNetZip が吐くログ文言。**同じ文字列は作れない。** + /// 解凍したパスは UnZipperV2.ExtractedFiles で受け取ること。 + /// ・AddProgress / ReadProgress / ZipError … 呼び出し元で未使用。 + /// </remarks> + public abstract class ZipBaseV2 + { + /// <summary>コンストラクタ</summary> + public ZipBaseV2() + { + // 選択処理を実装するデリゲート + this._selectionDlgt = new SelectionDelegate(this.DefaultSelectionDlgt); + } + + #region 選択処理 + + /// <summary>選択処理を実装するデリゲート</summary> + /// <param name="o"> + /// 圧縮時:ファイル(FileInfo) + /// 解凍時:エントリ名(string) + /// </param> + /// <param name="info">選択規準情報</param> + /// <returns> + /// true:ファイルを圧縮 or 解凍する。 + /// false:ファイルを圧縮 or 解凍しない。 + /// </returns> + public delegate bool SelectionDelegate(object o, object info); + + /// <summary>選択処理を実装するデリゲート</summary> + protected SelectionDelegate _selectionDlgt = null; + + /// <summary>選択処理を実装するデリゲート</summary> + public SelectionDelegate SelectionDlgt + { + private set { this._selectionDlgt = value; } + get { return this._selectionDlgt; } + } + + /// <summary>選択処理を実装するデリゲート</summary> + /// <param name="o"> + /// 圧縮時:ファイル(FileInfo) + /// 解凍時:エントリ名(string) + /// </param> + /// <param name="info">選択規準情報</param> + /// <returns> + /// true:ファイルを圧縮 or 解凍する。 + /// false:ファイルを圧縮 or 解凍しない。 + /// </returns> + protected bool DefaultSelectionDlgt(object o, object info) + { + return true; + } + + /// <summary>選択基準情報</summary> + protected object _selectionCriteriaInfo = null; + + /// <summary>選択基準情報</summary> + public object SelectionCriteriaInfo + { + private set { this._selectionCriteriaInfo = value; } + get { return this._selectionCriteriaInfo; } + } + + /// <summary>選択基準を設定する</summary> + /// <param name="selectionDlgt">ファイル選択デリゲード</param> + /// <param name="selectionCriteriaInfo">ファイル選択基準情報</param> + /// <remarks> + /// **デリゲートが null のときは既定(すべて選択)のまま**にする。 + /// 旧実装と同じ振る舞い。 + /// </remarks> + protected void SetSelectionCriteria( + SelectionDelegate selectionDlgt, object selectionCriteriaInfo) + { + if (selectionDlgt != null) + { + this._selectionDlgt = selectionDlgt; + this._selectionCriteriaInfo = selectionCriteriaInfo; + } + } + + #endregion + + #region 進捗イベント + + /// <summary>SaveProgressイベント ハンドラ</summary> + protected EventHandler<ZipProgressEventArgsV2> _saveProgress = null; + + /// <summary>SaveProgressイベント ハンドラ</summary> + public EventHandler<ZipProgressEventArgsV2> SaveProgress + { + set { this._saveProgress = value; } + get { return this._saveProgress; } + } + + /// <summary>ExtractProgressイベント ハンドラ</summary> + protected EventHandler<ZipProgressEventArgsV2> _extractProgress = null; + + /// <summary>ExtractProgressイベント ハンドラ</summary> + public EventHandler<ZipProgressEventArgsV2> ExtractProgress + { + set { this._extractProgress = value; } + get { return this._extractProgress; } + } + + /// <summary>SaveProgressイベントを発生させる</summary> + /// <param name="e">ZipProgressEventArgsV2</param> + protected void OnSaveProgress(ZipProgressEventArgsV2 e) + { + EventHandler<ZipProgressEventArgsV2> h = this._saveProgress; + if (h != null) { h(this, e); } + } + + /// <summary>ExtractProgressイベントを発生させる</summary> + /// <param name="e">ZipProgressEventArgsV2</param> + protected void OnExtractProgress(ZipProgressEventArgsV2 e) + { + EventHandler<ZipProgressEventArgsV2> h = this._extractProgress; + if (h != null) { h(this, e); } + } + + #endregion + + #region 書庫の設定 + + /// <summary>書庫に付けるコメント</summary> + public const string ZipComment = "ZipperV2 @ Powered by SharpZipLib"; + + /// <summary>文字コードの設定を作る</summary> + /// <param name="enc">エンコーディング(nullなら既定)</param> + /// <returns>StringCodec</returns> + /// <remarks> + /// **ZipStrings(プロセス全体の静的設定)は触らない。** + /// 触ると同一プロセスの他の処理に波及するため、 + /// インスタンス単位で持てる StringCodec を使う。 + /// + /// **プロパティに代入してはいけない。** セッターが init のため、 + /// C# 7.3 でビルドする net48 側でコンパイル エラーになる(CS0200)。 + /// 用意されている FromEncoding / WithForcedLegacyEncoding を使う。 + /// + /// WithForcedLegacyEncoding を呼ぶのは、指定した文字コードを + /// 実際にエントリ名へ使わせるため(既定では UTF-8 が優先される)。 + /// </remarks> + protected StringCodec GetStringCodec(Encoding enc) + { + if (enc == null) { return ZipStrings.GetStringCodec(); } + + return StringCodec.FromEncoding(enc).WithForcedLegacyEncoding(); + } + + #endregion + } + + /// <summary>進捗イベントの引数</summary> + /// <remarks> + /// 旧 Ionic.Zip の SaveProgressEventArgs / ExtractProgressEventArgs の代替。 + /// **プロパティ名は旧に合わせてある**(EventType / EntriesTotal / CurrentEntry 等)。 + /// </remarks> + public class ZipProgressEventArgsV2 : EventArgs + { + /// <summary>コンストラクタ</summary> + /// <param name="eventType">進捗の種別</param> + /// <param name="archiveName">書庫のファイル名</param> + public ZipProgressEventArgsV2(ZipProgressEventTypeV2 eventType, string archiveName) + { + this.EventType = eventType; + this.ArchiveName = archiveName; + } + + /// <summary>進捗の種別</summary> + public ZipProgressEventTypeV2 EventType { get; private set; } + + /// <summary>書庫のファイル名</summary> + public string ArchiveName { get; private set; } + + /// <summary>エントリの総数</summary> + /// <remarks>種別が Started / Completed 以外では 0 のことがある。</remarks> + public int EntriesTotal { get; set; } + + /// <summary>処理済みのエントリ数</summary> + public int EntriesProcessed { get; set; } + + /// <summary>処理中のエントリ名</summary> + public string CurrentEntryName { get; set; } + + /// <summary>処理中のエントリの総バイト数</summary> + public long TotalBytesToTransfer { get; set; } + + /// <summary>処理中のエントリの転送済みバイト数</summary> + public long BytesTransferred { get; set; } + + /// <summary>解凍先のフォルダ</summary> + /// <remarks>解凍時のみ設定される。</remarks> + public string ExtractLocation { get; set; } + + /// <summary>ハンドラへの問い合わせか</summary> + /// <remarks> + /// Extracting_ExtractEntryWouldOverwrite は 2 つの意味で起きる。 + /// true … **問い合わせ**。ExtractExistingFile に返答を設定すること + /// false … **通知**。既に「上書きしない」と決まっており、設定しても効かない + /// **既定値に頼って見分けてはいけない**ため、明示的に持たせている。 + /// </remarks> + public bool IsQuery { get; set; } + + /// <summary>このエントリをどう扱うか</summary> + /// <remarks> + /// **ハンドラが書き換えるためのプロパティ。** + /// EventType が Extracting_ExtractEntryWouldOverwrite のときだけ意味を持つ + /// (ExtractExistingFileActionV2.InvokeExtractProgressEvent を指定した場合)。 + /// + /// 旧 Ionic では ZipEntry 側のプロパティ(e.CurrentEntry.ExtractExistingFile) + /// だったが、こちらはイベント引数に持たせている。 + /// </remarks> + public ExtractExistingFileActionV2 ExtractExistingFile { get; set; } + + /// <summary>以降の処理を打ち切るか</summary> + /// <remarks>ハンドラが true を設定すると、残りのエントリを処理しない。</remarks> + public bool Cancel { get; set; } + } +} diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipEnumV2.cs b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipEnumV2.cs new file mode 100644 index 000000000..cf93cd99a --- /dev/null +++ b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipEnumV2.cs @@ -0,0 +1,149 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :ZipEnumV2 +//* クラス日本語名 :ZIP部品(V2)の列挙型 +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/08 玄人 幸道 新規作成(#524) +//********************************************************************************** + +namespace Touryo.Infrastructure.Public.IO +{ + /// <summary>暗号化方式</summary> + /// <remarks> + /// 旧 Zipper が使っていた Ionic.Zip.EncryptionAlgorithm の代替。 + /// **メンバ名は旧と同じ**にしてある(移植時に読み替えが要らないように)。 + /// + /// 旧にあった Unsupported は持たない。 + /// Ionic では「設定不可能」を表す番人だったが、SharpZipLib に相当が無く、 + /// None との違いを呼び出し側が意識する必要も無いため。 + /// </remarks> + public enum ZipEncryptionAlgorithmV2 + { + /// <summary>暗号化しない</summary> + None = 0, + + /// <summary>ZipCrypto(PKZIP 伝統方式)</summary> + /// <remarks> + /// **強度は低い。** 互換性のためだけに残している。 + /// 新規に選ぶなら WinZipAes256 を使うこと。 + /// </remarks> + PkzipWeak = 1, + + /// <summary>WinZip AES 128bit</summary> + WinZipAes128 = 2, + + /// <summary>WinZip AES 256bit</summary> + WinZipAes256 = 3, + } + + /// <summary>圧縮レベル</summary> + /// <remarks> + /// 旧 Zipper が使っていた Ionic.Zlib.CompressionLevel の代替。 + /// Ionic は 0〜9 の全段階を列挙していたが、実用上の 4 段階だけを持つ。 + /// 値は SharpZipLib の ZipOutputStream.SetLevel に渡す 0〜9 に対応する。 + /// </remarks> + public enum ZipCompressionLevelV2 + { + /// <summary>無圧縮(格納のみ)</summary> + None = 0, + + /// <summary>速度優先</summary> + BestSpeed = 1, + + /// <summary>既定</summary> + Default = 6, + + /// <summary>圧縮率優先</summary> + BestCompression = 9, + } + + /// <summary>解凍先に同名ファイルがあったときの動作</summary> + /// <remarks> + /// 旧 UnZipper が使っていた Ionic.Zip.ExtractExistingFileAction の代替。 + /// **メンバ名は旧と同じ**。 + /// </remarks> + public enum ExtractExistingFileActionV2 + { + /// <summary>例外にする</summary> + Throw = 0, + + /// <summary>黙って上書きする</summary> + OverwriteSilently = 1, + + /// <summary>上書きせず、そのファイルを飛ばす</summary> + DoNotOverwrite = 2, + + /// <summary>ExtractProgressイベントで、1件ずつ問い合わせる</summary> + /// <remarks> + /// Extracting_ExtractEntryWouldOverwrite でイベントが起き、 + /// ハンドラが ZipProgressEventArgsV2.ExtractExistingFile に + /// Throw / OverwriteSilently / DoNotOverwrite のいずれかを設定して返す。 + /// Cancel に true を設定すると、以降の解凍を打ち切る。 + /// + /// **ここに InvokeExtractProgressEvent を設定して返してはいけない**(無限に問い合わせるため)。 + /// その場合は DoNotOverwrite として扱う。 + /// </remarks> + InvokeExtractProgressEvent = 3, + } + + /// <summary>進捗の種別</summary> + /// <remarks> + /// 旧 Zipper / UnZipper が使っていた Ionic.Zip.ZipProgressEventType のうち、 + /// **呼び出し元が実際に分岐していたものだけ**を持つ。 + /// </remarks> + public enum ZipProgressEventTypeV2 + { + /// <summary>圧縮を開始した</summary> + Saving_Started = 0, + + /// <summary>1 エントリの書き込み前</summary> + Saving_BeforeWriteEntry = 1, + + /// <summary>1 エントリの書き込み中(バイト単位)</summary> + Saving_EntryBytesRead = 2, + + /// <summary>1 エントリの書き込み後</summary> + Saving_AfterWriteEntry = 3, + + /// <summary>圧縮が完了した</summary> + Saving_Completed = 4, + + /// <summary>解凍を開始した</summary> + Extracting_Started = 5, + + /// <summary>1 エントリの解凍前</summary> + Extracting_BeforeExtractEntry = 6, + + /// <summary>1 エントリの解凍中(バイト単位)</summary> + Extracting_EntryBytesWritten = 7, + + /// <summary>1 エントリの解凍後</summary> + Extracting_AfterExtractEntry = 8, + + /// <summary>上書きになるため飛ばした</summary> + Extracting_ExtractEntryWouldOverwrite = 9, + + /// <summary>解凍が完了した</summary> + Extracting_Completed = 10, + } +} diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipperV2.cs b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipperV2.cs new file mode 100644 index 000000000..2a40f08a9 --- /dev/null +++ b/root/programs/CS/Frameworks/Infrastructure/Public/IO/ZipperV2.cs @@ -0,0 +1,321 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :ZipperV2 +//* クラス日本語名 :SharpZipLibを使用した圧縮クラス +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/08 玄人 幸道 新規作成(#524) +//********************************************************************************** + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using ICSharpCode.SharpZipLib.Zip; + +using Touryo.Infrastructure.Public.Util; + +namespace Touryo.Infrastructure.Public.IO +{ + /// <summary>SharpZipLibを使用した圧縮クラス</summary> + /// <remarks> + /// 旧 Zipper(DotNetZip)の代替(#524)。 + /// **引数の並びと名前は旧に合わせてある。** 型だけが自前の列挙型に変わる。 + /// 自己解凍書庫(selfEx)を取るオーバーロードは持たない。 + /// </remarks> + public class ZipperV2 : ZipBaseV2 + { + #region ZippedFiles + + /// <summary>圧縮したファイルのパス</summary> + private List<string> _zippedFiles = new List<string>(); + + /// <summary>圧縮したファイルのパス</summary> + /// <remarks> + /// 旧 StatusMSG の代替(UnZipperV2.ExtractedFiles と対)。 + /// **CreateZipFromFolder のたびに作り直す**(前回の内容は残らない)。 + /// 選択デリゲートで除いたファイルは含まない。 + /// </remarks> + public string[] ZippedFiles + { + get { return this._zippedFiles.ToArray(); } + } + + #endregion + + #region CreateZipFromFolder + + /// <summary>フォルダ以下を圧縮</summary> + /// <param name="zipFileToCreate">圧縮ファイル名(拡張子は付けない。".zip"が付く)</param> + /// <param name="directoryToZip">圧縮対象フォルダ</param> + /// <param name="selectionDlgt">ファイル選択デリゲード</param> + /// <param name="selectionCriteriaInfo">ファイル選択基準情報</param> + /// <param name="rootPathInArchive">書庫内ルートフォルダ</param> + /// <param name="enc">エンコーディング</param> + /// <param name="cyp">暗号化</param> + /// <param name="zipPassword">パスワード</param> + /// <param name="cmpLv">圧縮レベル</param> + public void CreateZipFromFolder( + string zipFileToCreate, + string directoryToZip, + SelectionDelegate selectionDlgt, + object selectionCriteriaInfo, + string rootPathInArchive, + Encoding enc, + ZipEncryptionAlgorithmV2 cyp, + string zipPassword, + ZipCompressionLevelV2 cmpLv) + { + // ファイル選択基準 + base.SetSelectionCriteria(selectionDlgt, selectionCriteriaInfo); + + this._zippedFiles = new List<string>(); + + string zipFileName = zipFileToCreate + ".zip"; + + // 圧縮対象を先に数え上げる。 + // **進捗の総数を知るために必要。** 逐次追加では総数が分からない。 + List<ZipperV2.Target> targets = new List<ZipperV2.Target>(); + this.CollectRecursive(targets, directoryToZip, rootPathInArchive); + + ZipProgressEventArgsV2 e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Saving_Started, zipFileName); + e.EntriesTotal = targets.Count; + base.OnSaveProgress(e); + + using (FileStream fs = File.Create(zipFileName)) + using (ZipOutputStream zos = new ZipOutputStream(fs, base.GetStringCodec(enc))) + { + this.SetZipOutputStream(zos, cyp, zipPassword, cmpLv); + zos.SetComment(ZipBaseV2.ZipComment); + + int processed = 0; + + foreach (ZipperV2.Target t in targets) + { + this.AddEntry(zos, t, zipFileName, cyp, targets.Count, processed); + this._zippedFiles.Add(t.FilePath); + processed++; + } + + zos.Finish(); + } + + e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Saving_Completed, zipFileName); + e.EntriesTotal = targets.Count; + e.EntriesProcessed = targets.Count; + base.OnSaveProgress(e); + } + + #endregion + + #region private + + /// <summary>圧縮対象</summary> + private class Target + { + /// <summary>実ファイルのパス</summary> + public string FilePath; + + /// <summary>書庫内のパス</summary> + public string EntryName; + } + + /// <summary>圧縮対象を再帰で集める</summary> + /// <param name="targets">集めた結果</param> + /// <param name="directoryToZip">圧縮対象フォルダ</param> + /// <param name="directoryPathInArchive">ZIP内パス</param> + private void CollectRecursive( + List<ZipperV2.Target> targets, + string directoryToZip, + string directoryPathInArchive) + { + // ファイル + foreach (string fileName in Directory.GetFiles(directoryToZip)) + { + FileInfo f = new FileInfo(fileName); + + // 圧縮対象ファイルを選択(ファイル選択デリゲードを使用) + if (base.SelectionDlgt(f, base.SelectionCriteriaInfo)) + { + ZipperV2.Target t = new ZipperV2.Target(); + t.FilePath = f.FullName; + t.EntryName = ZipperV2.CombineEntryName(directoryPathInArchive, f.Name); + targets.Add(t); + } + } + + // フォルダ + foreach (string directoryName in Directory.GetDirectories(directoryToZip)) + { + DirectoryInfo d = new DirectoryInfo(directoryName); + + this.CollectRecursive(targets, directoryName, + ZipperV2.CombineEntryName(directoryPathInArchive, d.Name)); + } + } + + /// <summary>書庫内のパスを繋ぐ</summary> + /// <param name="parent">親</param> + /// <param name="name">名前</param> + /// <returns>書庫内のパス</returns> + /// <remarks> + /// **区切りは "/" にする。** ZIP の仕様であり、Path.Combine を使うと + /// Windows では "\" になって、他のツールで開いたときに階層にならない。 + /// </remarks> + private static string CombineEntryName(string parent, string name) + { + if (string.IsNullOrEmpty(parent)) { return name; } + return parent.Replace('\\', '/').TrimEnd('/') + "/" + name; + } + + /// <summary>ZipOutputStreamに圧縮方法を設定する</summary> + /// <param name="zos">ZipOutputStream</param> + /// <param name="cyp">暗号化</param> + /// <param name="zipPassword">パスワード</param> + /// <param name="cmpLv">圧縮レベル</param> + private void SetZipOutputStream( + ZipOutputStream zos, + ZipEncryptionAlgorithmV2 cyp, + string zipPassword, + ZipCompressionLevelV2 cmpLv) + { + // 4G以上のファイルがある時には、ZIP64を使用 + zos.UseZip64 = UseZip64.Dynamic; + + // 圧縮レベル + zos.SetLevel((int)cmpLv); + + // 解凍パスワード + if (string.IsNullOrEmpty(zipPassword)) + { + // null、空文字なので設定しない。 + if (cyp != ZipEncryptionAlgorithmV2.None) + { throw new ArgumentException(PublicExceptionMessage.ZIP_PASSWORD, "zipPassword"); } + } + else + { + if (cyp == ZipEncryptionAlgorithmV2.None) + { + // 暗号化しないので、パスワードは設定しない。 + } + else + { + zos.Password = zipPassword; + } + } + } + + /// <summary>1エントリを書き込む</summary> + /// <param name="zos">ZipOutputStream</param> + /// <param name="t">圧縮対象</param> + /// <param name="zipFileName">書庫のファイル名</param> + /// <param name="cyp">暗号化</param> + /// <param name="entriesTotal">エントリの総数</param> + /// <param name="entriesProcessed">処理済みのエントリ数</param> + /// <remarks> + /// **FastZip を使わない理由。** FastZip の進捗はバイト単位だけで、 + /// エントリの前後が取れない。旧 Zipper の呼び出し元は + /// Saving_BeforeWriteEntry / Saving_EntryBytesRead / Saving_AfterWriteEntry の + /// 3 段階で進捗バーを動かしていたため、ZipOutputStream を自前で回す。 + /// </remarks> + private void AddEntry( + ZipOutputStream zos, + ZipperV2.Target t, + string zipFileName, + ZipEncryptionAlgorithmV2 cyp, + int entriesTotal, + int entriesProcessed) + { + FileInfo f = new FileInfo(t.FilePath); + + ZipEntry entry = new ZipEntry(t.EntryName); + entry.DateTime = f.LastWriteTime; + entry.Size = f.Length; + + // 暗号化方式 + // AESKeySize は 0 で ZipCrypto(PKZIP 伝統方式)になる。 + switch (cyp) + { + case ZipEncryptionAlgorithmV2.WinZipAes128: + entry.AESKeySize = 128; + break; + case ZipEncryptionAlgorithmV2.WinZipAes256: + entry.AESKeySize = 256; + break; + default: + entry.AESKeySize = 0; + break; + } + + ZipProgressEventArgsV2 e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Saving_BeforeWriteEntry, zipFileName); + e.EntriesTotal = entriesTotal; + e.EntriesProcessed = entriesProcessed; + e.CurrentEntryName = t.EntryName; + e.TotalBytesToTransfer = f.Length; + base.OnSaveProgress(e); + + zos.PutNextEntry(entry); + + byte[] buffer = new byte[81920]; + long transferred = 0; + + using (FileStream src = File.OpenRead(t.FilePath)) + { + int read = src.Read(buffer, 0, buffer.Length); + + while (0 < read) + { + zos.Write(buffer, 0, read); + transferred += read; + + e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Saving_EntryBytesRead, zipFileName); + e.EntriesTotal = entriesTotal; + e.EntriesProcessed = entriesProcessed; + e.CurrentEntryName = t.EntryName; + e.TotalBytesToTransfer = f.Length; + e.BytesTransferred = transferred; + base.OnSaveProgress(e); + + read = src.Read(buffer, 0, buffer.Length); + } + } + + zos.CloseEntry(); + + e = new ZipProgressEventArgsV2( + ZipProgressEventTypeV2.Saving_AfterWriteEntry, zipFileName); + e.EntriesTotal = entriesTotal; + e.EntriesProcessed = entriesProcessed + 1; + e.CurrentEntryName = t.EntryName; + e.TotalBytesToTransfer = f.Length; + e.BytesTransferred = transferred; + base.OnSaveProgress(e); + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Log/LogManager_log4net.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Log/LogManager_log4net.cs index 976884180..522af06c3 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Log/LogManager_log4net.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Log/LogManager_log4net.cs @@ -1,4 +1,4 @@ -//********************************************************************************** +//********************************************************************************** //* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. //********************************************************************************** @@ -38,6 +38,8 @@ //* 2011/01/19 西野 大介 環境変数の組み込み処理に対応 //* 2011/10/09 西野 大介 国際化対応 //* 2018/03/28 西野 大介 .NET Standard対応で、I/F変更あり。 +//* 2026/08/01 玄人 幸道 定義ファイルの探索を ResourceLoader.ResolveFilePath に統一した。 +//* ※ 存在チェックと読み込みで同じ実パスを使うようにした。 //********************************************************************************** using System; @@ -154,13 +156,23 @@ public static log4net.ILog GetLog4netIf(string loggerName) } else { - // リソース ローダで存在チェック(存在しなければエラー) - ResourceLoader.Exists(log4netConfFile, true); + // ↓↓↓【変更】↓↓↓ + // リソース ローダで実パスを解決する。 + // ※ 以前は Exists で存在チェックした後、生のパスで開いていたため、 + // ResolveFilePath の探索結果(EXEの配置フォルダ基準)を活かせなかった。 + string log4netConfFilePath = ResourceLoader.ResolveFilePath(log4netConfFile); + + if (log4netConfFilePath == null) + { + // 存在しない場合はエラー(例外の送出は Exists に委ねる) + ResourceLoader.Exists(log4netConfFile, true); + } // ログ定義 [リソース ファイル] → ストリームを開く FileStream s = new FileStream( - StringVariableOperator.BuiltStringIntoEnvironmentVariable(log4netConfFile), + log4netConfFilePath, FileMode.Open, FileAccess.Read, FileShare.Read); + // ↑↑↑【変更】↑↑↑ // log4netのXML形式の設定ファイルを読み込む。 #if (NETSTD || NETCOREAPP) diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Log/LogManager_nlog.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Log/LogManager_nlog.cs index e56b337d1..fab4dd14d 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Log/LogManager_nlog.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Log/LogManager_nlog.cs @@ -1,4 +1,4 @@ -//********************************************************************************** +//********************************************************************************** //* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. //********************************************************************************** @@ -28,6 +28,8 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2025/06/15 西野 大介 新規作成 +//* 2026/08/01 玄人 幸道 定義ファイルの探索を ResourceLoader.ResolveFilePath に統一した。 +//* ※ 存在チェックと読み込みで同じ実パスを使うようにした。 //********************************************************************************** using System; @@ -127,11 +129,21 @@ public static NLog.Logger GetNLogIf(string loggerName) } else { - // リソース ローダで存在チェック(存在しなければエラー) - ResourceLoader.Exists(nlogConfFile, true); + // ↓↓↓【変更】↓↓↓ + // リソース ローダで実パスを解決する。 + // ※ 以前は Exists で存在チェックした後、生のパスで開いていたため、 + // ResolveFilePath の探索結果(EXEの配置フォルダ基準)を活かせなかった。 + string nlogConfFilePath = ResourceLoader.ResolveFilePath(nlogConfFile); + + if (nlogConfFilePath == null) + { + // 存在しない場合はエラー(例外の送出は Exists に委ねる) + ResourceLoader.Exists(nlogConfFile, true); + } // nlog - NLog.LogManager.Configuration = new XmlLoggingConfiguration(nlogConfFile); + NLog.LogManager.Configuration = new XmlLoggingConfiguration(nlogConfFilePath); + // ↑↑↑【変更】↑↑↑ } // NLog.Loggerインスタンスを初期化する。 diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Properties/AssemblyInfo.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Properties/AssemblyInfo.cs index f728b20bc..75ecc8cdf 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Properties/AssemblyInfo.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Properties/AssemblyInfo.cs @@ -62,4 +62,4 @@ // // すべての値を指定するか、下のように '*' を使ってリビジョンおよびビルド番号を // 既定値にすることができます: -[assembly: AssemblyVersion("3.0.0.0")] \ No newline at end of file +[assembly: AssemblyVersion("3.3.0.0")] \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Public_net48.csproj b/root/programs/CS/Frameworks/Infrastructure/Public/Public_net48.csproj index 63619373c..86525ad1e 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Public_net48.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Public_net48.csproj @@ -24,6 +24,12 @@ <OldToolsVersion>2.0</OldToolsVersion> <UpgradeBackupLocation /> <TargetFrameworkProfile /> + <!--Source Link(#531) + .NET 8 以降の SDK は Source Link を自動で組み込むが、**旧形式 csproj には効かない** + (Microsoft.Common.props を通らないため)。net48 側は明示的に入れる。 + これが無いと、利用者は lib\net48 を参照したときにソースへ踏み込めない。--> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> <PublishUrl>publish\</PublishUrl> <Install>true</Install> <InstallFrom>Disk</InstallFrom> @@ -131,6 +137,10 @@ <Compile Include="IO\BinarySerialize.cs" /> <Compile Include="IO\EmbeddedResourceLoader.cs" /> <Compile Include="IO\ResourceLoader.cs" /> + <Compile Include="IO\ZipEnumV2.cs" /> + <Compile Include="IO\ZipBaseV2.cs" /> + <Compile Include="IO\ZipperV2.cs" /> + <Compile Include="IO\UnZipperV2.cs" /> <Compile Include="Log\LogIF.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Str\CustomEncode.cs" /> @@ -169,7 +179,7 @@ </ItemGroup> <ItemGroup> <PackageReference Include="log4net"> - <Version>3.1.0</Version> + <Version>3.3.0</Version> </PackageReference> <PackageReference Include="Microsoft.Data.SqlClient"> <Version>6.0.2</Version> @@ -180,6 +190,16 @@ <PackageReference Include="NLog"> <Version>5.5.0</Version> </PackageReference> + <PackageReference Include="SharpZipLib"> + <Version>1.4.2</Version> + </PackageReference> + <!--Source Link(#531)。**ビルド時にだけ使う**ので PrivateAssets=all にし、 + NuGet パッケージの依存関係には出さない。--> + <PackageReference Include="Microsoft.SourceLink.GitHub"> + <Version>10.0.301</Version> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Public_netcore100.csproj b/root/programs/CS/Frameworks/Infrastructure/Public/Public_netcore100.csproj index 553e1cc41..70bed1f85 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Public_netcore100.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Public_netcore100.csproj @@ -4,8 +4,7 @@ <TargetFramework>net10.0</TargetFramework> <AssemblyName>OpenTouryo.Public</AssemblyName> <RootNamespace>Touryo.Infrastructure.Public</RootNamespace> - <Version>3.0.0.0</Version> - <Company>Hitachi Solutions</Company> + <Version>$(OpenTouryoVersion)</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> @@ -89,7 +88,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="log4net" Version="3.0.4" /> + <PackageReference Include="log4net" Version="3.3.0" /> <PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.1" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.4" /> <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.4" /> @@ -97,6 +96,7 @@ <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.4" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="NLog" Version="5.5.0" /> + <PackageReference Include="SharpZipLib" Version="1.4.2" /> <PackageReference Include="System.Data.Odbc" Version="9.0.4" /> <PackageReference Include="Zipangu" Version="1.1.8" /> </ItemGroup> diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Security/EnumSymmetricAlgorithm.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Security/EnumSymmetricAlgorithm.cs index 763772a15..0c972444e 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Security/EnumSymmetricAlgorithm.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Security/EnumSymmetricAlgorithm.cs @@ -28,6 +28,7 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2018/10/30 西野 大介 新規作成(分離) +//* 2026/08/10 玄人 幸道 CipherMode_ECB を非推奨化(CodeQL: Encryption using ECB) //********************************************************************************** using System; @@ -90,6 +91,12 @@ public enum EnumSymmetricAlgorithm /// <summary>CipherMode.CTS</summary> CipherMode_CTS = 1 << 10, /// <summary>CipherMode.ECB</summary> + /// <remarks> + /// ECB は各ブロックを独立に暗号化するため、同じ平文ブロックが常に同じ暗号文ブロックになる。 + /// 平文のパターンが暗号文に透け、ブロックの入れ替え・削除・再利用にも耐えない。 + /// 指定しなければ .NET の既定である CBC が使われる。 + /// </remarks> + [Obsolete("CipherMode_ECB is deprecated, please use CipherMode_CBC instead.")] CipherMode_ECB = 1 << 11, /// <summary>CipherMode.OFB</summary> CipherMode_OFB = 1 << 12, diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Jwt/EccPublicKeyConverter.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Jwt/EccPublicKeyConverter.cs index 86fea6e49..49bcf7034 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Jwt/EccPublicKeyConverter.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Jwt/EccPublicKeyConverter.cs @@ -32,6 +32,8 @@ //* 下位がExportableである必要性があった、 //* また、ASP.NET上で実行する可能性もある。 //* 2019/06/25 西野 大介 インスタンス・メソッド化(ES256, 384, 512対応) +//* 2026/08/01 玄人 幸道 jose-jwtへの依存を解消(JwkToCngをBCLのみで実装) +//* ※ 楕円曲線の決定にcrvを使用するため、jose-jwt非互換。 //********************************************************************************** using System; @@ -44,7 +46,6 @@ //using Jose; //using Security.Cryptography; -using Jose.keys; using Touryo.Infrastructure.Public.Str; @@ -252,14 +253,34 @@ public CngKey JwkToCng(string jwkString) /// <summary>JwkToCng</summary> /// <param name="jwk">JObject</param> /// <returns>CngKey(公開鍵)</returns> + /// <remarks> + /// 【jose-jwt 非互換】 + /// 以前は jose-jwt の EccKey.New(x, y) を使用していたが、 + /// jose-jwt への依存を解消するため、BCL のみの実装に変更した。 + /// これに伴い、楕円曲線の決定方法が変わっている。 + /// ・旧:x 座標のバイト長から推測(32→P-256、48→P-384、66→P-521) + /// ・新:JWK の crv メンバを参照する + /// 長さによる推測は secp256k1 や Brainpool と区別が付かず、 + /// 誤った曲線の鍵を生成し得るため、crv を必須とした。 + /// なお crv は RFC 7517/RFC 7518 において EC 鍵の必須メンバであり、 + /// 姉妹メソッドの JwkToParam も従来から crv を必須としている。 + /// </remarks> public CngKey JwkToCng(Dictionary<string, string> jwk) { + ECParameters ecParams = new ECParameters(); + // 楕円曲線 - // 不要 + ecParams.Curve = this.GetECCurveFromCrvString((string)jwk[JwtConst.crv]); + // 公開鍵の部分 - return EccKey.New( - CustomEncode.FromBase64UrlString((string)jwk[JwtConst.x]), - CustomEncode.FromBase64UrlString((string)jwk[JwtConst.y])); + ecParams.Q.X = CustomEncode.FromBase64UrlString((string)jwk[JwtConst.x]); + ecParams.Q.Y = CustomEncode.FromBase64UrlString((string)jwk[JwtConst.y]); + + // ECParameters → CngKey + ECDsaCng ecDsaCng = new ECDsaCng(); + ecDsaCng.ImportParameters(ecParams); + + return ecDsaCng.Key; } #endregion diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Properties/AssemblyInfo.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Properties/AssemblyInfo.cs index 0f116f94d..c7810e612 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Properties/AssemblyInfo.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Properties/AssemblyInfo.cs @@ -62,4 +62,4 @@ // // すべての値を指定するか、下のように '*' を使ってリビジョンおよびビルド番号を // 既定値にすることができます: -[assembly: AssemblyVersion("3.0.0.0")] \ No newline at end of file +[assembly: AssemblyVersion("3.3.0.0")] \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Public.Security_net48.csproj b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Public.Security_net48.csproj index 4cbe5694a..1a43b5efc 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Public.Security_net48.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Public.Security_net48.csproj @@ -41,7 +41,13 @@ <BootstrapperEnabled>true</BootstrapperEnabled> <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> <RestorePackages>true</RestorePackages> - </PropertyGroup> + <!--Source Link(#531) + .NET 8 以降の SDK は Source Link を自動で組み込むが、**旧形式 csproj には効かない** + (Microsoft.Common.props を通らないため)。net48 側は明示的に入れる。 + これが無いと、利用者は lib\net48 を参照したときにソースへ踏み込めない。--> + <PublishRepositoryUrl>true</PublishRepositoryUrl> + <EmbedUntrackedSources>true</EmbedUntrackedSources> +</PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> @@ -184,9 +190,6 @@ <PackageReference Include="BouncyCastle.NetCore"> <Version>2.2.1</Version> </PackageReference> - <PackageReference Include="jose-jwt"> - <Version>5.1.1</Version> - </PackageReference> <PackageReference Include="Newtonsoft.Json"> <Version>13.0.3</Version> </PackageReference> @@ -203,4 +206,13 @@ <PostBuildEvent> </PostBuildEvent> </PropertyGroup> + <ItemGroup> + <!--Source Link(#531)。**ビルド時にだけ使う**ので PrivateAssets=all にし、 + NuGet パッケージの依存関係には出さない。--> + <PackageReference Include="Microsoft.SourceLink.GitHub"> + <Version>10.0.301</Version> + <PrivateAssets>all</PrivateAssets> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + </PackageReference> + </ItemGroup> </Project> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Public.Security_netcore100.csproj b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Public.Security_netcore100.csproj index e19bfe877..2d7b67290 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Security/Public.Security_netcore100.csproj +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Security/Public.Security_netcore100.csproj @@ -4,8 +4,7 @@ <TargetFramework>net10.0</TargetFramework> <AssemblyName>OpenTouryo.Public.Security</AssemblyName> <RootNamespace>Touryo.Infrastructure.Public.Security</RootNamespace> - <Version>3.0.0.0</Version> - <Company>Hitachi Solutions</Company> + <Version>$(OpenTouryoVersion)</Version> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> @@ -38,9 +37,8 @@ <ItemGroup> <PackageReference Include="BouncyCastle.NetCore" Version="2.2.1" /> - <PackageReference Include="jose-jwt" Version="5.1.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> - <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.4" /> + <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.18" /> </ItemGroup> <ItemGroup> diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Security/SymmetricCryptography.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Security/SymmetricCryptography.cs index 2942cfca1..03a4e7aca 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Security/SymmetricCryptography.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Security/SymmetricCryptography.cs @@ -1,4 +1,4 @@ -//********************************************************************************** +//********************************************************************************** //* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. //********************************************************************************** @@ -41,6 +41,7 @@ //* 2018/10/30 西野 大介 各種プロバイダのサポートを追加 //* 2018/10/30 西野 大介 CipherMode, PaddingMode指定の追加(CipherModeによってはIVを無視する)。 //* 2018/11/09 西野 大介 インスタンス・メソッド化 +//* 2026/08/10 玄人 幸道 CipherMode_ECB 非推奨化に伴う CS0618 の抑止(CodeQL 対応) //********************************************************************************** using System; @@ -282,10 +283,14 @@ private SymmetricAlgorithm CreateSymmetricAlgorithm(EnumSymmetricAlgorithm esa) { cm = CipherMode.CTS; } + // CipherMode_ECB は非推奨だが、指定された場合は従来どおり動作させる(下位互換)。 + // 参照するだけで CS0618 が出るため、この分岐に限って抑止する。 +#pragma warning disable CS0618 else if (esa.HasFlag(EnumSymmetricAlgorithm.CipherMode_ECB)) { cm = CipherMode.ECB; } +#pragma warning restore CS0618 else if (esa.HasFlag(EnumSymmetricAlgorithm.CipherMode_OFB)) { cm = CipherMode.OFB; diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Util/ArrayOperator.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Util/ArrayOperator.cs index 7750e2548..ecf5dd0b1 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Util/ArrayOperator.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Util/ArrayOperator.cs @@ -28,6 +28,8 @@ //* 日時 更新者 内容 //* ---------- ---------------- ------------------------------------------------- //* 2019/05/28 西野 大介 新規作成(分割 +//* 2026/08/06 玄人 幸道 GetLongFromByteのシフト量の誤りを修正(#522) +//* 2026/08/06 玄人 幸道 GetLongFromByteをシフト演算に変更・引数検査を追加(#522) //********************************************************************************** using System; @@ -117,32 +119,41 @@ public static byte[] ShortenByteArray(byte[] bytes, int newSize) /// <summary>バイトデータを数値(Int64)データに変換</summary> /// <param name="bytes">バイトデータ(byte[](8 byte以内))</param> /// <returns>数値(Int64)データ</returns> + /// <remarks> + /// ビッグ エンディアンとして解釈する(先頭のバイトが上位)。 + /// + /// 2026/08/06 まで、桁の重みを 256 * j(掛け算)で求めていたため、 + /// 3 byte 目以降が誤った値になっていた(#522)。 + /// ・1〜2 byte … 256 * 1 == 256 ^ 1 のため、たまたま正しかった + /// ・3 byte 目 … 512 になっていた(正しくは 65536) + /// 呼び出し元の CheckCharCode は Shift_JIS の 1〜2 byte にしか使わないため + /// 影響は無かったが、public なので誤りは誤りとして直した。 + /// + /// **掛け算ではなくシフトで積むこと。** 8 byte 目の重み(256 ^ 7)を掛ける方式は、 + /// 最上位ビットが立つと Int64 の範囲を超えるため、checked ビルドでは例外になる。 + /// シフト演算は checked の影響を受けないので、この差が出ない。 + /// + /// なお 8 byte で最上位ビットが立つ場合の戻り値は負になる + /// (2 の補数として解釈した値。BitConverter.ToInt64 と同じ考え方)。 + /// </remarks> public static long GetLongFromByte(byte[] bytes) { - long rtnCode = 0; - - if (bytes.Length <= 0) + if (bytes == null) { - // bytData.Length <= 0(ArgumentOutOfRangeException - throw new ArgumentOutOfRangeException("bytData"); + throw new ArgumentNullException(nameof(bytes)); } - else if (bytes.Length <= 8) - { - int j = 0; // 256 ( = 8 bit、= 1 byte) - for (int i = bytes.Length - 1; i >= 0; i--) - { - // 数値化→bitシフト→加算。 - int bitShift = 256 * j; - if (bitShift == 0) bitShift = 1; - rtnCode += Convert.ToInt32(bytes[i]) * bitShift; - j++; // 8 bit シフトする。 - } + if (bytes.Length == 0 || 8 < bytes.Length) + { + throw new ArgumentOutOfRangeException(nameof(bytes)); } - else + + long rtnCode = 0; + + for (int i = 0; i < bytes.Length; i++) { - // 8 < bytData(ArgumentOutOfRangeException - throw new ArgumentOutOfRangeException("bytData"); + // 8 bit シフトして下位に積む(先頭のバイトが上位になる)。 + rtnCode = (rtnCode << 8) | bytes[i]; } // 戻す diff --git a/root/programs/CS/Frameworks/Infrastructure/Public/Util/GetConfigParameter.cs b/root/programs/CS/Frameworks/Infrastructure/Public/Util/GetConfigParameter.cs index b2367aae8..97332059f 100644 --- a/root/programs/CS/Frameworks/Infrastructure/Public/Util/GetConfigParameter.cs +++ b/root/programs/CS/Frameworks/Infrastructure/Public/Util/GetConfigParameter.cs @@ -36,6 +36,11 @@ //* ※ JSONキーの「:」を「__」で処理する。 //* GetAnyConfigSectionメソッドでコンテナ・モードに対応しない。 //* ※ コンテナ・モードでは、セクションを返せない。 +//* 2026/08/01 玄人 幸道 appsettings.jsonの読込基点を、currentディレクトリから +//* AppContext.BaseDirectory(EXEの配置フォルダ)に変更した。 +//* ※ app.configと同じ挙動に揃え、CLIのカレント依存を解消する。 +//* 2026/08/01 玄人 幸道 埋め込まれたリソースから初期化するオーバーロードを追加した。 +//* ※ PublishSingleFile(単一ファイル発行)への対応。 //********************************************************************************** #if (NETSTD || NETCOREAPP) @@ -86,27 +91,60 @@ public static void InitConfiguration(IConfigurationBuilder builder) /// <summary>IConfigurationの初期化</summary> /// <param name="jsonFileName">string</param> + /// <remarks> + /// jsonFileNameに絶対パスを指定した場合は、そのパスが優先される。 + /// </remarks> public static void InitConfiguration(string jsonFileName) { IConfigurationBuilder builder = new ConfigurationBuilder(); - // currentディレクトリのappsettings.jsonを読み込む。 + // ↓↓↓【変更】↓↓↓ + // EXEの配置フォルダのappsettings.jsonを読み込む。 + // 以前はcurrentディレクトリを基点にしていたが、CLIは任意のカレント + // ディレクトリから起動されるため、読み込みに失敗することがあった。 + // ※ app.config(<exe名>.exe.config)と同じ、EXEの隣を見る挙動に揃えている。 + // ※ AppContext.BaseDirectoryは、PublishSingleFile(単一ファイル発行)でも + // 正しい値を返す(Assembly.Locationは空文字になるため使用しない)。 builder = builder - .SetBasePath(Directory.GetCurrentDirectory()) + .SetBasePath(AppContext.BaseDirectory) .AddJsonFile(jsonFileName); + // ↑↑↑【変更】↑↑↑ GetConfigParameter._configuration = builder.Build(); } + // ↓↓↓【追加】↓↓↓ + + /// <summary>IConfigurationの初期化(埋め込まれたリソース)</summary> + /// <param name="jsonStream">Stream</param> + /// <remarks> + /// PublishSingleFile(単一ファイル発行)などで、appsettings.jsonを + /// EXEの隣に配置できない場合に使用する。 + /// EmbeddedResourceLoader.LoadAsStreamの戻り値を渡す。 + /// </remarks> + public static void InitConfiguration(Stream jsonStream) + { + IConfigurationBuilder builder = new ConfigurationBuilder(); + + // 埋め込まれたリソースのappsettings.jsonを読み込む。 + builder = builder.AddJsonStream(jsonStream); + + GetConfigParameter._configuration = builder.Build(); + } + + // ↑↑↑【追加】↑↑↑ + /// <summary>IConfigurationの初期化</summary> public static void InitConfiguration() { IConfigurationBuilder builder = new ConfigurationBuilder(); - // currentディレクトリのappsettings.jsonを読み込む。 + // ↓↓↓【変更】↓↓↓ + // EXEの配置フォルダのappsettings.jsonを読み込む(理由は上記と同じ)。 builder = builder - .SetBasePath(Directory.GetCurrentDirectory()) + .SetBasePath(AppContext.BaseDirectory) .AddJsonFile("appsettings.json"); + // ↑↑↑【変更】↑↑↑ #region 参考:メモリ内プロバイダによる POCO クラスとのバインディング diff --git a/root/programs/CS/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/Web.config b/root/programs/CS/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/Web.config index cffbde75d..15575de49 100644 --- a/root/programs/CS/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/Web.config +++ b/root/programs/CS/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/Web.config @@ -188,4 +188,13 @@ </dependentAssembly> </assemblyBinding> </runtime> + <system.webServer> + <httpProtocol> + <customHeaders> + <!-- クリックジャッキング対策(CodeQL: Missing X-Frame-Options HTTP header)。 + SOAP の Web サービスであり、フレームに表示する用途がないため DENY。 --> + <add name="X-Frame-Options" value="DENY" /> + </customHeaders> + </httpProtocol> + </system.webServer> </configuration> diff --git a/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/Result48.txt b/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/Result48.txt index 6d53435aa..74fa2763a 100644 --- a/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/Result48.txt +++ b/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/Result48.txt @@ -82,8 +82,8 @@ JWS_RS256_X509.Verify > True JWS_RS256_Param.Verify > True jWS_RS384_XML.Create > JWS Header: {"alg":"RS384","typ":"JWT"} jWS_RS384_XML.Create > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -jWS_RS384_XML.Create > JWS Signature: GYtiAAj6L44GHM2qypvONV8lNM2OPtwrTnfYD6j5Q9lyIHWP6h0iK9bp3TNno_-A63xosowbWK3IuyMx1FKsu2IqLiyjjBwp7jsE8UbOlPF2usFizii_5hgiVYVAXos7A0VdbTs8A0bINjGjh4cH3yPAXzHKsD4-6hYANWilod8 -RSA JWK > {"kty":"RSA","alg":"RS384","n":"vBRhj9ifBc_zAm5kkH9KOMKf1m_xrbXpkaMsFw_ZZtl3kD-fQzquUd04E7-OAbbe5xj4W1O_ec2w4ODqdcZGeD4vCqr9aiO04a3iPyncdPq07in2Va_gUa8VGJZPrOv25tt2vDvLeY9gs4COgPpvem39kgBaPSrdZ5wi6t8P3TE","e":"AQAB","kid":"ckOA08yMty7xvdwDUtRWO28qoilvZssjrj41DONhyGOT6FY5aN-nLsTp02_Co08c"} +jWS_RS384_XML.Create > JWS Signature: pVCX4l5AdgGPPMoYdilq0y0XtCfJ-mkiIdVWz8JI8azMxkoxMFHEbWHv5aObx4sZtCtccFrfUO1gOCgujLEEphye_88-EpO2GeXi6q0yboWrqRQYLwd4NoSvMuXQR1EGKZYK4PlbGUYEpC_g64w3OdvB-fKIv3NBq4fxFItL9nY +RSA JWK > {"kty":"RSA","alg":"RS384","n":"ySzPEwmS7hNOEvyKIMOu-Ffx2UzUtzv_hiVLeDYgdlrLeGh8MGed-rGUlfh_j44Z1UPCPoG0eyGFXjLfo553ny0TtoonmzybxNOZo9euXFyXAWKXO118YnmDW2hNODBOIhycKXCCQSL2xB3yNx5XoKpwRtvl5swyxkcQQ56qMS0","e":"AQAB","kid":"awxeCJpMBPEw5G5psPr7LgmKBfudVEcneY42q2XcqaCK-U029Xzahks0gQNhsPMv"} JWS_RS384_XML.Verify > True JWS_RS384_Param.Verify > True JWS_RS512_X509.Create > JWS Header: {"alg":"RS512","typ":"JWT"} @@ -94,54 +94,54 @@ JWS_RS512_X509.Verify > True JWS_RS512_Param.Verify > True JWS_ES256_X509.Create > JWS Header: {"alg":"ES256","typ":"JWT"} JWS_ES256_X509.Create > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JWS_ES256_X509.Create > JWS Signature: bDS8uIGDfDIuYcOOiEbl0GsEVSUNSl22y1vXERK_KbORH2VdJVdULkxkBXw15fMfRrGYUQkVWwlKW3EdkQ1rPg +JWS_ES256_X509.Create > JWS Signature: 6fp4-RyBzFTloznyxPUq31IU46GQOnP1x_RLlfIK_6ct3WbwV00mYYGMYNcdyhD0qipu5sWuavLWwwLsuP87Zw ECDSA JWK > {"kty":"EC","alg":"ES256","crv":"P-256","x":"qdS3bsts3UXi5p0G71GofUB9ls1fJz_z0dRQw9RZ99A","y":"hX6HISTIiDLt90VDEqGmsMj2kSlGLOcXgXSqz75EhV4","kid":"asm1SGqVczG7zj0saZPKiggv2xwRlb6c23CDCNBqBNA"} JWS_ES256_X509.Verify > True JWS_ES256_Param.Verify > True -JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.bDS8uIGDfDIuYcOOiEbl0GsEVSUNSl22y1vXERK_KbORH2VdJVdULkxkBXw15fMfRrGYUQkVWwlKW3EdkQ1rPg +JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.6fp4-RyBzFTloznyxPUq31IU46GQOnP1x_RLlfIK_6ct3WbwV00mYYGMYNcdyhD0qipu5sWuavLWwwLsuP87Zw JwsAlgorithm.xLibTest > JWS Header: {"alg":"ES256","typ":"JWT"} JwsAlgorithm.xLibTest > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.xLibTest > JWS Signature: bDS8uIGDfDIuYcOOiEbl0GsEVSUNSl22y1vXERK_KbORH2VdJVdULkxkBXw15fMfRrGYUQkVWwlKW3EdkQ1rPg +JwsAlgorithm.xLibTest > JWS Signature: 6fp4-RyBzFTloznyxPUq31IU46GQOnP1x_RLlfIK_6ct3WbwV00mYYGMYNcdyhD0qipu5sWuavLWwwLsuP87Zw JwsAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JWS_ES384_X509.Create > JWS Header: {"alg":"ES384","typ":"JWT"} JWS_ES384_X509.Create > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JWS_ES384_X509.Create > JWS Signature: Mqm-d-FC7NZ9bniVD9UYcnMJe5pJB-Hi_Kff18AyZ068k3aDac_Rb8ijEXf0TYJLTrbl-E6ToPpgfK7N0VZxPy1sFMygZDAIi_D40jwTFqJXmaplMFhAnt6bACQG7mby +JWS_ES384_X509.Create > JWS Signature: m13RGTk7jeWjidTwCFwvodOztKPTB4v7svipMHh49nAcAt2BffD7ID19hg_sLerM3H2fMZIq_Wd7B0YqKwdugifl9w9oYuNDfEAx6cN6U6nOWvnhiMr0pOJ6SPLcpGeP JWS_ES384_X509.Verify > True ECDSA JWK > {"kty":"EC","alg":"ES384","crv":"P-384","x":"qeyd2iMw8DZT7Yy3KO0mOuok1JBBdMwEuJTa81Upg06fbVbotK8yuhDSVkzSFsw3","y":"thH6faasSDmEO4zeVNdc5LbZJprQmL7JN3NZzYUJmF1GhQEl6QaZh-6f1QhDH0St","kid":"e_kI1ZJ_x9ttzEU_DICgGhJeNK8ghcW3bSl7KFM6eVefpKJHA5ecCowzJw69r9Vr"} JWS_ES384_X509.Verify > True JWS_ES384_Param.Verify > False -JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.Mqm-d-FC7NZ9bniVD9UYcnMJe5pJB-Hi_Kff18AyZ068k3aDac_Rb8ijEXf0TYJLTrbl-E6ToPpgfK7N0VZxPy1sFMygZDAIi_D40jwTFqJXmaplMFhAnt6bACQG7mby +JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.m13RGTk7jeWjidTwCFwvodOztKPTB4v7svipMHh49nAcAt2BffD7ID19hg_sLerM3H2fMZIq_Wd7B0YqKwdugifl9w9oYuNDfEAx6cN6U6nOWvnhiMr0pOJ6SPLcpGeP JwsAlgorithm.xLibTest > JWS Header: {"alg":"ES384","typ":"JWT"} JwsAlgorithm.xLibTest > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.xLibTest > JWS Signature: Mqm-d-FC7NZ9bniVD9UYcnMJe5pJB-Hi_Kff18AyZ068k3aDac_Rb8ijEXf0TYJLTrbl-E6ToPpgfK7N0VZxPy1sFMygZDAIi_D40jwTFqJXmaplMFhAnt6bACQG7mby +JwsAlgorithm.xLibTest > JWS Signature: m13RGTk7jeWjidTwCFwvodOztKPTB4v7svipMHh49nAcAt2BffD7ID19hg_sLerM3H2fMZIq_Wd7B0YqKwdugifl9w9oYuNDfEAx6cN6U6nOWvnhiMr0pOJ6SPLcpGeP JwsAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JWS_ES512_X509.Create > JWS Header: {"alg":"ES512","typ":"JWT"} JWS_ES512_X509.Create > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JWS_ES512_X509.Create > JWS Signature: AJxgTQH_qS55UyUyYSrNG1G5bfnU_g8qto77lsWSLRSqgGzK5aIhYz1jBx3doDJTEmDthiB7Ane52TvOnj_XnIIIAG-iGaMKlEEbyS0S6esD7pRcp7wUuAp1iZt-GTY9d_xN1wKayxJPw-T2H7fXGzq8YgF2doLvP5YSdIHiLzYm4n9E +JWS_ES512_X509.Create > JWS Signature: ALN6BlxWMVKND7wTgCgBrEuWNsrM0LB2pIGjQ5YoLjo9MPmDhjCsDS0b9J8flxFByFHH7iuz93wa52-nuFnVlT0lABikCBRYJULIDZRQxOaQSbBbPSpzk2R6qQ0uaPVHUbGkNQ6j68vAdd6Rmm1DTbHNTpUfu7oTVzPfZzFduglDFrPY JWS_ES512_X509.Verify > True ECDSA JWK > {"kty":"EC","alg":"ES512","crv":"P-521","x":"AQoRdSDzXLfin6CFhLxDOL0_Cfn-QcwgdbMkMGgwTeA4gDIygCOEy4m0eyTmEnjYdBOMN5JtYUiprdZZriAGzrHC","y":"ATj5JBej9ztfsArJLUMCs4edyCgPuItefh7KFGfeefI7YjB-pakcKxzhHZ1h2UhR183bnQ4rrXc71N5WAl3d5BqZ","kid":"OaO51pUD4-aJ8skED2eag0nvd1kfqIwo9BhB86PEZ34PBLE4TiHv6v9LCK20r0c6x06bULLSi84PcldSN2n6DQ"} JWS_ES512_X509.Verify > True JWS_ES512_Param.Verify > False -JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.AJxgTQH_qS55UyUyYSrNG1G5bfnU_g8qto77lsWSLRSqgGzK5aIhYz1jBx3doDJTEmDthiB7Ane52TvOnj_XnIIIAG-iGaMKlEEbyS0S6esD7pRcp7wUuAp1iZt-GTY9d_xN1wKayxJPw-T2H7fXGzq8YgF2doLvP5YSdIHiLzYm4n9E +JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.ALN6BlxWMVKND7wTgCgBrEuWNsrM0LB2pIGjQ5YoLjo9MPmDhjCsDS0b9J8flxFByFHH7iuz93wa52-nuFnVlT0lABikCBRYJULIDZRQxOaQSbBbPSpzk2R6qQ0uaPVHUbGkNQ6j68vAdd6Rmm1DTbHNTpUfu7oTVzPfZzFduglDFrPY JwsAlgorithm.xLibTest > JWS Header: {"alg":"ES512","typ":"JWT"} JwsAlgorithm.xLibTest > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.xLibTest > JWS Signature: AJxgTQH_qS55UyUyYSrNG1G5bfnU_g8qto77lsWSLRSqgGzK5aIhYz1jBx3doDJTEmDthiB7Ane52TvOnj_XnIIIAG-iGaMKlEEbyS0S6esD7pRcp7wUuAp1iZt-GTY9d_xN1wKayxJPw-T2H7fXGzq8YgF2doLvP5YSdIHiLzYm4n9E +JwsAlgorithm.xLibTest > JWS Signature: ALN6BlxWMVKND7wTgCgBrEuWNsrM0LB2pIGjQ5YoLjo9MPmDhjCsDS0b9J8flxFByFHH7iuz93wa52-nuFnVlT0lABikCBRYJULIDZRQxOaQSbBbPSpzk2R6qQ0uaPVHUbGkNQ6j68vAdd6Rmm1DTbHNTpUfu7oTVzPfZzFduglDFrPY JwsAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JWE_RsaOaepAesGcm_X509.Decrypt > True : {"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.xLibTest > Original:eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJ0eXAiOiJKV1QifQ.QzqiUMQh1bbmG8As9A4s0XXsMUR27oj5IJ8aazVZAWc2yf9F3BfCQaFR8M2Mcwglr9SXTgcBqJSgGItFgXiSt7UEtey06ubImo9gAp9BgcQmQTjsVTBHW5VWLJH23jnOCDl_XmqqE_Aqb992QvpiKdrgnvTg4qlyFymtJxU_xlcfsL8B5JqApiTQBPj96J7ta9vgZQx7tFOh23jGS5kt-7onNWs7NLOPVVM1wtEh4a49JLQl9gLfocMGnV9q_X2CEq-35XIe8dkfX_BsSh50YvMlbRSTCCmiGnumsMF77v_22WakHtFqsgEiNq7ZWXhaSKPLe-rVXaikkzUbtn8Mnw.p5ht61WtDaG_z9si.Hr2vtD16A9_rQDBn1F8kMp2OCsByvZXxF_4GAOvFugkwTnbOi1h_AJdtjg.3zK5dgHR3hZB4l5I2tTmFg +JweAlgorithm.xLibTest > Original:eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJ0eXAiOiJKV1QifQ.gL-45uRuTs_AoJifcJ4BYiQdvwFDUastt2tMkc91UGfBu-Ql3Ai2oyugKOFSDUyR9kRdr4CqUMdvcpD37QpmeJYhls1xFF3rCdz9fO6jVS75JjsGjfTmfSoxDVTnhW2Z9fZMjc4OWXsd6UvnLykwq61Nm7QRw6XvOI3mfvZhQa6cEw5cZa8UGfmhsLmu3y9MH8wTjcZMAfmvOI7rDT2geNMkrXLNPyZeabg9j9--VHLJGmtb4P0RfTl78_zMnHxN1M14A743QfAdYs5_ZdSwRgjkOOiZleYdmBzyDbFFsgTjnsxHNDGzp1-p_fMC3uq3rh3QfecNUhrKj5ONpr19AA.DTQWDiR8VswdIDAC.sxQEj_GWlLnIcvz2ezeRInMUTDQh8ixX0Yuc6JnY7JeiQwHXI_4ZhvPSKA.ws5zhj8OrAqqBsbeNjAvLg JweAlgorithm.xLibTest > JWE Header: {"alg":"RSA-OAEP","enc":"A256GCM","typ":"JWT"} -JweAlgorithm.xLibTest > JWE Encrypted Key: QzqiUMQh1bbmG8As9A4s0XXsMUR27oj5IJ8aazVZAWc2yf9F3BfCQaFR8M2Mcwglr9SXTgcBqJSgGItFgXiSt7UEtey06ubImo9gAp9BgcQmQTjsVTBHW5VWLJH23jnOCDl_XmqqE_Aqb992QvpiKdrgnvTg4qlyFymtJxU_xlcfsL8B5JqApiTQBPj96J7ta9vgZQx7tFOh23jGS5kt-7onNWs7NLOPVVM1wtEh4a49JLQl9gLfocMGnV9q_X2CEq-35XIe8dkfX_BsSh50YvMlbRSTCCmiGnumsMF77v_22WakHtFqsgEiNq7ZWXhaSKPLe-rVXaikkzUbtn8Mnw -JweAlgorithm.xLibTest > JWE Initialization Vector: p5ht61WtDaG_z9si -JweAlgorithm.xLibTest > JWE Ciphertext: Hr2vtD16A9_rQDBn1F8kMp2OCsByvZXxF_4GAOvFugkwTnbOi1h_AJdtjg -JweAlgorithm.xLibTest > JWE Authentication Tag: 3zK5dgHR3hZB4l5I2tTmFg +JweAlgorithm.xLibTest > JWE Encrypted Key: gL-45uRuTs_AoJifcJ4BYiQdvwFDUastt2tMkc91UGfBu-Ql3Ai2oyugKOFSDUyR9kRdr4CqUMdvcpD37QpmeJYhls1xFF3rCdz9fO6jVS75JjsGjfTmfSoxDVTnhW2Z9fZMjc4OWXsd6UvnLykwq61Nm7QRw6XvOI3mfvZhQa6cEw5cZa8UGfmhsLmu3y9MH8wTjcZMAfmvOI7rDT2geNMkrXLNPyZeabg9j9--VHLJGmtb4P0RfTl78_zMnHxN1M14A743QfAdYs5_ZdSwRgjkOOiZleYdmBzyDbFFsgTjnsxHNDGzp1-p_fMC3uq3rh3QfecNUhrKj5ONpr19AA +JweAlgorithm.xLibTest > JWE Initialization Vector: DTQWDiR8VswdIDAC +JweAlgorithm.xLibTest > JWE Ciphertext: sxQEj_GWlLnIcvz2ezeRInMUTDQh8ixX0Yuc6JnY7JeiQwHXI_4ZhvPSKA +JweAlgorithm.xLibTest > JWE Authentication Tag: ws5zhj8OrAqqBsbeNjAvLg JweAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JWE_Rsa15A128CbcHS256_X509.Decrypt > True : {"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.xLibTest > Original:eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidHlwIjoiSldUIn0.AbOg32Wq4VUypLhrYFe9ibRCUFV89I0mlK5W8U9kTiyifX6OGuYqhSDYzSlznhva3TWkiq4nYrKU-7Ke9JV3sQu_02r5YP1kymko7h-511AOWg7cSgfMLCMbMZNBSwi5DMZq4YZSvSCtdEyLR0qGTolPJ5B1mzrBuSqrGHR7YIJfdD7ppDyt6Ovb1zgMJ-9q3eQ-GTYcsz9sM8oe7V8_g3YgzpslUQRYoUS8n_Clrv4lJQvNxQkJBoAUU_u2OLkV77LpiThnYCGxyYIlzEHchMZyVH0NMf6A_GwEljo_hl0xt_nLPZjcargsA0GOkVnudsMDsvmArND2fvGhgihyVg.1cv_E7mfMc3aDY_c62IorQ.zwZqEErqyU4ykynxzXTkv_12UW4C7A4lP-PWV9DhPxr655vhi8jVEemLMMkpyxFf.zaQQjMyTDimHUC0aEcDLcA +JweAlgorithm.xLibTest > Original:eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidHlwIjoiSldUIn0.bcO3nu_1HhxZbfCSWVr7OwXFW0WCtxLOsV_E7Xs5_fyLk08-y0Zx5MXYk3K2xZ6LltxiosyDPzwJeuTbpscdLrUobuLKqGTcyvS5n_lEUdXdhO32GaDU7i4HhR7ZL778YtBlxs6wW5RNi-z44a9dcedWWJzGE4VunuDcQ_Cs-nAtmHxNhOSnT-FSidFPKfQp6noF7EcHdRIrDP_N8QxeEdyFKNjvdf40En8mop7p7zZEYyot5hbX2snjR4y8dU-QYuVbxXLmJYnW7J88nhzDorANdD9Ybu-0aRhSXB54eo2iumJyb1xELHuiPwq63t5iK3e4Fg08rFMLdJX055uMNQ.VKms2fp2oORdsuxRmytOVg.QdgjysnUkqTWh5I9jqORz8UNCbBj7TFu0zj9mLM-q-6jP090snFnijsIy3lfFxwQ.Cvgix0BFKtAfAXzlmQdLkg JweAlgorithm.xLibTest > JWE Header: {"alg":"RSA1_5","enc":"A128CBC-HS256","typ":"JWT"} -JweAlgorithm.xLibTest > JWE Encrypted Key: AbOg32Wq4VUypLhrYFe9ibRCUFV89I0mlK5W8U9kTiyifX6OGuYqhSDYzSlznhva3TWkiq4nYrKU-7Ke9JV3sQu_02r5YP1kymko7h-511AOWg7cSgfMLCMbMZNBSwi5DMZq4YZSvSCtdEyLR0qGTolPJ5B1mzrBuSqrGHR7YIJfdD7ppDyt6Ovb1zgMJ-9q3eQ-GTYcsz9sM8oe7V8_g3YgzpslUQRYoUS8n_Clrv4lJQvNxQkJBoAUU_u2OLkV77LpiThnYCGxyYIlzEHchMZyVH0NMf6A_GwEljo_hl0xt_nLPZjcargsA0GOkVnudsMDsvmArND2fvGhgihyVg -JweAlgorithm.xLibTest > JWE Initialization Vector: 1cv_E7mfMc3aDY_c62IorQ -JweAlgorithm.xLibTest > JWE Ciphertext: zwZqEErqyU4ykynxzXTkv_12UW4C7A4lP-PWV9DhPxr655vhi8jVEemLMMkpyxFf -JweAlgorithm.xLibTest > JWE Authentication Tag: zaQQjMyTDimHUC0aEcDLcA +JweAlgorithm.xLibTest > JWE Encrypted Key: bcO3nu_1HhxZbfCSWVr7OwXFW0WCtxLOsV_E7Xs5_fyLk08-y0Zx5MXYk3K2xZ6LltxiosyDPzwJeuTbpscdLrUobuLKqGTcyvS5n_lEUdXdhO32GaDU7i4HhR7ZL778YtBlxs6wW5RNi-z44a9dcedWWJzGE4VunuDcQ_Cs-nAtmHxNhOSnT-FSidFPKfQp6noF7EcHdRIrDP_N8QxeEdyFKNjvdf40En8mop7p7zZEYyot5hbX2snjR4y8dU-QYuVbxXLmJYnW7J88nhzDorANdD9Ybu-0aRhSXB54eo2iumJyb1xELHuiPwq63t5iK3e4Fg08rFMLdJX055uMNQ +JweAlgorithm.xLibTest > JWE Initialization Vector: VKms2fp2oORdsuxRmytOVg +JweAlgorithm.xLibTest > JWE Ciphertext: QdgjysnUkqTWh5I9jqORz8UNCbBj7TFu0zj9mLM-q-6jP090snFnijsIy3lfFxwQ +JweAlgorithm.xLibTest > JWE Authentication Tag: Cvgix0BFKtAfAXzlmQdLkg JweAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JwsAlgorithm.none > eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ. JwsAlgorithm.HS256 > Original:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.dvd5Ak6zcBy0OB7gxVtehT3Ab5NO7XEggon6r_CTSfE @@ -149,75 +149,75 @@ JwsAlgorithm.HS256 > JWS Header: {"alg":"HS256","typ":"JWT"} JwsAlgorithm.HS256 > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} JwsAlgorithm.HS256 > JWS Signature: dvd5Ak6zcBy0OB7gxVtehT3Ab5NO7XEggon6r_CTSfE JwsAlgorithm.HS256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.RS256 > Original:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.dCnfv92uWPC6q3quXU_a_fYPjZQreuNQIpFx5Qc1k61F_sQch8aNafx_SOP5vIm_eSaqKQSpg7f4BukGAvDMCBTTRANJvj4olE7nhEgzD3jmuvEcrovcM6c3Q6C7oTdNVCDZSRvluiI7rKLgFuLq1iQfTJdX_jPxOIkyO7VR8kA +JwsAlgorithm.RS256 > Original:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.zMhBg9-IeEAJ7JF05B0QWhV-TTaxTY4339FTUdvR8m3F3pMc-NcsWNnC4Ub3TUt4_r1_-jhrCWUnVJvqjHg88Jvbvdj2tqIH_dlcfazCLJucGUyEe7DAfA3Izw3LDvPTu6U6bAVi18o8a7FFvngGaj4RoTL6DBcDZAT6fpJwM0g JwsAlgorithm.RS256 > JWS Header: {"alg":"RS256","typ":"JWT"} JwsAlgorithm.RS256 > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.RS256 > JWS Signature: dCnfv92uWPC6q3quXU_a_fYPjZQreuNQIpFx5Qc1k61F_sQch8aNafx_SOP5vIm_eSaqKQSpg7f4BukGAvDMCBTTRANJvj4olE7nhEgzD3jmuvEcrovcM6c3Q6C7oTdNVCDZSRvluiI7rKLgFuLq1iQfTJdX_jPxOIkyO7VR8kA +JwsAlgorithm.RS256 > JWS Signature: zMhBg9-IeEAJ7JF05B0QWhV-TTaxTY4339FTUdvR8m3F3pMc-NcsWNnC4Ub3TUt4_r1_-jhrCWUnVJvqjHg88Jvbvdj2tqIH_dlcfazCLJucGUyEe7DAfA3Izw3LDvPTu6U6bAVi18o8a7FFvngGaj4RoTL6DBcDZAT6fpJwM0g JwsAlgorithm.RS256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.ES256 > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.5sjTJ18OthXG2r7iWeuwX5F63oyMTYmHYEhTWaDnsZNbiImVfoMsv9m4ovocZmzeJRIuHnxokyEd1sHBtrSAog +JwsAlgorithm.ES256 > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.V8yKzhTZuQBQ-Cd5NLzMR0sTJYMvPvFlfotKZ3yANYoSyuiZLr34gC93ws80sfCd82BEmd0mbvE4lppkkfuMtQ JwsAlgorithm.ES256 > JWS Header: {"alg":"ES256","typ":"JWT"} JwsAlgorithm.ES256 > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.ES256 > JWS Signature: 5sjTJ18OthXG2r7iWeuwX5F63oyMTYmHYEhTWaDnsZNbiImVfoMsv9m4ovocZmzeJRIuHnxokyEd1sHBtrSAog +JwsAlgorithm.ES256 > JWS Signature: V8yKzhTZuQBQ-Cd5NLzMR0sTJYMvPvFlfotKZ3yANYoSyuiZLr34gC93ws80sfCd82BEmd0mbvE4lppkkfuMtQ JwsAlgorithm.ES256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.ES256 > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.y9GTdsHGsPJwZbBXI54d1J-AFfpRmcxIEeJ7KqlyPyehkGS0p3h9OIyXJL67Nykg1IFPFkkk6cSI6aEpzRf36g +JwsAlgorithm.ES256 > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.MpQ-70bqvcSeIWjydh-AlkI63Gg4fk3OQ3NlsObLVF5nW_YsGZ9bAtrk0oe0K1Sw-gVbPeH8_3IfXNbn9u9FlA JwsAlgorithm.ES256 > JWS Header: {"alg":"ES256","typ":"JWT"} JwsAlgorithm.ES256 > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.ES256 > JWS Signature: y9GTdsHGsPJwZbBXI54d1J-AFfpRmcxIEeJ7KqlyPyehkGS0p3h9OIyXJL67Nykg1IFPFkkk6cSI6aEpzRf36g +JwsAlgorithm.ES256 > JWS Signature: MpQ-70bqvcSeIWjydh-AlkI63Gg4fk3OQ3NlsObLVF5nW_YsGZ9bAtrk0oe0K1Sw-gVbPeH8_3IfXNbn9u9FlA JwsAlgorithm.ES256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > Original:eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.Y-Z-EuZU8migC37s312S2qyiLYHuT3e5SD4aswf9FKGtQ35V2OcsY4DqS1TRk8RF5e_YjHMAbXNz8heBNYmspx9PU8tJvAVfWrJhRvvt_SO0jpv7YD-HweQLAGMbE2WWGFrSFDWIJO2Hbijy4xKXqy920U1OrfK02rW-sOtNAXoCGrSV3WQd5eEUV4Z0gF16V3RiO33xtc6Gqy8kmSHSVdC7ThhUVhxGygbAZBbGdnq45iWj-SLD3l143nthn_6I51DKxuzrxTI8rnRFqgCiyrFXRYDJ4haLdg9vkMUg65WjE9OpUo2CD5TqzeW01K2_l5gvo3i_rV54TWWi0wld7Q.O6p_BYf5ETk6OXMPzLArpw.IxCHmLYKCg9DWcXIVJyzAYQ31efTIeDRH00NcDwdzgDqhE80zcIYm6t2TH88ers1.TtaEl82V_-cfXnI2fPPd2w +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > Original:eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.gZo76u7tvzYKAOSeBEnENoop90w0V4-erGA6MV7aPwPKtLOtVuWT4ZU4VipxnfcignEizIxC-YabwBtxhVNI9mRhIUlVF4mjCWPX5RrUGnXFtMZqQnlGk7FPQ__fzOwDJkt-hKEUD5lvIoC2hFyg9VtilwwvFALVaNMm5UwrsJjaVQhGEucfxQ_sOcuJas5bZDTY4J0I09loCDXNMhviaXNM_5NRVI4k1PVl6F8LP2BjWbwpo0KHEgI0QY5vO7CQELbklHUoP5kdvwnIWrathNIybWwBocOLVgMHfToqG_llWzwR59mfC3OeVdNNGzpzAslE1vxOVN1459XYWspEOw.MCcndGrgqDzqIXn_ialwQw.W685MxTxTwVMxQL9_Z_NFiNHJ1gV8b26Fa_v5Zoi56V4ujeBglhC7UIk3i0TSTZf.s5N8tE8Ng458DN9_v9G65Q JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Header: {"alg":"RSA1_5","enc":"A128CBC-HS256"} -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Encrypted Key: Y-Z-EuZU8migC37s312S2qyiLYHuT3e5SD4aswf9FKGtQ35V2OcsY4DqS1TRk8RF5e_YjHMAbXNz8heBNYmspx9PU8tJvAVfWrJhRvvt_SO0jpv7YD-HweQLAGMbE2WWGFrSFDWIJO2Hbijy4xKXqy920U1OrfK02rW-sOtNAXoCGrSV3WQd5eEUV4Z0gF16V3RiO33xtc6Gqy8kmSHSVdC7ThhUVhxGygbAZBbGdnq45iWj-SLD3l143nthn_6I51DKxuzrxTI8rnRFqgCiyrFXRYDJ4haLdg9vkMUg65WjE9OpUo2CD5TqzeW01K2_l5gvo3i_rV54TWWi0wld7Q -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Initialization Vector: O6p_BYf5ETk6OXMPzLArpw -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Ciphertext: IxCHmLYKCg9DWcXIVJyzAYQ31efTIeDRH00NcDwdzgDqhE80zcIYm6t2TH88ers1 -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Authentication Tag: TtaEl82V_-cfXnI2fPPd2w +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Encrypted Key: gZo76u7tvzYKAOSeBEnENoop90w0V4-erGA6MV7aPwPKtLOtVuWT4ZU4VipxnfcignEizIxC-YabwBtxhVNI9mRhIUlVF4mjCWPX5RrUGnXFtMZqQnlGk7FPQ__fzOwDJkt-hKEUD5lvIoC2hFyg9VtilwwvFALVaNMm5UwrsJjaVQhGEucfxQ_sOcuJas5bZDTY4J0I09loCDXNMhviaXNM_5NRVI4k1PVl6F8LP2BjWbwpo0KHEgI0QY5vO7CQELbklHUoP5kdvwnIWrathNIybWwBocOLVgMHfToqG_llWzwR59mfC3OeVdNNGzpzAslE1vxOVN1459XYWspEOw +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Initialization Vector: MCcndGrgqDzqIXn_ialwQw +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Ciphertext: W685MxTxTwVMxQL9_Z_NFiNHJ1gV8b26Fa_v5Zoi56V4ujeBglhC7UIk3i0TSTZf +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Authentication Tag: s5N8tE8Ng458DN9_v9G65Q JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > Original:eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.IOfHVVGvdIJiMfsRG6L28LVOD0t14-EXFEFLYZrGJiXoRHwoYVnP1IcQOK5Wx28V7AzkZ7zNnKEymrMPedt5nsORo4ctv8LsHX1zS_xFGfB4OB1EfSj5LUaZ0JkKcEyH0aJ7gcyv578hci1gVu-zloTRUb56IgLUUiCi0MkjXVAYocY2wgDeFtiLdgaTP_aIpVEwCOrCjQWDrguyhQzI52O9sa0W7HjV34iAAWFf1eLqx0klp48NOvegHh0hTu1850t3PE9FsCzfNqFclsWHjzRpCzxE2IZCUzXxaHNd79KlaXRhzphJ5OocCvOF7me1GGMEz7XwZRAjft_GPDeEDg.akAAMGRTkDsjmr7x.kOOA9YbIk8oUIe_Yp4EnwSjo-bQm_aVaWO1LNwwzDQexvmmPrIjJOzX-tQ.AzhMl3Kmr_eoiNrZjelA3w +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > Original:eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.lIu5vLbhehBOxmmgozO0ScnYU9uixrB6FCRMbN7xrNgjMw9qzSUfEgnLqcfcqAX_cVFF_5Gilu-PajyMuMsAk87QdP0Ec5VFkxFdy1UqB1PgYzgETDYUOic16-lAp9aLU42QuCO5cFnghM9V1qXxdqH2zW02wNsuHhNH6BE9hsDkspo-nW6iUK3P2uolCueYgq6vMjYYeLUpysInozYPfyRAHwGDGlitVLXP_HJjg7QKumxhhU7fFhRfFkJQp6xzS_NyJXpw1PYZeQX1conUzV6a_dFQxgNSnL7Aq0GkQdwUaD5-N1jUedFE4MXRb09H6wYhk0bo5PPsteVp5hpRdg.8_JBtidPqQ9ql89a.Xl9j8-rJgn6jnXLuoWA7rWQWUnWYISDXwU-G1KvZRfFrvq8OSI6PUNVRCA.kiBTD9HqTr1x4UYc1ng6Qw JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Header: {"alg":"RSA-OAEP","enc":"A256GCM"} -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Encrypted Key: IOfHVVGvdIJiMfsRG6L28LVOD0t14-EXFEFLYZrGJiXoRHwoYVnP1IcQOK5Wx28V7AzkZ7zNnKEymrMPedt5nsORo4ctv8LsHX1zS_xFGfB4OB1EfSj5LUaZ0JkKcEyH0aJ7gcyv578hci1gVu-zloTRUb56IgLUUiCi0MkjXVAYocY2wgDeFtiLdgaTP_aIpVEwCOrCjQWDrguyhQzI52O9sa0W7HjV34iAAWFf1eLqx0klp48NOvegHh0hTu1850t3PE9FsCzfNqFclsWHjzRpCzxE2IZCUzXxaHNd79KlaXRhzphJ5OocCvOF7me1GGMEz7XwZRAjft_GPDeEDg -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Initialization Vector: akAAMGRTkDsjmr7x -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Ciphertext: kOOA9YbIk8oUIe_Yp4EnwSjo-bQm_aVaWO1LNwwzDQexvmmPrIjJOzX-tQ -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Authentication Tag: AzhMl3Kmr_eoiNrZjelA3w +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Encrypted Key: lIu5vLbhehBOxmmgozO0ScnYU9uixrB6FCRMbN7xrNgjMw9qzSUfEgnLqcfcqAX_cVFF_5Gilu-PajyMuMsAk87QdP0Ec5VFkxFdy1UqB1PgYzgETDYUOic16-lAp9aLU42QuCO5cFnghM9V1qXxdqH2zW02wNsuHhNH6BE9hsDkspo-nW6iUK3P2uolCueYgq6vMjYYeLUpysInozYPfyRAHwGDGlitVLXP_HJjg7QKumxhhU7fFhRfFkJQp6xzS_NyJXpw1PYZeQX1conUzV6a_dFQxgNSnL7Aq0GkQdwUaD5-N1jUedFE4MXRb09H6wYhk0bo5PPsteVp5hpRdg +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Initialization Vector: 8_JBtidPqQ9ql89a +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Ciphertext: Xl9j8-rJgn6jnXLuoWA7rWQWUnWYISDXwU-G1KvZRfFrvq8OSI6PUNVRCA +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Authentication Tag: kiBTD9HqTr1x4UYc1ng6Qw JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > Original:eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..gcGPcw6lYQ4-nUCB-I-Q-A.XROkpOO8PEr3IPKGnRWLp3sur6B3SqSogYb_TiUKi1sJuz1KgCIRoGZnZvHH9xCg.GbbV94uHu6Juz9GSW3-2ug +JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > Original:eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..VIiPbHndrN06JobUUZLeXA.nHPX676PqDRcMFVAszIXF2VJJrjYAC7JbSqX4wgHMmwoMEIiv-A1ZArNeeFUmYSo.oymRoLlPO-USs7lfm6GKOA JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Header: {"alg":"dir","enc":"A128CBC-HS256"} JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Encrypted Key: -JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Initialization Vector: gcGPcw6lYQ4-nUCB-I-Q-A -JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Ciphertext: XROkpOO8PEr3IPKGnRWLp3sur6B3SqSogYb_TiUKi1sJuz1KgCIRoGZnZvHH9xCg -JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Authentication Tag: GbbV94uHu6Juz9GSW3-2ug +JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Initialization Vector: VIiPbHndrN06JobUUZLeXA +JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Ciphertext: nHPX676PqDRcMFVAszIXF2VJJrjYAC7JbSqX4wgHMmwoMEIiv-A1ZArNeeFUmYSo +JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Authentication Tag: oymRoLlPO-USs7lfm6GKOA JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.nvzrNLij1eLkzWX9OvZv3lYCcKgxUjP5cqTUdq6SAT5jmB4Y6pdQ-1Gb_6NGJTf6k_AyjQca7cYHlijToocnekneR7dpibAS.wC0BKrRqaaure-mQP8DWuQ.QPL69JM4Nw6_iNlRJu63J8_eiHOVhAB591n2lewNZZlrmTjMeITdU69vuzlZebKZ.nxhdVnuH8G6ZtlPVIvQui2TxOvfuClY3A-sfZjs8aeo +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.SHYvgmLTT1OV2iBxW7Ym5MQaY3LWgyEN4iBWzA2XIOQtuISTboSmEguct0dK8IBZItTPVWEf3qe-8pnLaYbpVmDZ44_yATm9.AKmH3jeOQFCANuuDFbxeNw.-hNWMmdcIiyoFl4CHRR1dMLifOtukAE8gozWQORwa_yavnKmMv7X3_eQuvbq6gp4.mnqMEIhRgPzhiDdKDRxvc0sR-mpfU4h6bOcMD5_Bsl4 JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"A256KW","enc":"A256CBC-HS512"} -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: nvzrNLij1eLkzWX9OvZv3lYCcKgxUjP5cqTUdq6SAT5jmB4Y6pdQ-1Gb_6NGJTf6k_AyjQca7cYHlijToocnekneR7dpibAS -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: wC0BKrRqaaure-mQP8DWuQ -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: QPL69JM4Nw6_iNlRJu63J8_eiHOVhAB591n2lewNZZlrmTjMeITdU69vuzlZebKZ -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: nxhdVnuH8G6ZtlPVIvQui2TxOvfuClY3A-sfZjs8aeo +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: SHYvgmLTT1OV2iBxW7Ym5MQaY3LWgyEN4iBWzA2XIOQtuISTboSmEguct0dK8IBZItTPVWEf3qe-8pnLaYbpVmDZ44_yATm9 +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: AKmH3jeOQFCANuuDFbxeNw +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: -hNWMmdcIiyoFl4CHRR1dMLifOtukAE8gozWQORwa_yavnKmMv7X3_eQuvbq6gp4 +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: mnqMEIhRgPzhiDdKDRxvc0sR-mpfU4h6bOcMD5_Bsl4 JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJBMjU2R0NNS1ciLCJpdiI6IlcwbHQ1T1B0YzB5cHVybzYiLCJ0YWciOiJvMUd0VXR1YjhQTHBKb2I5ekdYVUtnIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.UiTUcWTyHjkxA2khlzfJcEc62t-EHA8QpjeZu_K2xgeSbSSpNWJH9X_XsHYUU1W2aMG9cSMmw77ULxUWZLOUTg.jKUCAdU3VQ9GNECTVL27ug.FkbDex80HqKcsQ-M-HnJsL3VZSq49CkCHrL77VGTlTed7m135Jiy4kHsdgbbQqYL.rcQUTu0zg2oToqtZIS7oKvSlz94gfOaonwbDmNYwrRA -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"A256GCMKW","iv":"W0lt5OPtc0ypuro6","tag":"o1GtUtub8PLpJob9zGXUKg","enc":"A256CBC-HS512"} -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: UiTUcWTyHjkxA2khlzfJcEc62t-EHA8QpjeZu_K2xgeSbSSpNWJH9X_XsHYUU1W2aMG9cSMmw77ULxUWZLOUTg -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: jKUCAdU3VQ9GNECTVL27ug -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: FkbDex80HqKcsQ-M-HnJsL3VZSq49CkCHrL77VGTlTed7m135Jiy4kHsdgbbQqYL -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: rcQUTu0zg2oToqtZIS7oKvSlz94gfOaonwbDmNYwrRA +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJBMjU2R0NNS1ciLCJpdiI6InZGR2xUbHVrdTk2Rm5zbVEiLCJ0YWciOiJuWkRnUlVleHVJTGVOOTF1dWUxQjVnIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.aJ3t9G961LJgFCpTuoJQL01KbFbfp4ovsNDRrGX1zaoOR64VyqXKoIZhURomK9U5CFMDahMXUj-vpi7SW07IGw.pUMdmnyXG0C1vCOjQKhsuA.Bq7_h-63v-i-xSKos1KKa5Xbmwt-L6A-i1HFT5V11GVHeWqFj75C4QK7IgGC5m3D._aHC3ZR0Mi2wVBhKOVWcxDR4HH6kBBkJTENkDOoJ0eE +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"A256GCMKW","iv":"vFGlTluku96FnsmQ","tag":"nZDgRUexuILeN91uue1B5g","enc":"A256CBC-HS512"} +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: aJ3t9G961LJgFCpTuoJQL01KbFbfp4ovsNDRrGX1zaoOR64VyqXKoIZhURomK9U5CFMDahMXUj-vpi7SW07IGw +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: pUMdmnyXG0C1vCOjQKhsuA +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: Bq7_h-63v-i-xSKos1KKa5Xbmwt-L6A-i1HFT5V11GVHeWqFj75C4QK7IgGC5m3D +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: _aHC3ZR0Mi2wVBhKOVWcxDR4HH6kBBkJTENkDOoJ0eE JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > Original:eyJhbGciOiJFQ0RILUVTIiwiZXBrIjp7Imt0eSI6IkVDIiwieCI6IlhEMmJkSDFONmtBRVJURE9pZ3J6M1dwVWdHVUxLTzNMdXJ3QVpnWHoxZ28iLCJ5IjoiREtpdFM5eFQ5Vy1vUW1GUE1OcmgySGlXbDV5Q3NGREdEQWJpaDBBLVdiTSIsImNydiI6IlAtMjU2In0sImVuYyI6IkEyNTZHQ00ifQ..4_YxIEHgT0S3THYo.fgzS9zycj3N3Ts4BNN5kIduq0dxmc-p7FPsxQRsLoPly7bxBjbRZWyMinw.pSS_005rtwkI8zS2ci4RcQ -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Header: {"alg":"ECDH-ES","epk":{"kty":"EC","x":"XD2bdH1N6kAERTDOigrz3WpUgGULKO3LurwAZgXz1go","y":"DKitS9xT9W-oQmFPMNrh2HiWl5yCsFDGDAbih0A-WbM","crv":"P-256"},"enc":"A256GCM"} +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > Original:eyJhbGciOiJFQ0RILUVTIiwiZXBrIjp7Imt0eSI6IkVDIiwieCI6IlpXWmZjYTJmczdBb1d5Mk5rYVVlRk83c3VudDJCM3A0WGxiQkFXQkFsZ00iLCJ5IjoiYlVOSDM0VldmUzRwd2ZzdmxmckczTGtJcUZfS0VBZjNzS3ZHMWtSVjhLRSIsImNydiI6IlAtMjU2In0sImVuYyI6IkEyNTZHQ00ifQ..ar-gCTU6t3k4Tn-L.4K__xQ6uK_LixbUCg0DYt8CEti5ODo2Jx5o_-23sNUrTsEZKFfLbU04_pQ.lo3hEpitv7Vm5FSt-A4sBA +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Header: {"alg":"ECDH-ES","epk":{"kty":"EC","x":"ZWZfca2fs7AoWy2NkaUeFO7sunt2B3p4XlbBAWBAlgM","y":"bUNH34VWfS4pwfsvlfrG3LkIqF_KEAf3sKvG1kRV8KE","crv":"P-256"},"enc":"A256GCM"} JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Encrypted Key: -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Initialization Vector: 4_YxIEHgT0S3THYo -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Ciphertext: fgzS9zycj3N3Ts4BNN5kIduq0dxmc-p7FPsxQRsLoPly7bxBjbRZWyMinw -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Authentication Tag: pSS_005rtwkI8zS2ci4RcQ +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Initialization Vector: ar-gCTU6t3k4Tn-L +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Ciphertext: 4K__xQ6uK_LixbUCg0DYt8CEti5ODo2Jx5o_-23sNUrTsEZKFfLbU04_pQ +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Authentication Tag: lo3hEpitv7Vm5FSt-A4sBA JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > System.Security.Cryptography.CryptographicException, キーがありません。 -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJwMmMiOjgxOTIsInAycyI6IjhoZVFTUXhHUTFsekZMOGkiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.4w8H_QQeqtndy2gxSZoPQXYkErH5ynn9XblJCOoiSSCzBL9o2PmrbWHGOxS7ot0WA5YXlFzqLP6RPe27JwbsFW_dNG4rZTjE.SkrHmQA8V4vV-O6QppWSzg.Oj4F5E9wx7wFLTs-zq45PQNfqVjK4H2D4fRs0AiGyRnzSfquNau49hpKg6fERiNJ.MkcoNWK1OgXT0BsrJ83HhhoTTno_1RdHqHtl1-BfyMM -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"PBES2-HS256+A128KW","p2c":8192,"p2s":"8heQSQxGQ1lzFL8i","enc":"A256CBC-HS512"} -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: 4w8H_QQeqtndy2gxSZoPQXYkErH5ynn9XblJCOoiSSCzBL9o2PmrbWHGOxS7ot0WA5YXlFzqLP6RPe27JwbsFW_dNG4rZTjE -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: SkrHmQA8V4vV-O6QppWSzg -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: Oj4F5E9wx7wFLTs-zq45PQNfqVjK4H2D4fRs0AiGyRnzSfquNau49hpKg6fERiNJ -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: MkcoNWK1OgXT0BsrJ83HhhoTTno_1RdHqHtl1-BfyMM +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJwMmMiOjgxOTIsInAycyI6ImdEZTdldkcxSWlIc2FfcVUiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.Bniqu9Z8WeoSXGaWgGJi5zvI1oSrAaT2i2UI4WjCpeA1BclkwWkiUbBZck6MeGx_n4kL4vR3CYaWB971NkiL3t39RteYfiSP.2V_PEJe76-0bj_OSqLFksg.QM0SrZ6aW5cps8lhUOMl7KPitzvqWwG3HxOvQXIQpBeUVVcZpbCZgb4Nd_U9e4es.1QIQRjyiuQqErQA4dBE3zo1EiiOhRNtqcarzJxKbW7E +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"PBES2-HS256+A128KW","p2c":8192,"p2s":"gDe7evG1IiHsa_qU","enc":"A256CBC-HS512"} +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: Bniqu9Z8WeoSXGaWgGJi5zvI1oSrAaT2i2UI4WjCpeA1BclkwWkiUbBZck6MeGx_n4kL4vR3CYaWB971NkiL3t39RteYfiSP +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: 2V_PEJe76-0bj_OSqLFksg +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: QM0SrZ6aW5cps8lhUOMl7KPitzvqWwG3HxOvQXIQpBeUVVcZpbCZgb4Nd_U9e4es +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: 1QIQRjyiuQqErQA4dBE3zo1EiiOhRNtqcarzJxKbW7E JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -Adding extra headers to RS256 > Original:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCIsImtleWlkIjoiMTExLTIyMi0zMzMifQ.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.FSr9pqYSF8WxBNdahQ30fFnmATRtUIvuNPn8Vzeb7tncuC-m3AiEqqP02hTskzYWb5yL65Ms8WUSPUpPuq3fpOAEPaMQlB_tD1Cm9VdUWVVb2QenpYErlwghhieiaRwhNxb_HtgMEVSaUGl19rbuVSQrFZbK4xF2vcl1Mf0AIcQ +Adding extra headers to RS256 > Original:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCIsImtleWlkIjoiMTExLTIyMi0zMzMifQ.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.V3zWVmDHIekscCDCZwCnUrWRs8kDUAFqlf2VjxHXkLlaswA4BsBSaz4oThg5xdfeZ4Ne6XdyHpP6lPjcGYnJ9TyDufLdSdqqJfApzhof6nyb16VglDxeLDdHmtxugcUqHeIMu6FMn9hW3XrI8faivTUSbVqw4m37lWoQriizVwA Adding extra headers to RS256 > JWS Header: {"alg":"RS256","typ":"JWT","cty":"JWT","keyid":"111-222-333"} Adding extra headers to RS256 > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -Adding extra headers to RS256 > JWS Signature: FSr9pqYSF8WxBNdahQ30fFnmATRtUIvuNPn8Vzeb7tncuC-m3AiEqqP02hTskzYWb5yL65Ms8WUSPUpPuq3fpOAEPaMQlB_tD1Cm9VdUWVVb2QenpYErlwghhieiaRwhNxb_HtgMEVSaUGl19rbuVSQrFZbK4xF2vcl1Mf0AIcQ +Adding extra headers to RS256 > JWS Signature: V3zWVmDHIekscCDCZwCnUrWRs8kDUAFqlf2VjxHXkLlaswA4BsBSaz4oThg5xdfeZ4Ne6XdyHpP6lPjcGYnJ9TyDufLdSdqqJfApzhof6nyb16VglDxeLDdHmtxugcUqHeIMu6FMn9hW3XrI8faivTUSbVqw4m37lWoQriizVwA Adding extra headers to RS256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} Strict validation(RS256) > {"sub":"mr.x@contoso.com","exp":1300819380} -Verify nested signedXml > True : <?xml version="1.0" encoding="utf-8"?><xml><a ID="a"><b ID="b"><c /><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#b"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>+sg4j+LFYSzu6ZSzp2Jrh7CxLATJlNH/KTEQlXcfmtM=</DigestValue></Reference></SignedInfo><SignatureValue>FBB/YzsLszo0rDe8Mvb1s8JbHxNm59IEVdU8q+rkKa13lsXuSiuSDq/Cw3C3RW3VFy5nJJiOVbCQ6FwHSGhY4vSa3fgohWIPDYKFDTzToxuqrX2W5wsjnl26DiHpBCkWjpGJqEWD6VH9yLWBgo+5ltRLVJRLMoGPj+9/EmjFY/4=</SignatureValue></Signature></b><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#a"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>puYEL9d9TeBL7MbOia9vcx3qOeyBRiciAwi4MxsjAoI=</DigestValue></Reference></SignedInfo><SignatureValue>sbNtaEdIQUxdzJG+ihGnJD9+03JjcKhcG1rRdL2dNA0FhUmSY3D0yT58UNTDOWZ1482op1ixGqLcMhtFs1+PyxoQsA0++YndIf8biE5L+gzktyx6j4d3LtbxujHtT3+HxcEvOOjOXsk2jaTngCJMTrX0Ig3PaF39l/RSok6xVME=</SignatureValue></Signature></a></xml> +Verify nested signedXml > True : <?xml version="1.0" encoding="utf-8"?><xml><a ID="a"><b ID="b"><c /><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#b"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>+sg4j+LFYSzu6ZSzp2Jrh7CxLATJlNH/KTEQlXcfmtM=</DigestValue></Reference></SignedInfo><SignatureValue>jja+mCSz2mXT0AxYIE4mst2Gbyt4zcRr6F90ZD/uKgvBEs0D70irqgcVPCXs0yhudgguhHufCzqRLtqi8WijV1aX9rk73g6XEOxOfP5kF/hjCp3/qET3W6TDoRFDsrlK+GCMAOHuiJsKeZRUqQLcZLNlzY9wNnwaqMACa0ukhY0=</SignatureValue></Signature></b><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#a"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>xxZhObA6prS6yijOb9123xfSDRamrAafiJduMX7A+2M=</DigestValue></Reference></SignedInfo><SignatureValue>jJXqE5DM7YZT/7zAG3Sx7TdX4vtXBgfhu1iV6DWmNbqtcigItS2DwpXPC5um7gdabir9doFbZ//dgWmsHn9NE2oKXPTNp/IqCmWMRz0D9vd5YJbpmQeSP0fAh7xlf86Q6NTvwtyq3CWLf23dWYUYMtzU+z/wS+XIrg4OSYnY9lM=</SignatureValue></Signature></a></xml> diff --git a/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/ResultCore100.txt b/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/ResultCore100.txt index 48a9fcc70..d71ab6dd3 100644 --- a/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/ResultCore100.txt +++ b/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/ResultCore100.txt @@ -77,8 +77,8 @@ JWS_RS256_X509.Verify > True JWS_RS256_Param.Verify > True jWS_RS384_XML.Create > JWS Header: {"alg":"RS384","typ":"JWT"} jWS_RS384_XML.Create > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -jWS_RS384_XML.Create > JWS Signature: shqAjKO-YTBsx6DASpCZW5QtbZWkYC1kYrpZap2eZoNkKVipKekHSnFDoNj3soPMY6hCk5onVOtO9-Ev5_rmJeggEsJ-Vr7JBWRjTc9wRaOmhdXj0wlN_b146TgPTeRTyKeMjeEvp8PiY8hHDKqXHO_b0FeMEwpQU3OBio60AGA -RSA JWK > {"kty":"RSA","alg":"RS384","n":"z0Id6i1UAMLlF8rf5RAtbewG-ncNFFSwK91VXKXqzLPLLK35nxkyQ47zhHXBwtvGcuva3Oe2Nu-xBR33nKrzXPuLb9lvW6T3MnIMU57RyXSKM-nRWWUfgXNrD_r7sa7U5keBjt0l03zVLNRuoPAB9niY2D2N2GH0GMvijRUygq0","e":"AQAB","kid":"dP-zVYRWaQmRfFH2bLdBearWhgmgd3AO4vxdv34FyDN8stXCtz4le8cY1NDYfq7U"} +jWS_RS384_XML.Create > JWS Signature: rMojHYz6NVqVzwGbEPRFBRcHXvMmJhVU9MMzc7BxThOVMewM6E5rhhHdDKFmHu8dSxnCqNU98QlqJ5K3EqEAeXu4-L8KPxA9N0pqo4WFLDGG4w08SSBqlIhJkQ9lIfuycBNhoGe7qHmDRW0gVXDbNMY_zcD7-_N9xJzXZJbCr3Y +RSA JWK > {"kty":"RSA","alg":"RS384","n":"wPS5szmJXDw4YtG2zWiEtdmH3QJxL84HS6Sm8XW-TfcgXfBHWMBD4gsgr8arbsNHBL8LWiENbT0jAFHiXX6atgOGC7-rp6y-pvfDl-Y7uehZtEpUjr2dlH1rY97-h9fc3Oji96Y1cFi_hb9-QD-hOd6bWwJdYrc4t1DuUDUCsS0","e":"AQAB","kid":"opCbdYKnwQJTmuuslEYGKqSoMUIABtm_iqAY9Y1AHCI8_eEKeHVUvmWnN449MdhI"} JWS_RS384_XML.Verify > True JWS_RS384_Param.Verify > True JWS_RS512_X509.Create > JWS Header: {"alg":"RS512","typ":"JWT"} @@ -89,54 +89,54 @@ JWS_RS512_X509.Verify > True JWS_RS512_Param.Verify > True JWS_ES256_X509.Create > JWS Header: {"alg":"ES256","typ":"JWT"} JWS_ES256_X509.Create > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JWS_ES256_X509.Create > JWS Signature: FdhyZVwp5zW2SDL72d6yIdtJCSPwnfduiyWYL9XvzyFNrLl8pfdDuY2jR6RT41SRvX8ukbowAzSZJrxK0D35RQ +JWS_ES256_X509.Create > JWS Signature: 4L9aKma0GGae1YoweR6m1YO7FpFzL-wpLXgZutbTLTZ9_ZkIzK8rDAblOm5rTRWFfQX56JI_czRSOSDLryByvw ECDSA JWK > {"kty":"EC","alg":"ES256","crv":"P-256","x":"qdS3bsts3UXi5p0G71GofUB9ls1fJz_z0dRQw9RZ99A","y":"hX6HISTIiDLt90VDEqGmsMj2kSlGLOcXgXSqz75EhV4","kid":"asm1SGqVczG7zj0saZPKiggv2xwRlb6c23CDCNBqBNA"} JWS_ES256_X509.Verify > True JWS_ES256_Param.Verify > True -JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.FdhyZVwp5zW2SDL72d6yIdtJCSPwnfduiyWYL9XvzyFNrLl8pfdDuY2jR6RT41SRvX8ukbowAzSZJrxK0D35RQ +JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.4L9aKma0GGae1YoweR6m1YO7FpFzL-wpLXgZutbTLTZ9_ZkIzK8rDAblOm5rTRWFfQX56JI_czRSOSDLryByvw JwsAlgorithm.xLibTest > JWS Header: {"alg":"ES256","typ":"JWT"} JwsAlgorithm.xLibTest > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.xLibTest > JWS Signature: FdhyZVwp5zW2SDL72d6yIdtJCSPwnfduiyWYL9XvzyFNrLl8pfdDuY2jR6RT41SRvX8ukbowAzSZJrxK0D35RQ +JwsAlgorithm.xLibTest > JWS Signature: 4L9aKma0GGae1YoweR6m1YO7FpFzL-wpLXgZutbTLTZ9_ZkIzK8rDAblOm5rTRWFfQX56JI_czRSOSDLryByvw JwsAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JWS_ES384_X509.Create > JWS Header: {"alg":"ES384","typ":"JWT"} JWS_ES384_X509.Create > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JWS_ES384_X509.Create > JWS Signature: Y4rg0Z_1ew7Ih3bV1CENag45BWA221TjHAMkY1YSILgWs7e4wnEPq10PnEwIDWOah2sqd_98D1D5KV9tcZ5sMRfZRfuWC7WBvtza9lFrF1A4ZjAzZZ2hJu4WOJWSJqRH +JWS_ES384_X509.Create > JWS Signature: NHLVhIZrEj5IFn9u0HqiwUTFWaY-ALkjUCROVY8NMRdSaFdf7nyvor1-S28a4e4E3RVmMhWL9_iEAVNsZbXIcTej5LLNr63-kgOM48UHyrSTlZPtk8NJBVAG5kFw7P3D JWS_ES384_X509.Verify > True ECDSA JWK > {"kty":"EC","alg":"ES384","crv":"P-384","x":"qeyd2iMw8DZT7Yy3KO0mOuok1JBBdMwEuJTa81Upg06fbVbotK8yuhDSVkzSFsw3","y":"thH6faasSDmEO4zeVNdc5LbZJprQmL7JN3NZzYUJmF1GhQEl6QaZh-6f1QhDH0St","kid":"e_kI1ZJ_x9ttzEU_DICgGhJeNK8ghcW3bSl7KFM6eVefpKJHA5ecCowzJw69r9Vr"} JWS_ES384_X509.Verify > True JWS_ES384_Param.Verify > False -JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.Y4rg0Z_1ew7Ih3bV1CENag45BWA221TjHAMkY1YSILgWs7e4wnEPq10PnEwIDWOah2sqd_98D1D5KV9tcZ5sMRfZRfuWC7WBvtza9lFrF1A4ZjAzZZ2hJu4WOJWSJqRH +JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.NHLVhIZrEj5IFn9u0HqiwUTFWaY-ALkjUCROVY8NMRdSaFdf7nyvor1-S28a4e4E3RVmMhWL9_iEAVNsZbXIcTej5LLNr63-kgOM48UHyrSTlZPtk8NJBVAG5kFw7P3D JwsAlgorithm.xLibTest > JWS Header: {"alg":"ES384","typ":"JWT"} JwsAlgorithm.xLibTest > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.xLibTest > JWS Signature: Y4rg0Z_1ew7Ih3bV1CENag45BWA221TjHAMkY1YSILgWs7e4wnEPq10PnEwIDWOah2sqd_98D1D5KV9tcZ5sMRfZRfuWC7WBvtza9lFrF1A4ZjAzZZ2hJu4WOJWSJqRH +JwsAlgorithm.xLibTest > JWS Signature: NHLVhIZrEj5IFn9u0HqiwUTFWaY-ALkjUCROVY8NMRdSaFdf7nyvor1-S28a4e4E3RVmMhWL9_iEAVNsZbXIcTej5LLNr63-kgOM48UHyrSTlZPtk8NJBVAG5kFw7P3D JwsAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JWS_ES512_X509.Create > JWS Header: {"alg":"ES512","typ":"JWT"} JWS_ES512_X509.Create > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JWS_ES512_X509.Create > JWS Signature: AZnwnyNqkpF1QoU0Iu2eiEQRMI6O-YMMrJXLe8k26w-1uGEx2tLQZr0DLt2IRfML9SbklhlwDAOAqlXJZLZ0-20RAeIsiyHBOJChGktYKsTvQcEicVofispEUHYtiV7eVYeHF_FY07rkw08h3dqq2vdj0XhchQkbgrTAz5CCSPXyBj8F +JWS_ES512_X509.Create > JWS Signature: AUfQuH4qATLAlcMz8-YRIk1NVNljRHsKWKZw3PN2Y6v1CqCX4hYwuBZHvAK4ofn8vooorwqr9t9Uc36EGzgWJR2aAdTE2WyD882fq6ZRfP3dJp9Tyd-Fa3RxSkBV0M9C4_C2v0_0SaHEUn2UgQOeAZ25t_VKKwfC1oLP6QTPLtnn4Ldc JWS_ES512_X509.Verify > True ECDSA JWK > {"kty":"EC","alg":"ES512","crv":"P-521","x":"AQoRdSDzXLfin6CFhLxDOL0_Cfn-QcwgdbMkMGgwTeA4gDIygCOEy4m0eyTmEnjYdBOMN5JtYUiprdZZriAGzrHC","y":"ATj5JBej9ztfsArJLUMCs4edyCgPuItefh7KFGfeefI7YjB-pakcKxzhHZ1h2UhR183bnQ4rrXc71N5WAl3d5BqZ","kid":"OaO51pUD4-aJ8skED2eag0nvd1kfqIwo9BhB86PEZ34PBLE4TiHv6v9LCK20r0c6x06bULLSi84PcldSN2n6DQ"} JWS_ES512_X509.Verify > True JWS_ES512_Param.Verify > False -JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.AZnwnyNqkpF1QoU0Iu2eiEQRMI6O-YMMrJXLe8k26w-1uGEx2tLQZr0DLt2IRfML9SbklhlwDAOAqlXJZLZ0-20RAeIsiyHBOJChGktYKsTvQcEicVofispEUHYtiV7eVYeHF_FY07rkw08h3dqq2vdj0XhchQkbgrTAz5CCSPXyBj8F +JwsAlgorithm.xLibTest > Original:eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.AUfQuH4qATLAlcMz8-YRIk1NVNljRHsKWKZw3PN2Y6v1CqCX4hYwuBZHvAK4ofn8vooorwqr9t9Uc36EGzgWJR2aAdTE2WyD882fq6ZRfP3dJp9Tyd-Fa3RxSkBV0M9C4_C2v0_0SaHEUn2UgQOeAZ25t_VKKwfC1oLP6QTPLtnn4Ldc JwsAlgorithm.xLibTest > JWS Header: {"alg":"ES512","typ":"JWT"} JwsAlgorithm.xLibTest > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.xLibTest > JWS Signature: AZnwnyNqkpF1QoU0Iu2eiEQRMI6O-YMMrJXLe8k26w-1uGEx2tLQZr0DLt2IRfML9SbklhlwDAOAqlXJZLZ0-20RAeIsiyHBOJChGktYKsTvQcEicVofispEUHYtiV7eVYeHF_FY07rkw08h3dqq2vdj0XhchQkbgrTAz5CCSPXyBj8F +JwsAlgorithm.xLibTest > JWS Signature: AUfQuH4qATLAlcMz8-YRIk1NVNljRHsKWKZw3PN2Y6v1CqCX4hYwuBZHvAK4ofn8vooorwqr9t9Uc36EGzgWJR2aAdTE2WyD882fq6ZRfP3dJp9Tyd-Fa3RxSkBV0M9C4_C2v0_0SaHEUn2UgQOeAZ25t_VKKwfC1oLP6QTPLtnn4Ldc JwsAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JWE_RsaOaepAesGcm_X509.Decrypt > True : {"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.xLibTest > Original:eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJ0eXAiOiJKV1QifQ.edcrJWqKOfY080tAusvFJzuprNKTeaw7YILvAyDw_909i5aQ16CK6yuZs2tXd_pRp4UON05_jCNSBwOz-qkMptTjO9UX4B0Ln4LN4UUK-44bPdHWsQHA4-T0OyOHtEcemqElnuWGVL32i6-FmA1hA70OvxzF_DKB6JD65bPV4scfwcaAILySeVzq2Efg3y-6Qu5hOySeT8RLhEH1NAxisTI1jWi5-jIpYHlcRBm5LH25YXiyouc3zxaoZ_8g5dC2D6TTP40CdZBV8IO505FvINHqo6cli7LznVcDjR6AVtsPoBXsuP63GtJA-NCCDSAZ5G8YG3SvZ6LBDO035YClyw.tAX-0ka-sV93KBtw.dRlMYVJtyFL-8JjUiv32PPaE58UGkCnTAFIEAO12ZXSOoqiTS5RG74JRHg.oUbGIhaiV9ohBEMIfuoUWg +JweAlgorithm.xLibTest > Original:eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00iLCJ0eXAiOiJKV1QifQ.WZXdQnF9G5a0Vljq-tkNujN5zj8axVnM1YbKuR7-igrzswgHm5X89SKgeBK3D6bagiogf9H89nXTaTEn0UBtEnU-LLbMDbYfKfdUXRSNvhwuKAx8H6XyURMFMPZ6OXyduH1ycESmL9TG-Sb_WG0vCcUFGYZPqRemjL38tBNyH-1JfYvh7a4UcjHQ9dwoBWQyZoH6VuwRAUI0biogugPi-L9zxArWOeIXji71mUjhdrLxRXeOk-tdtr8sbsGxqSzQ8jB6Q9MDZClELjEeTdzpJIqVMsrSHNbFkGOpvAhBAFKrGzJ5JVCEpBua6VTt0B0pmtqIdkQSxVsozCCxzRaLew.dcmcZ_4U_XVYcs6U.1UZlzbqGWSt4Q-rbOgA9FFB9OiwqtWMCWhuEPFSLEbdlgRVtMe33korRgQ.dfL2_g_uv3qar4WuwhGfWg JweAlgorithm.xLibTest > JWE Header: {"alg":"RSA-OAEP","enc":"A256GCM","typ":"JWT"} -JweAlgorithm.xLibTest > JWE Encrypted Key: edcrJWqKOfY080tAusvFJzuprNKTeaw7YILvAyDw_909i5aQ16CK6yuZs2tXd_pRp4UON05_jCNSBwOz-qkMptTjO9UX4B0Ln4LN4UUK-44bPdHWsQHA4-T0OyOHtEcemqElnuWGVL32i6-FmA1hA70OvxzF_DKB6JD65bPV4scfwcaAILySeVzq2Efg3y-6Qu5hOySeT8RLhEH1NAxisTI1jWi5-jIpYHlcRBm5LH25YXiyouc3zxaoZ_8g5dC2D6TTP40CdZBV8IO505FvINHqo6cli7LznVcDjR6AVtsPoBXsuP63GtJA-NCCDSAZ5G8YG3SvZ6LBDO035YClyw -JweAlgorithm.xLibTest > JWE Initialization Vector: tAX-0ka-sV93KBtw -JweAlgorithm.xLibTest > JWE Ciphertext: dRlMYVJtyFL-8JjUiv32PPaE58UGkCnTAFIEAO12ZXSOoqiTS5RG74JRHg -JweAlgorithm.xLibTest > JWE Authentication Tag: oUbGIhaiV9ohBEMIfuoUWg +JweAlgorithm.xLibTest > JWE Encrypted Key: WZXdQnF9G5a0Vljq-tkNujN5zj8axVnM1YbKuR7-igrzswgHm5X89SKgeBK3D6bagiogf9H89nXTaTEn0UBtEnU-LLbMDbYfKfdUXRSNvhwuKAx8H6XyURMFMPZ6OXyduH1ycESmL9TG-Sb_WG0vCcUFGYZPqRemjL38tBNyH-1JfYvh7a4UcjHQ9dwoBWQyZoH6VuwRAUI0biogugPi-L9zxArWOeIXji71mUjhdrLxRXeOk-tdtr8sbsGxqSzQ8jB6Q9MDZClELjEeTdzpJIqVMsrSHNbFkGOpvAhBAFKrGzJ5JVCEpBua6VTt0B0pmtqIdkQSxVsozCCxzRaLew +JweAlgorithm.xLibTest > JWE Initialization Vector: dcmcZ_4U_XVYcs6U +JweAlgorithm.xLibTest > JWE Ciphertext: 1UZlzbqGWSt4Q-rbOgA9FFB9OiwqtWMCWhuEPFSLEbdlgRVtMe33korRgQ +JweAlgorithm.xLibTest > JWE Authentication Tag: dfL2_g_uv3qar4WuwhGfWg JweAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JWE_Rsa15A128CbcHS256_X509.Decrypt > True : {"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.xLibTest > Original:eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidHlwIjoiSldUIn0.MtulbY_m_n7EnWKU2JtGFuZhuoz060YvMHGDo7rLsXziHN0rtVQKKbCHzWd9Z3bp_rSr99YeeVaDcJSw0dPKJ9Kwt9g5vdqVHin7exOUmFRH3ELlwL26xKQFyV_Dvx1zmMHiYC4fBJ8lpruojg2Sp3hafdZKKyEDIf7wdOodQITH8oTLl63pwALqGUCxY7BikQgBMnaR74DfbvlfZaGwuqW3_IEonL-wFORjYN7PMEMMhBv3BVXNuJX50TgEU1irazHslIqDvRKNpnXJnCvZYMQHWLZLii1QLkXKNtsm712D8wki0cVT8P3Eeu9EuXX1ndmu6K30jesksmUZzthfUw.C2rFKhxUYzz3UKPKznOBmg.nJ8T8e6NYk5C14Yy1HoIDslMg9mAUuP-FgB-wOXvQ-Pgy4r1wJ80gVa0OgJnpDRO.ua5QHzHyKDD7UwqlxBZkpg +JweAlgorithm.xLibTest > Original:eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwidHlwIjoiSldUIn0.hP3HGEABF3QVOuwQG-hDAPTz8WIw9sG_yyOdVgnw-RWnq7YH9i1LQLZo8utEVL-RjPb7Z3-X_bk78lL7oxOAQ5THIkmMMcoYdWte8kKzcXCzSyIkimi0qfjFVE8Acv8wCxqX-RK1m4kYbM__XHormTqBU9t5ha_ECrF0DS6VLmoeTaOJs78KDX1I3AwugYom5DgfEcuzlo1w1mJJNH7e_w-nkbkIyqnoS9oUbzo8pZxJ0zlwIOu1Go05ElACEMdp2d7BzvuUCqgMqGMfrj3a-o1B3HZO7bpV-Blqi44fSlkSw0lBQaSZxiuAjvejXFwD1SokECvQiP4PmTaQrjIKgg.l6OREY5O844vZvFzeIC2yA.Z-n_cx77c4dpMYyJctyaI9UJH8Qj4VflRbxQYZY83rr-O466O8ipYPgMhEwag69S.S-WMCHkGm1xTdEz7muEJMg JweAlgorithm.xLibTest > JWE Header: {"alg":"RSA1_5","enc":"A128CBC-HS256","typ":"JWT"} -JweAlgorithm.xLibTest > JWE Encrypted Key: MtulbY_m_n7EnWKU2JtGFuZhuoz060YvMHGDo7rLsXziHN0rtVQKKbCHzWd9Z3bp_rSr99YeeVaDcJSw0dPKJ9Kwt9g5vdqVHin7exOUmFRH3ELlwL26xKQFyV_Dvx1zmMHiYC4fBJ8lpruojg2Sp3hafdZKKyEDIf7wdOodQITH8oTLl63pwALqGUCxY7BikQgBMnaR74DfbvlfZaGwuqW3_IEonL-wFORjYN7PMEMMhBv3BVXNuJX50TgEU1irazHslIqDvRKNpnXJnCvZYMQHWLZLii1QLkXKNtsm712D8wki0cVT8P3Eeu9EuXX1ndmu6K30jesksmUZzthfUw -JweAlgorithm.xLibTest > JWE Initialization Vector: C2rFKhxUYzz3UKPKznOBmg -JweAlgorithm.xLibTest > JWE Ciphertext: nJ8T8e6NYk5C14Yy1HoIDslMg9mAUuP-FgB-wOXvQ-Pgy4r1wJ80gVa0OgJnpDRO -JweAlgorithm.xLibTest > JWE Authentication Tag: ua5QHzHyKDD7UwqlxBZkpg +JweAlgorithm.xLibTest > JWE Encrypted Key: hP3HGEABF3QVOuwQG-hDAPTz8WIw9sG_yyOdVgnw-RWnq7YH9i1LQLZo8utEVL-RjPb7Z3-X_bk78lL7oxOAQ5THIkmMMcoYdWte8kKzcXCzSyIkimi0qfjFVE8Acv8wCxqX-RK1m4kYbM__XHormTqBU9t5ha_ECrF0DS6VLmoeTaOJs78KDX1I3AwugYom5DgfEcuzlo1w1mJJNH7e_w-nkbkIyqnoS9oUbzo8pZxJ0zlwIOu1Go05ElACEMdp2d7BzvuUCqgMqGMfrj3a-o1B3HZO7bpV-Blqi44fSlkSw0lBQaSZxiuAjvejXFwD1SokECvQiP4PmTaQrjIKgg +JweAlgorithm.xLibTest > JWE Initialization Vector: l6OREY5O844vZvFzeIC2yA +JweAlgorithm.xLibTest > JWE Ciphertext: Z-n_cx77c4dpMYyJctyaI9UJH8Qj4VflRbxQYZY83rr-O466O8ipYPgMhEwag69S +JweAlgorithm.xLibTest > JWE Authentication Tag: S-WMCHkGm1xTdEz7muEJMg JweAlgorithm.xLibTest > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} JwsAlgorithm.none > eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ. JwsAlgorithm.HS256 > Original:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.dvd5Ak6zcBy0OB7gxVtehT3Ab5NO7XEggon6r_CTSfE @@ -149,64 +149,64 @@ JwsAlgorithm.RS256 > JWS Header: {"alg":"RS256","typ":"JWT"} JwsAlgorithm.RS256 > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} JwsAlgorithm.RS256 > JWS Signature: jMJbrOaZ_p0xouAFfetm_orlTuwPbJK65-rEto5lIGgCR_oCG_ApQWeCXc5xikto_IcN2nNsHWMOMJMII6WlhVmn9pFTuuj-fZH_aB-aasDSguyXd59BA43a4glZbPCITOwZFfeNMpXGrKG_YNvexP5mtiJYYCDXMgq2zBHS9lQYcGXy4YyGPD_jNu6ziLRNDdKCkRqTppTE2SexZAwaSJRGGuY-fHA3jVPBV90Cty7yBC3ybKmiE4imVQs8CUw7ic61HSytgItIlreol4PMMP8fXB6O1e_K8QJFfRIf9oC07y9Mo5OWl4CCOxvKAo9nos0GTWUUNUH-sugJhUV14A JwsAlgorithm.RS256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.ES256 > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.6TPKtvEBm2VHxGa_9fexyxV7_AfAz-eyJORBoxJdy2oI7viElhe_deqp8lM-15lAZmmJU9iIm7u7ykztquH2sQ +JwsAlgorithm.ES256 > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.YXGFXfDvnapaWH4tIOKkELlIpPBhU_pQJ9B-RuDQPJmNK_-lCxiYyxgvMVbcex4bzJmmp-7Qpqe8DVs_kpguTA JwsAlgorithm.ES256 > JWS Header: {"alg":"ES256","typ":"JWT"} JwsAlgorithm.ES256 > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.ES256 > JWS Signature: 6TPKtvEBm2VHxGa_9fexyxV7_AfAz-eyJORBoxJdy2oI7viElhe_deqp8lM-15lAZmmJU9iIm7u7ykztquH2sQ +JwsAlgorithm.ES256 > JWS Signature: YXGFXfDvnapaWH4tIOKkELlIpPBhU_pQJ9B-RuDQPJmNK_-lCxiYyxgvMVbcex4bzJmmp-7Qpqe8DVs_kpguTA JwsAlgorithm.ES256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.ES256 > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.GeRBw5SiQhVB1chhNwVA-xMKmWr6YGkfEY6VTWGGRUGQLmlqpTV6G85v_aJRvw6ob-yVbhZvPmqXJwUtayRalA +JwsAlgorithm.ES256 > Original:eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.iX9RFZ9Yk71zeAvJpAqgzWbZTv9vyILQg-CS_N9GWRAu7TZHlyyTSAOFtHCrqramNzCgBTJ2CQ6nJ7-lGWJBVQ JwsAlgorithm.ES256 > JWS Header: {"alg":"ES256","typ":"JWT"} JwsAlgorithm.ES256 > JWS Payload: {"sub":"mr.x@contoso.com","exp":1300819380} -JwsAlgorithm.ES256 > JWS Signature: GeRBw5SiQhVB1chhNwVA-xMKmWr6YGkfEY6VTWGGRUGQLmlqpTV6G85v_aJRvw6ob-yVbhZvPmqXJwUtayRalA +JwsAlgorithm.ES256 > JWS Signature: iX9RFZ9Yk71zeAvJpAqgzWbZTv9vyILQg-CS_N9GWRAu7TZHlyyTSAOFtHCrqramNzCgBTJ2CQ6nJ7-lGWJBVQ JwsAlgorithm.ES256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > Original:eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.kKCM3QOB7PjZXcQmL3XE3HKb2LPsn_HAXS3GpW9t2yrh6frqciP4MHr8S5S9O0BkZlWzf7fUivZ2auyNow7fuBGynihTn9vVOCMKI12k_LCkdnMdgE52rxnr_tfdhqGlikNQvPIiWLxa1q43ywnFvdZvmx5VaRZzCDFyJm9pL1F0e_iXdz4hzybOuOOXN5fQ3hih7PJmtRyos1CEa86wegiTD6BeYIbJgajWuUMw7jLAPllLzbD4m1s-FCCowZyni53HxLCercOu4Oc3t-jzTYZju_apELrPJ7y0RYPcTzU4TSnuEoTtznYUw1Ls-_ceztoNt5j3Mxp-FMIhFXnZPw.GN3QJ5vAsUq3T5XNzLhuWg.DgxbAehLvwTYErc9-wzpeAnND6hVMuAndrmwyKMaIFHnNoEupw471xHGonsdZt-c.S6y4xWqM7OwMfuO66MlM-A +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > Original:eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.giMIq2k6YW3IJWzSl17fHJFVCPpU9IIjnj-GajpLXo3gY0RR-xqZqpmXuNzK426T6jmBojP6SUajAFRYkF7SBbo-Q0qpTMaLTcVCNbiSwa0mvU7Z7qiL2kuWIK7bDLazfuFQn_Af9N6v4EW_3w1sgNXCc2dKKNB2XoK2wgc4RyW8UgEKHqJK3l8HQhKPf-r3M-CH5G9dOqMUeI679VduCpmDkXPfq4zSeQIf93kq7L6ZTW9GdWG61OrVWQqYkwSPHABM7nDXTY1hFRXJlwiyZB18-lxAsK7X6HCIFMQ5Z8etMVGpB1BbpllfydqcaSU76T96IBGCo03S8y9TEyEzMA.3WVShFMeNtp7Af3Pg8huIg.BZTteEKr1pnsUpYgW6P1LLWh7djUzSyHwekkcdTLtiVeRn7woK3QDRXk1PtM82AD.wqaQRgb7szkKmeN254DLDg JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Header: {"alg":"RSA1_5","enc":"A128CBC-HS256"} -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Encrypted Key: kKCM3QOB7PjZXcQmL3XE3HKb2LPsn_HAXS3GpW9t2yrh6frqciP4MHr8S5S9O0BkZlWzf7fUivZ2auyNow7fuBGynihTn9vVOCMKI12k_LCkdnMdgE52rxnr_tfdhqGlikNQvPIiWLxa1q43ywnFvdZvmx5VaRZzCDFyJm9pL1F0e_iXdz4hzybOuOOXN5fQ3hih7PJmtRyos1CEa86wegiTD6BeYIbJgajWuUMw7jLAPllLzbD4m1s-FCCowZyni53HxLCercOu4Oc3t-jzTYZju_apELrPJ7y0RYPcTzU4TSnuEoTtznYUw1Ls-_ceztoNt5j3Mxp-FMIhFXnZPw -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Initialization Vector: GN3QJ5vAsUq3T5XNzLhuWg -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Ciphertext: DgxbAehLvwTYErc9-wzpeAnND6hVMuAndrmwyKMaIFHnNoEupw471xHGonsdZt-c -JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Authentication Tag: S6y4xWqM7OwMfuO66MlM-A +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Encrypted Key: giMIq2k6YW3IJWzSl17fHJFVCPpU9IIjnj-GajpLXo3gY0RR-xqZqpmXuNzK426T6jmBojP6SUajAFRYkF7SBbo-Q0qpTMaLTcVCNbiSwa0mvU7Z7qiL2kuWIK7bDLazfuFQn_Af9N6v4EW_3w1sgNXCc2dKKNB2XoK2wgc4RyW8UgEKHqJK3l8HQhKPf-r3M-CH5G9dOqMUeI679VduCpmDkXPfq4zSeQIf93kq7L6ZTW9GdWG61OrVWQqYkwSPHABM7nDXTY1hFRXJlwiyZB18-lxAsK7X6HCIFMQ5Z8etMVGpB1BbpllfydqcaSU76T96IBGCo03S8y9TEyEzMA +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Initialization Vector: 3WVShFMeNtp7Af3Pg8huIg +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Ciphertext: BZTteEKr1pnsUpYgW6P1LLWh7djUzSyHwekkcdTLtiVeRn7woK3QDRXk1PtM82AD +JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > JWE Authentication Tag: wqaQRgb7szkKmeN254DLDg JweAlgorithm.RSA1_5, JweEncryption.A128CBC_HS256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > Original:eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.GnmWpfccMRweSdfgnpiEwlhmEAqGMDnwMG4RryLDoHS3SkhhOJ-FVeMUVUoeuIEsXbR_Ea5qg7p9TziXaH8EwiQcClkAkgdn0Fmo51IQ2CoRnleGbF9ysq7Ppr5urPozDvBO9mDrIbAwBY4Q0OVlVio7VUo5sg7UVkM42aR3M7k-KJdyoJLQsHkF6skSyLnajNs9Gc5iozXmK5fpcYqTVhgl0PdazntTxQuvN1ileg5yORvveQ-0zOR4oa0udyJULTeAjWhEfYEopLihNAnGGWj7P_GdvnGCw9W_Y8OMXnR3GJw76l82sWdB53KZlNLtjXWJo37oKQjnWuvjcqtpEw.A2aMGxvBXSlRNG9C.s4J3soaCmwKTJzR2KsxOIuvT5Bj4fevMCtQ6ky4tNB7ZJzqW8HH1hP3qbA.ha1fZH4ofYZlGxYMBf1Xaw +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > Original:eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.m71V5Pd2oY0IqcRKQqWbSni5RLBdOQFLgsBK-korgVa7aHpwPgW6IFT-pYt6uAzJHEHEdzo2l12l85x7ul59U4wL_Rm2yATRLPS0FNTAxyPWhF0RhTTccweL3T40AkBTEOYHVyDShS81axMz7RQwcmOwckDfNamdj2x2J9Q9NvWtg3tI4vdNYQY2zv7iG5dENPsbSf7_0Q-41oCp_f5QCji68EKt7TZNK62y6Hajpg20ojz0s4LgNOoLqbVuGnQ5dVtPzNBs656r2O7kYqQnnzRksMD4EB-pWAtWsDHTDyr252wUL66byJpKozLVoddVqOezBzGORrBB3e5d14hygQ.iTWs9lNzvnXfvtuT.VDqqiy4eQvWsMzrLBrhiAoU9DEfxl3vioPl3I-F0TIccrklUo3a63l_BBw.gQfndG8ZYSyjjnRDpG-j7A JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Header: {"alg":"RSA-OAEP","enc":"A256GCM"} -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Encrypted Key: GnmWpfccMRweSdfgnpiEwlhmEAqGMDnwMG4RryLDoHS3SkhhOJ-FVeMUVUoeuIEsXbR_Ea5qg7p9TziXaH8EwiQcClkAkgdn0Fmo51IQ2CoRnleGbF9ysq7Ppr5urPozDvBO9mDrIbAwBY4Q0OVlVio7VUo5sg7UVkM42aR3M7k-KJdyoJLQsHkF6skSyLnajNs9Gc5iozXmK5fpcYqTVhgl0PdazntTxQuvN1ileg5yORvveQ-0zOR4oa0udyJULTeAjWhEfYEopLihNAnGGWj7P_GdvnGCw9W_Y8OMXnR3GJw76l82sWdB53KZlNLtjXWJo37oKQjnWuvjcqtpEw -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Initialization Vector: A2aMGxvBXSlRNG9C -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Ciphertext: s4J3soaCmwKTJzR2KsxOIuvT5Bj4fevMCtQ6ky4tNB7ZJzqW8HH1hP3qbA -JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Authentication Tag: ha1fZH4ofYZlGxYMBf1Xaw +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Encrypted Key: m71V5Pd2oY0IqcRKQqWbSni5RLBdOQFLgsBK-korgVa7aHpwPgW6IFT-pYt6uAzJHEHEdzo2l12l85x7ul59U4wL_Rm2yATRLPS0FNTAxyPWhF0RhTTccweL3T40AkBTEOYHVyDShS81axMz7RQwcmOwckDfNamdj2x2J9Q9NvWtg3tI4vdNYQY2zv7iG5dENPsbSf7_0Q-41oCp_f5QCji68EKt7TZNK62y6Hajpg20ojz0s4LgNOoLqbVuGnQ5dVtPzNBs656r2O7kYqQnnzRksMD4EB-pWAtWsDHTDyr252wUL66byJpKozLVoddVqOezBzGORrBB3e5d14hygQ +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Initialization Vector: iTWs9lNzvnXfvtuT +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Ciphertext: VDqqiy4eQvWsMzrLBrhiAoU9DEfxl3vioPl3I-F0TIccrklUo3a63l_BBw +JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > JWE Authentication Tag: gQfndG8ZYSyjjnRDpG-j7A JweAlgorithm.RSA_OAEP, JweEncryption.A256GCM > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > Original:eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..QVrifvtI6I5Ooo9TD4zhXA.Fi6y6jUXoIhF-ewFpjpunvykW32AuSsg19ucWGcKBe41s7mlurF_YrS9-xEkyjkq.nkhS-2r8JYDiWAnwKg3inQ +JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > Original:eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0..AtWQvIBIu0r1cYEnyCThQw.x2pM9BdQM7odA17Wpd5eDnw4vmLcxnzB61pi_HOpCaThvw-og2ejryFdAylelrIT.x__KBjUYbXdDhV2Fu7MojQ JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Header: {"alg":"dir","enc":"A128CBC-HS256"} JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Encrypted Key: -JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Initialization Vector: QVrifvtI6I5Ooo9TD4zhXA -JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Ciphertext: Fi6y6jUXoIhF-ewFpjpunvykW32AuSsg19ucWGcKBe41s7mlurF_YrS9-xEkyjkq -JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Authentication Tag: nkhS-2r8JYDiWAnwKg3inQ +JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Initialization Vector: AtWQvIBIu0r1cYEnyCThQw +JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Ciphertext: x2pM9BdQM7odA17Wpd5eDnw4vmLcxnzB61pi_HOpCaThvw-og2ejryFdAylelrIT +JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > JWE Authentication Tag: x__KBjUYbXdDhV2Fu7MojQ JweAlgorithm.DIR, JweEncryption.A128CBC_HS256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.I53ooLjzbWEV1c5y53IPg_J18hmJY7MXT_tdTPmJwqP1qZrM0xGiE-Z-V8X_nPpuRYgTfn184cmkaZ7n_dyzejPha9mWLRaM.zuo1PwH-b-c0plvEFtUMBg.bDmhsw1maPd2n3rBNqGqLJOBtWvpjZwyeHQIVO7roT08oweVA22XxCZOy4rpgeNC.4Bcb4-P2IayzjV4lKOkLGFZJ_4W-wO_f3ic2hIirZIw +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJBMjU2S1ciLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.VRxXjJgeUhm3UEvu-0iv-GydA81IWZ8Iypj0bjqQkCJ6atxDGMQoRmf690GSaWi6fJEHl5hfqwzqNL-Ijwn1W_o3n0RJY11n.CzDQB1jauz9yrzea_kCOkA.8P2XdTtAOB4LwMSdWEKQ9ISYkvQiW1kmfXcXs-qww4hawTKqqfRm55V1eOZ-OPPS.Ci7MGeGoP8rM6zNibNWdvQ620HlfsNJK-zN4wmg8jnM JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"A256KW","enc":"A256CBC-HS512"} -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: I53ooLjzbWEV1c5y53IPg_J18hmJY7MXT_tdTPmJwqP1qZrM0xGiE-Z-V8X_nPpuRYgTfn184cmkaZ7n_dyzejPha9mWLRaM -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: zuo1PwH-b-c0plvEFtUMBg -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: bDmhsw1maPd2n3rBNqGqLJOBtWvpjZwyeHQIVO7roT08oweVA22XxCZOy4rpgeNC -JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: 4Bcb4-P2IayzjV4lKOkLGFZJ_4W-wO_f3ic2hIirZIw +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: VRxXjJgeUhm3UEvu-0iv-GydA81IWZ8Iypj0bjqQkCJ6atxDGMQoRmf690GSaWi6fJEHl5hfqwzqNL-Ijwn1W_o3n0RJY11n +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: CzDQB1jauz9yrzea_kCOkA +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: 8P2XdTtAOB4LwMSdWEKQ9ISYkvQiW1kmfXcXs-qww4hawTKqqfRm55V1eOZ-OPPS +JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: Ci7MGeGoP8rM6zNibNWdvQ620HlfsNJK-zN4wmg8jnM JweAlgorithm.A256KW, JweEncryption.A256CBC_HS512 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJBMjU2R0NNS1ciLCJpdiI6IkQ2bUVlLXV3bUw1VEV3dUEiLCJ0YWciOiJOMGRSQV9JUEhhQndjeG9WT3BFYjlBIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.14yQsB8He2E6eRQTLWaFKyXG6KHtHoWNBswgJfmbDd93g1ioi_ukxXsgo9WSqxme0m-WoVenxSOhZJwk9s6Zrw.6tyAe7zEnsAMIzF_1z_9Nw.sg5995L8QkvHBRoUr4rzNVUhIv-AdNSzgQozFPpAV-9rwbQsrKaO2TJILNGTuKjK.dzRekdA9FNlluMu3hZF9nJWgtxLWWl1gJIUnjMjywJU -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"A256GCMKW","iv":"D6mEe-uwmL5TEwuA","tag":"N0dRA_IPHaBwcxoVOpEb9A","enc":"A256CBC-HS512"} -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: 14yQsB8He2E6eRQTLWaFKyXG6KHtHoWNBswgJfmbDd93g1ioi_ukxXsgo9WSqxme0m-WoVenxSOhZJwk9s6Zrw -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: 6tyAe7zEnsAMIzF_1z_9Nw -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: sg5995L8QkvHBRoUr4rzNVUhIv-AdNSzgQozFPpAV-9rwbQsrKaO2TJILNGTuKjK -JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: dzRekdA9FNlluMu3hZF9nJWgtxLWWl1gJIUnjMjywJU +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJBMjU2R0NNS1ciLCJpdiI6InRuQXNPZUZRQ0VVNjVtbVYiLCJ0YWciOiJVTk1Md0pMalFhdXQxVnpCQ3FsMFJnIiwiZW5jIjoiQTI1NkNCQy1IUzUxMiJ9.mDulML4QQD0_X43f02I2DLYm4_GoBgOfJFsQ0KAbVq9Fre1lkHWi9BxOirR86YrukYYbnuyoItIq4H-5aIAndg.QFLXF9ph6Ik15I3kjSK4_A.nofrN5GnHx0nYJzQarFGs7rzonljnafCGIFAdoJktSK_vSVm1tr0brPuQGfqzn2j.zgV6SV1WcDAjbmvisQwcIJh82Mshhw5gOsuhXbO_gOw +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"A256GCMKW","iv":"tnAsOeFQCEU65mmV","tag":"UNMLwJLjQaut1VzBCql0Rg","enc":"A256CBC-HS512"} +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: mDulML4QQD0_X43f02I2DLYm4_GoBgOfJFsQ0KAbVq9Fre1lkHWi9BxOirR86YrukYYbnuyoItIq4H-5aIAndg +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: QFLXF9ph6Ik15I3kjSK4_A +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: nofrN5GnHx0nYJzQarFGs7rzonljnafCGIFAdoJktSK_vSVm1tr0brPuQGfqzn2j +JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: zgV6SV1WcDAjbmvisQwcIJh82Mshhw5gOsuhXbO_gOw JweAlgorithm.A256GCMKW, JweEncryption.A256CBC_HS512 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > Original:eyJhbGciOiJFQ0RILUVTIiwiZXBrIjp7Imt0eSI6IkVDIiwieCI6IldwbGRSQkJBWktxSktncndpMk56UGplRHdCek1tY09Dd1ZYWUFSb3hqSFUiLCJ5IjoiSUdCRXZXUEtCZEdDQUtoOVc3NVg0bHRXelg0YThJbVR6RW9fb2hlOXVUTSIsImNydiI6IlAtMjU2In0sImVuYyI6IkEyNTZHQ00ifQ..EcC8NIJuuSwfBLOR.u8-_yuTuxDd89ZfP7PumVfgMaqFPJ6Rm5DSfiJZAgSUnEyXg0gHK5HwGwg.g1L4cz-kr2uBf-Tcn_K9cA -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Header: {"alg":"ECDH-ES","epk":{"kty":"EC","x":"WpldRBBAZKqJKgrwi2NzPjeDwBzMmcOCwVXYARoxjHU","y":"IGBEvWPKBdGCAKh9W75X4ltWzX4a8ImTzEo_ohe9uTM","crv":"P-256"},"enc":"A256GCM"} +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > Original:eyJhbGciOiJFQ0RILUVTIiwiZXBrIjp7Imt0eSI6IkVDIiwieCI6IjFuOVhucXpCaEpvQ2NTSmVsRE0weUt4ZEdMcFlfcmxRM0pabVlSY3VpZlUiLCJ5IjoiTjV3eVQ2TGZaVWI3XzB0UUFjSWNSc3VmWG9kR2dXbVhBdDlEaW5uNGhuayIsImNydiI6IlAtMjU2In0sImVuYyI6IkEyNTZHQ00ifQ..nZQYzhEhyZyq0dFZ.YvY1A6I99mCQyF_JEPkBORajzfa5llUfgduhACdvYOwp2xeykZm_ZelXsA.UD4ZSWglfAvy1vWo20kptQ +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Header: {"alg":"ECDH-ES","epk":{"kty":"EC","x":"1n9XnqzBhJoCcSJelDM0yKxdGLpY_rlQ3JZmYRcuifU","y":"N5wyT6LfZUb7_0tQAcIcRsufXodGgWmXAt9Dinn4hnk","crv":"P-256"},"enc":"A256GCM"} JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Encrypted Key: -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Initialization Vector: EcC8NIJuuSwfBLOR -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Ciphertext: u8-_yuTuxDd89ZfP7PumVfgMaqFPJ6Rm5DSfiJZAgSUnEyXg0gHK5HwGwg -JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Authentication Tag: g1L4cz-kr2uBf-Tcn_K9cA +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Initialization Vector: nZQYzhEhyZyq0dFZ +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Ciphertext: YvY1A6I99mCQyF_JEPkBORajzfa5llUfgduhACdvYOwp2xeykZm_ZelXsA +JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > JWE Authentication Tag: UD4ZSWglfAvy1vWo20kptQ JweAlgorithm.ECDH_ES, JweEncryption.A256GCM > System.Security.Cryptography.CryptographicException, キーがありません。 -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJwMmMiOjgxOTIsInAycyI6IlJ2VmZvc1Nua0Vxb3FpMFEiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.3PB8TgWzRJbc__0yLUZ8KFnmFvTJbhNcHm7K523OjNUIDkFRP7nMIn8PQkbWf4eB8sTAArTotqeXSAN8sC8M7TSS_TkRCCAJ.zNB4bHGogG5K3mdQnG7_Rg.TS0HPoeZo6J9pgu6udaXfggeBvN13ppquLXqbF5OqSUbA3H-r69sd0yVN1urTNOF.SOj1Cl58MzoMN3Itu5vzoiotjPS3hudXlZ4XBXYgo8s -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"PBES2-HS256+A128KW","p2c":8192,"p2s":"RvVfosSnkEqoqi0Q","enc":"A256CBC-HS512"} -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: 3PB8TgWzRJbc__0yLUZ8KFnmFvTJbhNcHm7K523OjNUIDkFRP7nMIn8PQkbWf4eB8sTAArTotqeXSAN8sC8M7TSS_TkRCCAJ -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: zNB4bHGogG5K3mdQnG7_Rg -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: TS0HPoeZo6J9pgu6udaXfggeBvN13ppquLXqbF5OqSUbA3H-r69sd0yVN1urTNOF -JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: SOj1Cl58MzoMN3Itu5vzoiotjPS3hudXlZ4XBXYgo8s +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > Original:eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJwMmMiOjgxOTIsInAycyI6Ijhzbld4UGxfcXpBczF4SUEiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIn0.SH8javti2YDVghhdC1UQtw_b_cyeS6ntkQnQvv5GAritFS2oJtI1L_9cWVFmlo84R7uJKlHnrlLQLcPV5lnRbIEcF8aH1OPx.5-ewO99D5bqc7DlTpff9Fw.VpTGOwqH_I6GtJZMiy0EB8zkR529AP40blx_NmWqqdlKI2lfzJTbv62EgZjpkLLl.sqnHLvw9el9lcTtooqT8fZpu88zjvb2vyHn7D8LLymk +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Header: {"alg":"PBES2-HS256+A128KW","p2c":8192,"p2s":"8snWxPl_qzAs1xIA","enc":"A256CBC-HS512"} +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Encrypted Key: SH8javti2YDVghhdC1UQtw_b_cyeS6ntkQnQvv5GAritFS2oJtI1L_9cWVFmlo84R7uJKlHnrlLQLcPV5lnRbIEcF8aH1OPx +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Initialization Vector: 5-ewO99D5bqc7DlTpff9Fw +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Ciphertext: VpTGOwqH_I6GtJZMiy0EB8zkR529AP40blx_NmWqqdlKI2lfzJTbv62EgZjpkLLl +JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > JWE Authentication Tag: sqnHLvw9el9lcTtooqT8fZpu88zjvb2vyHn7D8LLymk JweAlgorithm.PBES2_HS256_A128KW, JweEncryption.A256CBC_HS512 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} Adding extra headers to RS256 > Original:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImN0eSI6IkpXVCIsImtleWlkIjoiMTExLTIyMi0zMzMifQ.eyJzdWIiOiJtci54QGNvbnRvc28uY29tIiwiZXhwIjoxMzAwODE5MzgwfQ.KwtpHrjNKBnyHo6QRaULxcWZDF9mDKHiQG1QBSmnrwHi7vJSiLH_3fFIcTkQvdu7FstmPOuuVD-T3EPKfv61aHz5o-0dRTylooln5tS_2_uZ4lPV4A2C_Pr_cYzRawUIuTwhCi3n0i-fQapYvKT41qjh0vKalEuDmd6-WDnpGcKdI3dv-kSB_42FfIdbEKDEtYvgyzwj5An9YJim29OsiM-GW6tyqei3nzHrQ0yPhgfKOd89M_azGynAVTTNKvPyZujnILu-XnVu54So-5W2fwg-WkKIpvP2ZZFAWRs-DEapBJWrNm10GGZdid-98SmGoifkaDNpCeIcQe3uetDB6w Adding extra headers to RS256 > JWS Header: {"alg":"RS256","typ":"JWT","cty":"JWT","keyid":"111-222-333"} @@ -214,4 +214,4 @@ Adding extra headers to RS256 > JWS Payload: {"sub":"mr.x@contoso.com","exp":130 Adding extra headers to RS256 > JWS Signature: KwtpHrjNKBnyHo6QRaULxcWZDF9mDKHiQG1QBSmnrwHi7vJSiLH_3fFIcTkQvdu7FstmPOuuVD-T3EPKfv61aHz5o-0dRTylooln5tS_2_uZ4lPV4A2C_Pr_cYzRawUIuTwhCi3n0i-fQapYvKT41qjh0vKalEuDmd6-WDnpGcKdI3dv-kSB_42FfIdbEKDEtYvgyzwj5An9YJim29OsiM-GW6tyqei3nzHrQ0yPhgfKOd89M_azGynAVTTNKvPyZujnILu-XnVu54So-5W2fwg-WkKIpvP2ZZFAWRs-DEapBJWrNm10GGZdid-98SmGoifkaDNpCeIcQe3uetDB6w Adding extra headers to RS256 > Decoded:{"sub":"mr.x@contoso.com","exp":1300819380} Strict validation(RS256) > {"sub":"mr.x@contoso.com","exp":1300819380} -Verify nested signedXml > True : <?xml version="1.0" encoding="utf-8"?><xml><a ID="a"><b ID="b"><c /><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#b"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>+sg4j+LFYSzu6ZSzp2Jrh7CxLATJlNH/KTEQlXcfmtM=</DigestValue></Reference></SignedInfo><SignatureValue>GBYFP0HPapV9CBUVsWWnokOhEWkJeTIVf8U3hy3DxPNUiqungv6jcfVmYPEazzjkSkxvVEEPZZ8tCr6fiWHl2Mlm/9zMwfFDX3pxsNirtkAMTk73xwajGw6SB+NQiA1NgG21TabU4S6CVoQGdW9zAUSYqQ/K/6b8uu+z26uEad0=</SignatureValue></Signature></b><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#a"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>gOyUYjJl2u0ljtYCKT6it/xfIC45SQUR6RUTq6ngLk4=</DigestValue></Reference></SignedInfo><SignatureValue>saT83xL1EoONw2q22s+t1k6vO29mt/znMYNChyOUhJPsY5VWpwWPBBkYEPCFZGLMK2pz6yyv3b3AbyfueGL+kf43ePkOzCeZlYx87j3bG6nKT1FEsIl89LUdVSv+x76WrZM73tb4ZOeQKbF03WIrwHmVyp0OmPuZyeCpnof7/Sk=</SignatureValue></Signature></a></xml> +Verify nested signedXml > True : <?xml version="1.0" encoding="utf-8"?><xml><a ID="a"><b ID="b"><c /><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#b"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>+sg4j+LFYSzu6ZSzp2Jrh7CxLATJlNH/KTEQlXcfmtM=</DigestValue></Reference></SignedInfo><SignatureValue>vHsR/HO9Q/It6fYHGiMx26sR8k0kCqpa34CJpQ4qm8axztPefo1CkkH5kSRrA1Oks0Qoly5dzc+TNdQ9tNxTu+19VTE2uwBI7wupkie9W+ie1keH2BCE98q7L9/ke+KwDYvltgkUfc+l1Msrfna9w2D8XavFnBXIgd1JAtHRfQY=</SignatureValue></Signature></b><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI="#a"><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>yRKv9RV97QTkVsREBkgh3tnhMaKxOg3HnRj3d7/oLVY=</DigestValue></Reference></SignedInfo><SignatureValue>dW6hmKSK3Rd3BUW65Ba+J+wvfATVZ5p7n9+fmSHCHlWEmb0Pu/JarimnSUqm2jyYdRzcgxOfUZyIPIP/i15ColTvlpu5vESCjsctYWXz1IpwrwBhMYcRtpe+xxpWsVTizdJX3dx89N7jAVm4ydq/emkGpvfBRG4cSy/RJJ6oVpc=</SignatureValue></Signature></a></xml> diff --git a/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/core100/EncAndDecUtilCUICore.csproj b/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/core100/EncAndDecUtilCUICore.csproj index 0e14bdc55..b7062780a 100644 --- a/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/core100/EncAndDecUtilCUICore.csproj +++ b/root/programs/CS/Frameworks/Tests/EncAndDecUtilCUI/core100/EncAndDecUtilCUICore.csproj @@ -19,7 +19,7 @@ <PackageReference Include="jose-jwt" Version="5.2.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.6" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> - <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.6" /> + <PackageReference Include="System.Security.Cryptography.Xml" Version="9.0.18" /> </ItemGroup> <ItemGroup> diff --git a/root/programs/CS/Frameworks/Tests/TestBatch/ResultSimpleBatch48.txt b/root/programs/CS/Frameworks/Tests/TestBatch/ResultSimpleBatch48.txt index 7aedc7544..a8b149bf5 100644 --- a/root/programs/CS/Frameworks/Tests/TestBatch/ResultSimpleBatch48.txt +++ b/root/programs/CS/Frameworks/Tests/TestBatch/ResultSimpleBatch48.txt @@ -69,7 +69,7 @@ log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.Level log4net: Created Appender [OPERATION2] log4net: Adding appender named [OPERATION2] to logger [OPERATION]. log4net: Hierarchy Threshold [] -[2025/11/18 15:19:08,286],[INFO ],[1],,,,----->>,C:\OpenTouryo\root\programs\CS\Frameworks\Tests\TestBatch\SimpleBatch\bin\Debug\SimpleBatch.exe,-,SelectCount,SQL%individual%static%- +[2026/08/08 10:16:21,273],[INFO ],[1],,,,----->>,C:\OpenTouryo\root\programs\CS\Frameworks\Tests\TestBatch\SimpleBatch\bin\Debug\SimpleBatch.exe,-,SelectCount,SQL%individual%static%- log4net: configuring repository [log4net-default-repository] using stream log4net: loading XML configuration log4net: Configuring Repository [log4net-default-repository] @@ -144,6 +144,6 @@ log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.Level log4net: Created Appender [OPERATION2] log4net: Adding appender named [OPERATION2] to logger [OPERATION]. log4net: Hierarchy Threshold [] -[2025/11/18 15:19:08,522],[INFO ],[1],153,109,[commandText]:SELECT COUNT(*) FROM Shippers [commandParameter]: -[2025/11/18 15:19:08,523],[INFO ],[1],,,,<<-----,C:\OpenTouryo\root\programs\CS\Frameworks\Tests\TestBatch\SimpleBatch\bin\Debug\SimpleBatch.exe,-,SelectCount,SQL%individual%static%-,214,172 +[2026/08/08 10:16:21,392],[INFO ],[1],87,63,[commandText]:SELECT COUNT(*) FROM Shippers [commandParameter]: +[2026/08/08 10:16:21,393],[INFO ],[1],,,,<<-----,C:\OpenTouryo\root\programs\CS\Frameworks\Tests\TestBatch\SimpleBatch\bin\Debug\SimpleBatch.exe,-,SelectCount,SQL%individual%static%-,110,63 3件のデータがあります diff --git a/root/programs/CS/Frameworks/Tests/TestBatch/ResultSimpleBatchCore100.txt b/root/programs/CS/Frameworks/Tests/TestBatch/ResultSimpleBatchCore100.txt index 6c070d34d..ca648cccc 100644 --- a/root/programs/CS/Frameworks/Tests/TestBatch/ResultSimpleBatchCore100.txt +++ b/root/programs/CS/Frameworks/Tests/TestBatch/ResultSimpleBatchCore100.txt @@ -69,7 +69,7 @@ log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.Level log4net: Created Appender [OPERATION2] log4net: Adding appender named [OPERATION2] to logger [OPERATION]. log4net: Hierarchy Threshold [] -[2025/11/18 15:19:19,105],[INFO ],[2],,,,----->>,C:\OpenTouryo\root\programs\CS\Frameworks\Tests\TestBatch\SimpleBatchCore\bin\Debug\net10.0\SimpleBatchCore.dll,-,SelectCount,SQL%individual%static%- +[2026/08/08 10:16:24,296],[INFO ],[2],,,,----->>,C:\OpenTouryo\root\programs\CS\Frameworks\Tests\TestBatch\SimpleBatchCore\bin\Debug\net10.0\SimpleBatchCore.dll,-,SelectCount,SQL%individual%static%- log4net: configuring repository [log4net-default-repository] using stream log4net: loading XML configuration log4net: Configuring Repository [log4net-default-repository] @@ -144,6 +144,6 @@ log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.Level log4net: Created Appender [OPERATION2] log4net: Adding appender named [OPERATION2] to logger [OPERATION]. log4net: Hierarchy Threshold [] -[2025/11/18 15:19:19,225],[INFO ],[2],67,,[commandText]:SELECT COUNT(*) FROM Shippers [commandParameter]: -[2025/11/18 15:19:19,227],[INFO ],[2],,,,<<-----,C:\OpenTouryo\root\programs\CS\Frameworks\Tests\TestBatch\SimpleBatchCore\bin\Debug\net10.0\SimpleBatchCore.dll,-,SelectCount,SQL%individual%static%-,97, +[2026/08/08 10:16:24,373],[INFO ],[2],50,,[commandText]:SELECT COUNT(*) FROM Shippers [commandParameter]: +[2026/08/08 10:16:24,374],[INFO ],[2],,,,<<-----,C:\OpenTouryo\root\programs\CS\Frameworks\Tests\TestBatch\SimpleBatchCore\bin\Debug\net10.0\SimpleBatchCore.dll,-,SelectCount,SQL%individual%static%-,67, 3件のデータがあります diff --git a/root/programs/CS/Frameworks/Tests/TestBatch/SimpleBatch/SimpleBatch.csproj b/root/programs/CS/Frameworks/Tests/TestBatch/SimpleBatch/SimpleBatch.csproj index 43d57c2f9..2bece7770 100644 --- a/root/programs/CS/Frameworks/Tests/TestBatch/SimpleBatch/SimpleBatch.csproj +++ b/root/programs/CS/Frameworks/Tests/TestBatch/SimpleBatch/SimpleBatch.csproj @@ -101,7 +101,7 @@ </ItemGroup> <ItemGroup> <PackageReference Include="log4net"> - <Version>3.1.0</Version> + <Version>3.3.0</Version> </PackageReference> <PackageReference Include="Microsoft.Data.SqlClient"> <Version>6.0.2</Version> diff --git a/root/programs/CS/Frameworks/Tests/TestBatch/SimpleBatchCore/SimpleBatchCore.csproj b/root/programs/CS/Frameworks/Tests/TestBatch/SimpleBatchCore/SimpleBatchCore.csproj index 3107c6493..34980605e 100644 --- a/root/programs/CS/Frameworks/Tests/TestBatch/SimpleBatchCore/SimpleBatchCore.csproj +++ b/root/programs/CS/Frameworks/Tests/TestBatch/SimpleBatchCore/SimpleBatchCore.csproj @@ -17,7 +17,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="log4net" Version="3.1.0" /> + <PackageReference Include="log4net" Version="3.3.0" /> <PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.2" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="9.0.6" /> @@ -25,6 +25,10 @@ <PackageReference Include="MySql.Data" Version="9.3.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Npgsql" Version="9.0.3" /> + <!--Oracle は .NET (Core) 版のパッケージ名が異なる(DamManagedOdp_netcore100.csproj に合わせる)。 + net48 版(Oracle.ManagedDataAccess)では動かず、/Dap ODP の接続時に + System.IO.FileNotFoundException になる。--> + <PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.8.0" /> <PackageReference Include="System.Security.Permissions" Version="9.0.6" /> </ItemGroup> diff --git a/root/programs/CS/Frameworks/Tests/TestCode/App.config b/root/programs/CS/Frameworks/Tests/TestCode/App.config index b9c085ab8..9a2e924ac 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/App.config +++ b/root/programs/CS/Frameworks/Tests/TestCode/App.config @@ -7,6 +7,12 @@ <!--埋め込まれたリソースの場合--> <!--add key="FxXMLMSGDefinition" value="TestCodeFx.MSGDefinition.xml"/--> <!--add key="FxXMLSPDefinition" value="TestCodeFx.SPDefinition.xml"/--> + + <!--メッセージの言語を固定する--> + <!--GetMessage は、指定が無ければ CurrentUICulture から MSGDefinition_xx.xml を選ぶ。 + 期待結果は日本語で記録されているため、実行環境の表示言語に依存しないよう固定する。 + (英語環境では既定の MSGDefinition.xml=英語版に落ち、例外にならないので気付きにくい)--> + <add key="FxBusinessMessageCulture" value="ja-JP" /> <!-- Log4Netのコンフィグファイルへのパス --> <!-- リソース ファイルの場合 --> diff --git a/root/programs/CS/Frameworks/Tests/TestCode/Program.cs b/root/programs/CS/Frameworks/Tests/TestCode/Program.cs index 23427e9d7..4cabfef5e 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/Program.cs +++ b/root/programs/CS/Frameworks/Tests/TestCode/Program.cs @@ -8,6 +8,10 @@ namespace TestCode { /// <summary>Program</summary> + /// <remarks> + /// 何をテストしているか、ケースを書き足すときの決まりは README.md を参照。 + /// **結果ファイルとの比較で判定するため、環境で変わる値を出してはならない。** + /// </remarks> public class Program { /// <summary>Main</summary> @@ -36,6 +40,15 @@ public static void Main(string[] args) MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); TestFormatChecker.Root(); + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestStringVariableOperator.Root(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestStringExtractor.Root(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestUtil.Root(); + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); TestStringConverter.Root(); @@ -57,7 +70,30 @@ public static void Main(string[] args) MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); TestDeflateCompression.Root(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestResourceLoader.Root(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestZipV2.Root(); + #endregion + #region Dto + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestDto.Root(); + #endregion + #region Diagnostics + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestObjectInspector.Root(); + #endregion + #region Reflection + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestLatebind.Root(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestFastReflection.Root(); #endregion + // Db は TestDataAccess へ移した(#520)。 + // DB に接続するテストと前提が異なるため、プロジェクトを分けている。 #endregion #region Business diff --git a/root/programs/CS/Frameworks/Tests/TestCode/README.md b/root/programs/CS/Frameworks/Tests/TestCode/README.md new file mode 100644 index 000000000..2da272e99 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/README.md @@ -0,0 +1,187 @@ +# TestCode — 部品層(`Public`)のテスト + +`Touryo.Infrastructure.Public` を中心とした部品層の総合テスト。**DB には接続しない。** +データ アクセスは [`TestDataAccess`](../TestDataAccess/README.md) に分けてある(#520)。 + +コンソール EXE で、`Program.cs` が `Test*.Root()` を順に呼び、 +出力を `Result48.txt` / `ResultCore100.txt` に書く。 +判定はこのファイルとの比較で行う([`TESTING.md`](../../../../TESTING.md) が一次情報)。 + +``` +y_Build_TestCode_Public.bat … ビルド → 実行 → 結果ファイル出力 +``` + +`net48` と `core100` の 2 プロジェクトが `..\*.cs` を `Link` で共有する(実体は 1 つ)。 + +--- + +## 何をテストしているか + +`Program.cs` の呼び出し順に対応する。 + +### Basic + +| ファイル | 対象 | 見ていること | +|---|---|---| +| `TestOutputLog` | `Public.Log` | log4net / NLog へのログ出力(`LogIF`) | +| `TestGetMessageAndProperty` | `Framework.Common` / `Framework.Util` | `GetMessage`(メッセージ定義 XML)、`GetSharedProperty` | +| `TestStringChecker` | `Public.Str` | 数字・英字・かな・漢字・Shift_JIS の判定 | +| `TestFormatChecker` | `Public.Str` | 郵便番号・電話番号・日付などの書式判定 | +| `TestStringVariableOperator` | `Public.Str` | `a=1;b=2` 形式の解析と、環境変数の埋め込み(#522) | +| `TestStringExtractor` | `Public.Str` | クエリ文字列・XML 属性からの抽出、`XmlToString`(#522) | +| `TestUtil` | `Public.Util` | 型変換・配列操作・設定の読み取り・環境情報(#522) | +| `TestStringConverter` | `Public.Str` | 半角/全角・ひらがな/カタカナの変換 | +| `TestFormatConverter` | `Public.Str` | 西暦/和暦、数値の書式化 | +| `TestCustomEncode` | `Public.Str` | Base64URL・パーセント エンコード等 | +| `TestJISCode` | `Public.Str` | JIS コードの判定 | + +### Extension + +| ファイル | 対象 | 見ていること | +|---|---|---| +| `TestEnumToStringExtensions` | `Public.FastReflection` | 列挙体 ⇔ 文字列 | +| `TestXmlLib` | `Public.Xml` | XML の読み書き | +| `TestDeflateCompression` | `Public.IO` | Deflate の圧縮・伸張 | +| `TestResourceLoader` | `Public.IO` | ファイル・埋め込みリソースの読み取り(#522) | +| `TestZipV2` | `Public.IO` | ZIP の圧縮・解凍(`ZipperV2` / `UnZipperV2`、#524) | + +### Dto + +| ファイル | 対象 | 見ていること | +|---|---|---| +| `TestDto` | `Public.Dto` | `DataToPoco` / `PocoToPoco` / `DataToDictionary` の項目移送(#522) | + +### Diagnostics + +| ファイル | 対象 | 見ていること | +|---|---|---| +| `TestObjectInspector` | `Public.Diagnostics` | オブジェクトの再帰的な文字列化と**再帰の上限**(#522) | + +### Reflection + +| ファイル | 対象 | 見ていること | +|---|---|---| +| `TestLatebind` | `Public.Reflection` | 遅延バインドによる呼び出し(`NonPublic` を含む) | +| `TestFastReflection` | `Public.FastReflection` | `AccessorCacher` / `InstanceCreator` 等の高速リフレクション(#522) | + +`TestEmbedded.txt` は `TestResourceLoader` が読む埋め込みリソース。 +**`LogicalName` を `TestCode.TestEmbedded.txt` に固定している** +(既定のままだと `TestCodeFx` / `TestCodeCore` で名前が食い違うため)。 + +--- + +## テストを書き足すときの決まり + +結果ファイルとの比較で判定するため、**実行するたびに変わる値を出してはならない。** +`CompareResult.ps1` の正規化で吸収できるもの(日時・処理時間・GUID 等)もあるが、 +**吸収に頼らず、そもそも出さない**方がよい。 + +### 例外は必ず捕まえ、型名だけを出す + +捕まえないと `Program.Main` まで抜けて**実行が中断**し、 +さらに**パス入りのスタック トレースが結果ファイルに書き込まれる**(環境依存の差分になる)。 + +``` +場所 ...\ArrayOperator.cs:行 62 +``` + +メッセージ本文も出してはならない。**OS とランタイムの言語で変わる**ため +(CI は英語環境、ローカルは日本語環境)。 + +```csharp +catch (Exception ex) +{ + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole(caseName + " : 例外 " + ex.GetType().FullName); +} +``` + +### 環境で変わる値は「取れること」までに留める + +`EnvInfo`(マシン名・OS・ビット数)や `GetConfigParameter` の設定値がこれにあたる。 +設定値は **net48 と .NET (Core) でパス区切りが違う**ため、値そのものは比較できない。 + +```csharp +MyDebug.OutputDebugAndConsole( + "EnvInfo.MachineName が取れる : " + !string.IsNullOrEmpty(EnvInfo.MachineName)); +``` + +### 期待値は「出力をそのまま貼る」のではなく、**検算する** + +結果ファイルとの比較方式は、**実装が誤っていても、その誤った出力を「正」として固定してしまう。** +`OK` が出続けるので、後から気付けない。 + +**値が自明でないものは、実装を読んで手計算で確かめてから記録すること。** + +`ArrayOperator.GetLongFromByte` がこれで漏れた(#522)。 +桁の重みを `256 * j`(掛け算)で求めていたため 3 byte 目から誤っていたが、 +8 byte の出力をそのまま期待値にしていたため、いったん見逃した。 + +### 境界は必ず跨ぐ + +同じ `GetLongFromByte` は、**1〜2 byte だけを見ていると不具合に気付けない。** +`256 * 1 == 256 ^ 1` のため、2 byte までは誤った実装でも正しい値になる。 + +``` +2 byte : 258 ← 誤った実装でも一致する +3 byte : 66051 ← ここで初めて差が出る +``` + +**「たまたま一致する範囲」の外側にケースを置く。** + +### 日時は固定値を与える + +`DateTime.Now` を使わない。UTC で与えれば、時差のある環境でも同じ結果になる。 + +```csharp +DateTimeOffset dto = new DateTimeOffset(2026, 8, 6, 12, 34, 56, TimeSpan.Zero); +``` + +### `csproj` は 2 つとも直す + +`net48/TestCodeFx.csproj` と `core100/TestCodeCore.csproj` の**両方**に +`Compile` を足す。片方だけだと、そちらのフレームワークでしかテストが動かない。 + +### フレームワークが使うパッケージは、テスト側にも並べる + +**フレームワークは `HintPath` で参照しており、NuGet の推移的依存が効かない。** +`OpenTouryo.Public` が新しいパッケージを使い始めたら、 +`core100/TestCodeCore.csproj` にも同じ `PackageReference` を足す。 + +足りないと**ビルドは通るのに実行時に落ちる**。 + +``` +System.IO.FileNotFoundException: Could not load file or assembly +'ICSharpCode.SharpZipLib, Version=1.4.2.13, ...' +``` + +net48 側は `4_Build_CopyAssemblies.bat` が依存 DLL を `Build_net48` へ並べるため +顕在化しにくい。**.NET (Core) 側だけで落ちる**ことがある(#524 で踏んだ)。 + +--- + +## 記録している「仕様」(不具合ではない) + +読み違えやすい挙動は、**誤用したときの結果も含めて**ケースに残してある。 + +| 対象 | 挙動 | +|---|---| +| `PubCmnFunction.GetFileNameNoEx` | 第 2 引数は**パス区切り**。拡張子の区切りだと思って `'.'` を渡すと空文字が返る | +| `ArrayOperator.CopyArray` | **配列を伸ばせない。** コピー長が「コピー先配列の長さ」で固定のため、コピー先を大きくするとコピー元が足りず落ちる。書込開始位置を 0 より後ろにしても落ちる | +| `ArrayOperator.ShortenByteArray` | 単純な切り詰めではなく、**XOR で畳み込む**(暗号鍵の生成用) | +| `ArrayOperator.GetLongFromByte` | ビッグ エンディアン。8 byte で最上位ビットが立つと **Int64 の範囲を超えて負になる**(2 の補数として解釈した値) | +| `StringExtractor.GetParameterFromQueryString` | 「値が空」と「名前が無い」を**区別できない**(どちらも `""`) | +| `ObjectInspector` | 再帰の深さは **5 まで**。入口で加算・出口で減算するカウンタで抑えている | +| `Latebind` | `NonPublic` を含むため **private も呼べる**。呼び先の例外は `TargetInvocationException` に包まれる | + +--- + +## 差分が大量に出たときの読み方 + +**テストを足した直後は、差分件数が実態より大きく出る。** +`CompareResult.ps1` は `Compare-Object -SyncWindow 20` で比較するため、 +20 行を超える挿入があると以降の行が総崩れになる。 + +**合否(OK / NG)は正しい。誤るのは件数と一覧の見え方だけ。** +実差分を見たいときは `-SyncWindow` を外して突き合わせる。詳細は +[`TESTING.md`](../../../../TESTING.md) の「差分の『件数』は当てにならないことがある」。 diff --git a/root/programs/CS/Frameworks/Tests/TestCode/Result48.txt b/root/programs/CS/Frameworks/Tests/TestCode/Result48.txt index bd93ca737..55d78db7e 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/Result48.txt +++ b/root/programs/CS/Frameworks/Tests/TestCode/Result48.txt @@ -70,11 +70,11 @@ log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.Level log4net: Created Appender [OPERATION2] log4net: Adding appender named [OPERATION2] to logger [OPERATION]. log4net: Hierarchy Threshold [] -[2025/11/18 15:17:57,158],[DEBUG],[1],LogIF.DebugLog("ACCESS"); -[2025/11/18 15:17:57,174],[INFO ],[1],LogIF.InfoLog("ACCESS"); -[2025/11/18 15:17:57,175],[WARN ],[1],LogIF.WarnLog("ACCESS"); -[2025/11/18 15:17:57,175],[ERROR],[1],LogIF.ErrorLog("ACCESS"); -[2025/11/18 15:17:57,175],[FATAL],[1],LogIF.FatalLog("ACCESS"); +[2026/08/08 10:15:45,904],[DEBUG],[1],LogIF.DebugLog("ACCESS"); +[2026/08/08 10:15:45,912],[INFO ],[1],LogIF.InfoLog("ACCESS"); +[2026/08/08 10:15:45,913],[WARN ],[1],LogIF.WarnLog("ACCESS"); +[2026/08/08 10:15:45,913],[ERROR],[1],LogIF.ErrorLog("ACCESS"); +[2026/08/08 10:15:45,913],[FATAL],[1],LogIF.FatalLog("ACCESS"); ---------------------------------------------------------------------------------------------------- GetMessage: ~メッセージID:I0001に対応する記述(正常系)~ GetMessage: ~メッセージID:E0001に対応する記述(異常系)~ @@ -2170,6 +2170,105 @@ JpIpPhoneNumber_NoHyphen 08099999999: False 09099999999: False ---------------------------------------------------------------------------------------------------- +StringVariableOperator.GetPropsFromPropString +[1 組] a=1 + 件数 : 1 + A = 1 +[2 組] a=1;b=2 + 件数 : 2 + A = 1 + B = 2 +[値が空] a=;b=2 + 件数 : 2 + A = + B = 2 +[値に = を含む] a={=};b=2 + 件数 : 2 + A = = + B = 2 +[値に ; を含む] a={;};b=2 + 件数 : 2 + A = ; + B = 2 +[名前に = を含む] a{=}b=1 + 件数 : 1 + A=B = 1 +[= が無い] a + 件数 : 0 +[空文字] + 件数 : 0 +---------------------------------------------------------------------------------------------------- +StringVariableOperator.BuiltStringIntoEnvironmentVariable +[そのまま] abc → abc +[埋め込み] x%OPENTOURYO_TEST_VAR%y → xVALUEy +[2 回] %OPENTOURYO_TEST_VAR%-%OPENTOURYO_TEST_VAR% → VALUE-VALUE +[未定義] x%OPENTOURYO_NOT_EXIST%y → xy +[閉じていない] x%OPENTOURYO_TEST_VAR → x%OPENTOURYO_TEST_VAR +[null] (null) → (null) +[空文字] → +---------------------------------------------------------------------------------------------------- +StringExtractor.GetParameterFromQueryString +[先頭の値] a → "1" +[途中の値] b → "xyz" +[空の値] c → "" +[無い名前] z → "" +[クエリ無し] a → "" +[前方一致の紛れ] a → "1" +---------------------------------------------------------------------------------------------------- +StringExtractor.GetAttributeFromXml +[最初の属性] id → "1" +[2 番目の属性] name → "abc" +[無い属性] notexist → "" +---------------------------------------------------------------------------------------------------- +ToStringExtension.XmlToString +宣言なし : <root><child id="1">値</child></root> +インデントあり : +<root> + <child id="1">値</child> +</root> +---------------------------------------------------------------------------------------------------- +PubCmnFunction +ChangeType string → int : 123 (Int32) +ChangeType int → string : 123 (String) +ChangeType string → int? : 123 (Int32) +ChangeType null → int? : null +ChangeType string → decimal : 1.5 (Decimal) +ChangeType 変換できない : 例外 System.FormatException +GetUnderlyingType(int?) : Int32 +GetUnderlyingType(int) : (null) +GetUnderlyingType(string): (null) +ToUnixTime : 1786019696 +GetFileNameNoEx(パス付き) : a +GetFileNameNoEx(二重拡張子) : a.b +GetFileNameNoEx(拡張子なし) : +GetFileNameNoEx(区切りを「.」): "" +GetCurrentMethodName : GetCurrentMethodName +---------------------------------------------------------------------------------------------------- +ArrayOperator +CopyArray(3 → 2) : [1, 2] +CopyArray(3 → 5) : 例外 System.ArgumentException +CopyArray(読取開始位置をずらす) : [2, 3] +CopyArray(書込開始位置をずらす) : 例外 System.ArgumentException +CombineArray : [1, 2, 3, 4, 5] +ShortenByteArray(8 → 3) : [2, 15, 5] +ArrayOperator.GetLongFromByte +1 byte : 1 +2 byte : 258 +3 byte : 66051 +3 byte(上位のみ) : 65536 +8 byte : 72623859790382856 +8 byte(最上位ビット) : -1 +0 byte : 例外 System.ArgumentOutOfRangeException +9 byte : 例外 System.ArgumentOutOfRangeException +null : 例外 System.ArgumentNullException +---------------------------------------------------------------------------------------------------- +GetConfigParameter / EnvInfo +GetConfigValue(FxBusinessMessageCulture) : ja-JP +無いキー : null または空 +EnvInfo.MachineName が取れる : True +EnvInfo.OsVersionString が取れる : True +EnvInfo.ProcessBit が 32 または 64 : True +---------------------------------------------------------------------------------------------------- StringConverter.ToHankaku - アアア: アアア StringConverter.ToZenkaku - アアア: アアア StringConverter.ToHiragana - アアア: あああ @@ -2301,4 +2400,183 @@ DeflateCompression(FileStream)-2 > is working properly. -------------------------------------------------- DeflateCompression(MemoryStream) > is working properly. ---------------------------------------------------------------------------------------------------- +ResourceLoader +絶対パスで解決 : True +絶対パスで読み込み : リソースの内容 +環境変数入りで解決 : True +配置フォルダ基準 : True +見つからない(解決) : null +見つからない(Exists): False +見つからない(例外) : System.ArgumentException +空文字(解決) : null +null(解決) : null +---------------------------------------------------------------------------------------------------- +EmbeddedResourceLoader +存在する : True +読み込み : 埋め込まれたリソースの内容 / embedded resource +存在しない : False +存在しない(例外) : System.ArgumentException +---------------------------------------------------------------------------------------------------- +ZipperV2 → UnZipperV2(往復) +解凍した件数 : 4 + root/a.txt + root/b.log + root/sub/c.txt + root/日本語.txt +内容が一致 : True +---------------------------------------------------------------------------------------------------- +暗号化 +[暗号化なし] 往復して一致 : True +[PkzipWeak] 往復して一致 : True +[WinZipAes128] 往復して一致 : True +[WinZipAes256] 往復して一致 : True +[パスワード誤り] 例外 ICSharpCode.SharpZipLib.Zip.ZipException +[パスワード未指定] 例外 System.ArgumentException +---------------------------------------------------------------------------------------------------- +選択デリゲート +[圧縮時に .log を除く] + a.txt + sub/c.txt + 日本語.txt +[上書き時の動作] + DoNotOverwrite の解凍件数 : 0 + OverwriteSilently の解凍件数 : 3 + Throw : 例外 System.IO.IOException +[上書きの問い合わせ] + 上書きすると答えた : 問い合わせ 3 件 / 解凍 3 件 + 答えない(既定) : 解凍 0 件 + 打ち切る : 解凍 0 件 +---------------------------------------------------------------------------------------------------- +進捗イベント +SaveProgress : Saving_Started, Saving_BeforeWriteEntry, Saving_EntryBytesRead, Saving_AfterWriteEntry, Saving_Completed +ExtractProgress : Extracting_Started, Extracting_BeforeExtractEntry, Extracting_EntryBytesWritten, Extracting_AfterExtractEntry, Extracting_Completed +無圧縮より BestCompression の方が小さい : True +---------------------------------------------------------------------------------------------------- +DataToPoco +[DataTableToList : 名前が一致] +件数 : 2 +OrderID=1, Note=x, Qty=0 +OrderID=2, Note=(null), Qty=0 +[DataTableToPOCO : 先頭行だけ] +OrderID=1, Note=x, Qty=0 +[マップ無 : 列名が PK_OrderID] +件数 : 1 +OrderID=0, Note=y, Qty=0 +[マップ有 : OrderID → PK_OrderID] +件数 : 1 +OrderID=9, Note=y, Qty=0 +---------------------------------------------------------------------------------------------------- +PocoToPoco +[Map : 同名のみ] +OrderID=3, Note=z, Qty=0 +[Map : Qty ← OrderID] +OrderID=3, Note=z, Qty=3 +---------------------------------------------------------------------------------------------------- +DataToDictionary +OrderID : 4 +Note : w +OrderDate : 2026/08/06 12:34:56 +---------------------------------------------------------------------------------------------------- +DTTable +[FromDataTable] +表名 : TestOrders +列 : OrderID, Note +行 : 5, a +行 : 6, b +[文字列との往復] +表の数 : 1 +表名 : TestOrders +列 : OrderID, Note +行 : 5, a +行 : 6, b +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : 基本の型 +[null] +null +[int] +123 +[string] +"あいう" +[bool] +True +[空文字] +"" +[int[]] +[1, 2, 3] +[int[] (8 要素)] +[1, 2, 3, 4, 5, 6, 7, 8] +[List<string>] +["a", "b"] +[Dictionary] +[x = 1, y = 2] +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : POCO +[入れ子が null] +[Name = "外側", Inner = null, Numbers = [10, 20]] +[入れ子に値] +[Name = "外側", Inner = [Code = "C1", Value = 99], Numbers = [10, 20]] +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : 深さの上限 +[入れ子 8 段] +[Level = 1, Child = [Level = 2, Child = [Level = 3, Child = [Level = 4, Child = [Level = -over-, Child = -over-]]]]] +[循環参照] +[Level = 1, Child = [Level = 1, Child = [Level = 1, Child = [Level = 1, Child = [Level = -over-, Child = -over-]]]]] +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : 日時 +[DateTime(書式あり)] +2026/08/06 12:34:56 +[TimeSpan(書式あり)] +1.02:03:04 +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : 除外 +[除外なし] +[Name = "外側", Inner = [Code = "C2", Value = 1], Numbers = [1]] +[InnerPoco を除外] +[Name = "外側", Inner = excluded. TestCode.TestObjectInspector+InnerPoco, Numbers = [1]] +---------------------------------------------------------------------------------------------------- +Latebind.InvokeMethod +[引数なし] PublicMethod +[引数あり] WithArgs:1:x +[static] StaticMethod +[private] PrivateMethod +[基底のメソッド] BaseMethod +[呼び先が例外] 例外 : System.Reflection.TargetInvocationException +---------------------------------------------------------------------------------------------------- +Latebind : メソッドが無いとき +[InvokeMethod] 例外 : System.ArgumentException +[InvokeMethod_NoErr] null +---------------------------------------------------------------------------------------------------- +Latebind : オーバーロード +[引数 1 個] Overloaded(int):1 +[引数 2 個] Overloaded(int,int):1:2 +[引数 3 個(該当なし)] 例外 : System.ArgumentException +---------------------------------------------------------------------------------------------------- +Latebind : 型とメソッドの確認 +CheckTypeOfBaseClass(Target, TargetBase) : True +CheckTypeOfBaseClass(Target, string) : False +CheckTypeOfMethodByName(PublicMethod) : True +CheckTypeOfMethodByName(PrivateMethod) : True +CheckTypeOfMethodByName(NotExist) : False +---------------------------------------------------------------------------------------------------- +InstanceCreator<T>.Factory +生成できた : True +別のインスタンス : True +既定値(Id) : 0 +既定値(Name) : (null) +---------------------------------------------------------------------------------------------------- +AccessorCacher.CacheAccessor +件数 : 5 +Count : 型=Nullable`1, 実体型=Int32, Get=True, Set=True +Field : 型=String, 実体型=(null), Get=True, Set=True +Id : 型=Int32, 実体型=(null), Get=True, Set=True +Name : 型=String, 実体型=(null), Get=True, Set=True +ReadOnly : 型=String, 実体型=(null), Get=True, Set=False +Set → Get : 設定した値 +再取得しても同じ : True +---------------------------------------------------------------------------------------------------- +CompiledExpressionCreater +プロパティ Id : 42 +フィールド Field : フィールドの値 +存在しないメンバ : 例外 System.ArgumentException +---------------------------------------------------------------------------------------------------- log4net: Shutdown called on Hierarchy [log4net-default-repository] diff --git a/root/programs/CS/Frameworks/Tests/TestCode/ResultCore100.txt b/root/programs/CS/Frameworks/Tests/TestCode/ResultCore100.txt index f223484f4..13a8c76f0 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/ResultCore100.txt +++ b/root/programs/CS/Frameworks/Tests/TestCode/ResultCore100.txt @@ -1,2323 +1,2601 @@ ----------------------------------------------------------------------------------------------------- -log4net: Configuration update mode [Merge]. -log4net: Retrieving an instance of log4net.Repository.Logger for logger [ACCESS]. -log4net: Setting [ACCESS] additivity to [True]. -log4net: Logger [ACCESS] Level string is [All]. -log4net: Logger [ACCESS] level set to [name="ALL",value=-2147483648]. -log4net: Loading Appender [ACCESS2] type: [log4net.Appender.ConsoleAppender] -log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Setting Property [ConversionPattern] to String value [[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline] -log4net: Converter [literal] Option [[] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [date] Option [yyyy/MM/dd HH:mm:ss,fff] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [level] Option [] Format [min=5,max=2147483647,leftAlign=True] -log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [thread] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [literal] Option [],] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Setting Property [Layout] to object [log4net.Layout.PatternLayout] -log4net: Setting Property [LevelMin] to Level value [DEBUG] -log4net: Setting Property [LevelMax] to Level value [FATAL] -log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.LevelRangeFilter] -log4net: Created Appender [ACCESS2] -log4net: Adding appender named [ACCESS2] to logger [ACCESS]. -log4net: Retrieving an instance of log4net.Repository.Logger for logger [SQLTRACE]. -log4net: Setting [SQLTRACE] additivity to [True]. -log4net: Logger [SQLTRACE] Level string is [All]. -log4net: Logger [SQLTRACE] level set to [name="ALL",value=-2147483648]. -log4net: Loading Appender [SQLTRACE2] type: [log4net.Appender.ConsoleAppender] -log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Setting Property [ConversionPattern] to String value [[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline] -log4net: Converter [literal] Option [[] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [date] Option [yyyy/MM/dd HH:mm:ss,fff] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [level] Option [] Format [min=5,max=2147483647,leftAlign=True] -log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [thread] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [literal] Option [],] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Setting Property [Layout] to object [log4net.Layout.PatternLayout] -log4net: Setting Property [LevelMin] to Level value [DEBUG] -log4net: Setting Property [LevelMax] to Level value [FATAL] -log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.LevelRangeFilter] -log4net: Created Appender [SQLTRACE2] -log4net: Adding appender named [SQLTRACE2] to logger [SQLTRACE]. -log4net: Retrieving an instance of log4net.Repository.Logger for logger [OPERATION]. -log4net: Setting [OPERATION] additivity to [True]. -log4net: Logger [OPERATION] Level string is [All]. -log4net: Logger [OPERATION] level set to [name="ALL",value=-2147483648]. -log4net: Loading Appender [OPERATION2] type: [log4net.Appender.ConsoleAppender] -log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Setting Property [ConversionPattern] to String value [[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline] -log4net: Converter [literal] Option [[] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [date] Option [yyyy/MM/dd HH:mm:ss,fff] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [level] Option [] Format [min=5,max=2147483647,leftAlign=True] -log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [thread] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [literal] Option [],] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] -log4net: Setting Property [Layout] to object [log4net.Layout.PatternLayout] -log4net: Setting Property [LevelMin] to Level value [DEBUG] -log4net: Setting Property [LevelMax] to Level value [FATAL] -log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.LevelRangeFilter] -log4net: Created Appender [OPERATION2] -log4net: Adding appender named [OPERATION2] to logger [OPERATION]. -log4net: Hierarchy Threshold [] -[2025/11/18 04:03:14,431],[DEBUG],[2],LogIF.DebugLog("ACCESS"); -[2025/11/18 04:03:14,445],[INFO ],[2],LogIF.InfoLog("ACCESS"); -[2025/11/18 04:03:14,445],[WARN ],[2],LogIF.WarnLog("ACCESS"); -[2025/11/18 04:03:14,446],[ERROR],[2],LogIF.ErrorLog("ACCESS"); -[2025/11/18 04:03:14,446],[FATAL],[2],LogIF.FatalLog("ACCESS"); ----------------------------------------------------------------------------------------------------- -GetMessage: ~メッセージID:I0001に対応する記述(正常系)~ -GetMessage: ~メッセージID:E0001に対応する記述(異常系)~ --------------------------------------------------- -GetSharedProperty: てすと1 -GetSharedProperty: てすと3 ----------------------------------------------------------------------------------------------------- -StringChecker.IsNumbers - あああ: False -StringChecker.IsNumbers - 111: True -StringChecker.IsNumbers_Hankaku - あああ: False -StringChecker.IsNumbers_Hankaku - 111111: True -StringChecker.IsNumbers_Zenkaku - あああ: False -StringChecker.IsNumbers_Zenkaku - 111: True ----------------------------------------------------------------------------------------------------- -StringChecker.IsAlphabet - あああ: False -StringChecker.IsAlphabet - aaa: True -StringChecker.IsAlphabet_Hankaku - あああ: False -StringChecker.IsAlphabet_Hankaku - aaaaaa: True -StringChecker.IsAlphabet_Zenkaku - あああ: False -StringChecker.IsAlphabet_Zenkaku - aaa: True ----------------------------------------------------------------------------------------------------- -StringChecker.IsHiragana - aaa: False -StringChecker.IsHiragana - あああ: True ----------------------------------------------------------------------------------------------------- -StringChecker.IsKatakana - あああ: False -StringChecker.IsKatakana - アアア: True -StringChecker.IsKatakana_Zenkaku - あああ: False -StringChecker.IsKatakana_Zenkaku - アアア: True -StringChecker.IsKatakana_Zenkaku - アアア: False -StringChecker.IsKatakana_Zenkaku - アアアアアア: True ----------------------------------------------------------------------------------------------------- -StringChecker.IsKanji - あああ: False -StringChecker.IsKanji - 亜亜亜: True ----------------------------------------------------------------------------------------------------- -StringChecker.IsShift_Jis - 鱓鱓鱓: False -StringChecker.IsShift_Jis - 亜亜亜: True -StringChecker.IsShift_Jis_Zenkaku - aaaaaa: False -StringChecker.IsShift_Jis_Zenkaku - 亜亜亜: True -StringChecker.IsShift_Jis_Hankaku - aaa: False -StringChecker.IsShift_Jis_Hankaku - aaaaaa: True ----------------------------------------------------------------------------------------------------- -TestFormatChecker.IsJpZipCode -JpZipCode_Hyphen -000-0000: True -aaa-aaaa: False -0000-00000: False -0000-0000: False -000-00000: False -00-000: False -00-0000: False -000-000: False -JpZipKuCode1_Hyphen -000-00: True -aaa-aa: False -0000-000: False -0000-00: False -000-000: False -00-0: False -00-00: False -000-0: False -JpZipKuCode2_Hyphen -000: True -aaa: False -0000: False -00: False -JpZipCode_NoHyphen -0000000: True -aaaaaaa: False -00000000: False -000000: False -JpZipKuCode1_NoHyphen -00000: True -aaaaa: False -000000: False -0000: False -JpZipKuCode2_NoHyphen -000: True -aaa: False -0000: False -00: False --------------------------------------------------- -TestFormatChecker.IsJpZipCode_Hyphen -JpZipCode_Hyphen -000-0000: True -aaa-aaaa: False -0000-00000: False -0000-0000: False -000-00000: False -00-000: False -00-0000: False -000-000: False -JpZipKuCode1_Hyphen -000-00: True -aaa-aa: False -0000-000: False -0000-00: False -000-000: False -00-0: False -00-00: False -000-0: False -JpZipKuCode2_Hyphen -000: True -aaa: False -0000: False -00: False --------------------------------------------------- -TestFormatChecker.IsJpZipCode_NoHyphen -JpZipCode_NoHyphen -0000000: True -aaaaaaa: False -00000000: False -000000: False -JpZipKuCode1_NoHyphen -00000: True -aaaaa: False -000000: False -0000: False -JpZipKuCode2_NoHyphen -000: True -aaa: False -0000: False -00: False --------------------------------------------------- -TestFormatChecker.IsJpZipCode7 -JpZipCode_Hyphen -000-0000: True -aaa-aaaa: False -0000-00000: False -0000-0000: False -000-00000: False -00-000: False -00-0000: False -000-000: False -JpZipCode_NoHyphen -0000000: True -aaaaaaa: False -00000000: False -000000: False --------------------------------------------------- -TestFormatChecker.IsJpZipCode7_Hyphen -JpZipCode_Hyphen -000-0000: True -aaa-aaaa: False -0000-00000: False -0000-0000: False -000-00000: False -00-000: False -00-0000: False -000-000: False --------------------------------------------------- -TestFormatChecker.IsJpZipCode7_NoHyphen -JpZipCode_NoHyphen -0000000: True -aaaaaaa: False -00000000: False -000000: False --------------------------------------------------- -TestFormatChecker.IsJpZipCode5 -JpZipKuCode1_Hyphen -000-00: True -aaa-aa: False -0000-000: False -0000-00: False -000-000: False -00-0: False -00-00: False -000-0: False -JpZipKuCode2_Hyphen -000: True -aaa: False -0000: False -00: False -JpZipKuCode1_NoHyphen -00000: True -aaaaa: False -000000: False -0000: False -JpZipKuCode2_NoHyphen -000: True -aaa: False -0000: False -00: False --------------------------------------------------- -TestFormatChecker.IsJpZipCode5_Hyphen -JpZipKuCode1_Hyphen -000-00: True -aaa-aa: False -0000-000: False -0000-00: False -000-000: False -00-0: False -00-00: False -000-0: False -JpZipKuCode2_Hyphen -000: True -aaa: False -0000: False -00: False --------------------------------------------------- -TestFormatChecker.IsJpZipCode5_NoHyphen -JpZipKuCode1_NoHyphen -00000: True -aaaaa: False -000000: False -0000: False -JpZipKuCode2_NoHyphen -000: True -aaa: False -0000: False -00: False --------------------------------------------------- -TestFormatChecker.IsJpTelephoneNumber -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: True -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: True -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: True -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: True -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: True -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: True -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: True -020-999-9999: True -020-9999-999: False -060-9999-9999: True -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: True -060-999-9999: True -060-9999-999: False -070-9999-9999: True -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: True -070-999-9999: True -070-9999-999: False -080-9999-9999: True -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: True -080-999-9999: True -080-9999-999: False -090-9999-9999: True -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: True -090-999-9999: True -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: True -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: True -06099999999: True -07099999999: True -08099999999: True -09099999999: True -01099999999: False -03099999999: False -04099999999: False -05099999999: True -JpIpPhoneNumber_Hyphen -050-9999-9999: True -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: True -050-999-9999: True -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: True -030-9999-9999: False -040-9999-9999: False -060-9999-9999: True -070-9999-9999: True -080-9999-9999: True -090-9999-9999: True -JpIpPhoneNumber_NoHyphen -05099999999: True -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: True -01099999999: False -02099999999: True -03099999999: False -04099999999: False -06099999999: True -07099999999: True -08099999999: True -09099999999: True --------------------------------------------------- -TestFormatChecker.IsJpTelephoneNumber_Hyphen -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: True -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: True -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: True -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: True -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: False -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: True -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: True -020-999-9999: True -020-9999-999: False -060-9999-9999: True -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: True -060-999-9999: True -060-9999-999: False -070-9999-9999: True -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: True -070-999-9999: True -070-9999-999: False -080-9999-9999: True -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: True -080-999-9999: True -080-9999-999: False -090-9999-9999: True -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: True -090-999-9999: True -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: False -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False -01099999999: False -03099999999: False -04099999999: False -05099999999: False -JpIpPhoneNumber_Hyphen -050-9999-9999: True -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: True -050-999-9999: True -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: True -030-9999-9999: False -040-9999-9999: False -060-9999-9999: True -070-9999-9999: True -080-9999-9999: True -090-9999-9999: True -JpIpPhoneNumber_NoHyphen -05099999999: False -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: False -01099999999: False -02099999999: False -03099999999: False -04099999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False --------------------------------------------------- -TestFormatChecker.IsJpTelephoneNumber_NoHyphen -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: False -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: False -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: False -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: False -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: True -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: False -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: False -020-999-9999: False -020-9999-999: False -060-9999-9999: False -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: False -060-999-9999: False -060-9999-999: False -070-9999-9999: False -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: False -070-999-9999: False -070-9999-999: False -080-9999-9999: False -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: False -080-999-9999: False -080-9999-999: False -090-9999-9999: False -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: False -090-999-9999: False -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: True -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: True -06099999999: True -07099999999: True -08099999999: True -09099999999: True -01099999999: False -03099999999: False -04099999999: False -05099999999: True -JpIpPhoneNumber_Hyphen -050-9999-9999: False -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: False -050-999-9999: False -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: False -030-9999-9999: False -040-9999-9999: False -060-9999-9999: False -070-9999-9999: False -080-9999-9999: False -090-9999-9999: False -JpIpPhoneNumber_NoHyphen -05099999999: True -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: True -01099999999: False -02099999999: True -03099999999: False -04099999999: False -06099999999: True -07099999999: True -08099999999: True -09099999999: True --------------------------------------------------- -TestFormatChecker.IsJpFixedLinePhoneNumber -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: True -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: True -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: True -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: True -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: True -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: False -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: True -020-999-9999: True -020-9999-999: False -060-9999-9999: False -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: True -060-999-9999: True -060-9999-999: False -070-9999-9999: False -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: True -070-999-9999: True -070-9999-999: False -080-9999-9999: False -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: True -080-999-9999: True -080-9999-999: False -090-9999-9999: False -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: True -090-999-9999: True -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: False -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: True -06099999999: False -07099999999: False -08099999999: False -09099999999: False -01099999999: False -03099999999: False -04099999999: False -05099999999: False -JpIpPhoneNumber_Hyphen -050-9999-9999: False -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: True -050-999-9999: True -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: False -030-9999-9999: False -040-9999-9999: False -060-9999-9999: False -070-9999-9999: False -080-9999-9999: False -090-9999-9999: False -JpIpPhoneNumber_NoHyphen -05099999999: False -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: True -01099999999: False -02099999999: False -03099999999: False -04099999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False --------------------------------------------------- -TestFormatChecker.IsJpFixedLinePhoneNumber_Hyphen -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: True -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: True -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: True -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: True -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: False -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: False -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: True -020-999-9999: True -020-9999-999: False -060-9999-9999: False -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: True -060-999-9999: True -060-9999-999: False -070-9999-9999: False -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: True -070-999-9999: True -070-9999-999: False -080-9999-9999: False -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: True -080-999-9999: True -080-9999-999: False -090-9999-9999: False -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: True -090-999-9999: True -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: False -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False -01099999999: False -03099999999: False -04099999999: False -05099999999: False -JpIpPhoneNumber_Hyphen -050-9999-9999: False -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: True -050-999-9999: True -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: False -030-9999-9999: False -040-9999-9999: False -060-9999-9999: False -070-9999-9999: False -080-9999-9999: False -090-9999-9999: False -JpIpPhoneNumber_NoHyphen -05099999999: False -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: False -01099999999: False -02099999999: False -03099999999: False -04099999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False --------------------------------------------------- -TestFormatChecker.IsJpFixedLinePhoneNumber_NoHyphen -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: False -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: False -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: False -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: False -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: True -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: False -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: False -020-999-9999: False -020-9999-999: False -060-9999-9999: False -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: False -060-999-9999: False -060-9999-999: False -070-9999-9999: False -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: False -070-999-9999: False -070-9999-999: False -080-9999-9999: False -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: False -080-999-9999: False -080-9999-999: False -090-9999-9999: False -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: False -090-999-9999: False -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: False -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: True -06099999999: False -07099999999: False -08099999999: False -09099999999: False -01099999999: False -03099999999: False -04099999999: False -05099999999: False -JpIpPhoneNumber_Hyphen -050-9999-9999: False -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: False -050-999-9999: False -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: False -030-9999-9999: False -040-9999-9999: False -060-9999-9999: False -070-9999-9999: False -080-9999-9999: False -090-9999-9999: False -JpIpPhoneNumber_NoHyphen -05099999999: False -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: True -01099999999: False -02099999999: False -03099999999: False -04099999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False --------------------------------------------------- -TestFormatChecker.IsJpCellularPhoneNumber -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: False -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: False -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: False -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: False -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: False -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: True -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: False -020-999-9999: False -020-9999-999: False -060-9999-9999: True -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: False -060-999-9999: False -060-9999-999: False -070-9999-9999: True -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: False -070-999-9999: False -070-9999-999: False -080-9999-9999: True -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: False -080-999-9999: False -080-9999-999: False -090-9999-9999: True -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: False -090-999-9999: False -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: True -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: False -06099999999: True -07099999999: True -08099999999: True -09099999999: True -01099999999: False -03099999999: False -04099999999: False -05099999999: False -JpIpPhoneNumber_Hyphen -050-9999-9999: False -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: False -050-999-9999: False -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: True -030-9999-9999: False -040-9999-9999: False -060-9999-9999: True -070-9999-9999: True -080-9999-9999: True -090-9999-9999: True -JpIpPhoneNumber_NoHyphen -05099999999: False -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: False -01099999999: False -02099999999: True -03099999999: False -04099999999: False -06099999999: True -07099999999: True -08099999999: True -09099999999: True --------------------------------------------------- -TestFormatChecker.IsJpCellularPhoneNumber_Hyphen -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: False -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: False -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: False -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: False -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: False -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: True -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: False -020-999-9999: False -020-9999-999: False -060-9999-9999: True -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: False -060-999-9999: False -060-9999-999: False -070-9999-9999: True -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: False -070-999-9999: False -070-9999-999: False -080-9999-9999: True -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: False -080-999-9999: False -080-9999-999: False -090-9999-9999: True -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: False -090-999-9999: False -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: False -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False -01099999999: False -03099999999: False -04099999999: False -05099999999: False -JpIpPhoneNumber_Hyphen -050-9999-9999: False -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: False -050-999-9999: False -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: True -030-9999-9999: False -040-9999-9999: False -060-9999-9999: True -070-9999-9999: True -080-9999-9999: True -090-9999-9999: True -JpIpPhoneNumber_NoHyphen -05099999999: False -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: False -01099999999: False -02099999999: False -03099999999: False -04099999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False --------------------------------------------------- -TestFormatChecker.IsJpCellularPhoneNumber_NoHyphen -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: False -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: False -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: False -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: False -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: False -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: False -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: False -020-999-9999: False -020-9999-999: False -060-9999-9999: False -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: False -060-999-9999: False -060-9999-999: False -070-9999-9999: False -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: False -070-999-9999: False -070-9999-999: False -080-9999-9999: False -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: False -080-999-9999: False -080-9999-999: False -090-9999-9999: False -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: False -090-999-9999: False -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: True -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: False -06099999999: True -07099999999: True -08099999999: True -09099999999: True -01099999999: False -03099999999: False -04099999999: False -05099999999: False -JpIpPhoneNumber_Hyphen -050-9999-9999: False -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: False -050-999-9999: False -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: False -030-9999-9999: False -040-9999-9999: False -060-9999-9999: False -070-9999-9999: False -080-9999-9999: False -090-9999-9999: False -JpIpPhoneNumber_NoHyphen -05099999999: False -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: False -01099999999: False -02099999999: True -03099999999: False -04099999999: False -06099999999: True -07099999999: True -08099999999: True -09099999999: True --------------------------------------------------- -TestFormatChecker.IsJpIpPhoneNumber -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: False -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: False -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: False -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: False -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: False -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: False -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: False -020-999-9999: False -020-9999-999: False -060-9999-9999: False -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: False -060-999-9999: False -060-9999-999: False -070-9999-9999: False -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: False -070-999-9999: False -070-9999-999: False -080-9999-9999: False -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: False -080-999-9999: False -080-9999-999: False -090-9999-9999: False -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: False -090-999-9999: False -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: False -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False -01099999999: False -03099999999: False -04099999999: False -05099999999: True -JpIpPhoneNumber_Hyphen -050-9999-9999: True -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: False -050-999-9999: False -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: False -030-9999-9999: False -040-9999-9999: False -060-9999-9999: False -070-9999-9999: False -080-9999-9999: False -090-9999-9999: False -JpIpPhoneNumber_NoHyphen -05099999999: True -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: False -01099999999: False -02099999999: False -03099999999: False -04099999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False --------------------------------------------------- -TestFormatChecker.IsJpIpPhoneNumber_Hyphen -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: False -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: False -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: False -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: False -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: False -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: False -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: False -020-999-9999: False -020-9999-999: False -060-9999-9999: False -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: False -060-999-9999: False -060-9999-999: False -070-9999-9999: False -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: False -070-999-9999: False -070-9999-999: False -080-9999-9999: False -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: False -080-999-9999: False -080-9999-999: False -090-9999-9999: False -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: False -090-999-9999: False -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: False -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False -01099999999: False -03099999999: False -04099999999: False -05099999999: False -JpIpPhoneNumber_Hyphen -050-9999-9999: True -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: False -050-999-9999: False -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: False -030-9999-9999: False -040-9999-9999: False -060-9999-9999: False -070-9999-9999: False -080-9999-9999: False -090-9999-9999: False -JpIpPhoneNumber_NoHyphen -05099999999: False -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: False -01099999999: False -02099999999: False -03099999999: False -04099999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False --------------------------------------------------- -TestFormatChecker.IsJpIpPhoneNumber_NoHyphen -JpFixedLinePhoneNumber_Hyphen -09999-9-9999: False -99999-9-9999: False -0aaaa-a-aaaa: False -099999-9-9999: False -09999-99-9999: False -09999-9-99999: False -0999--999: False -0999-9-9999: False -09999--9999: False -09999-9-999: False -0999-99-9999: False -9999-99-9999: False -0aaa-aa-aaaa: False -09999-999-99999: False -09999-99-9999: False -0999-999-9999: False -0999-99-99999: False -099-9-999: False -099-99-9999: False -0999-9-9999: False -0999-99-999: False -099-999-9999: False -999-999-9999: False -0aa-aaa-aaaa: False -0999-9999-99999: False -0999-999-9999: False -099-9999-9999: False -099-999-99999: False -09-99-999: False -09-999-9999: False -099-99-9999: False -099-999-999: False -09-9999-9999: False -99-9999-9999: False -0a-aaaa-aaaa: False -099-99999-99999: False -099-9999-9999: False -09-99999-9999: False -09-9999-99999: False -0-999-999: False -0-9999-9999: False -09-999-9999: False -09-9999-999: False -JpFixedLinePhoneNumber_NoHyphen -0999999999: False -9999999999: False -0aaaaaaaaa: False -09999999999: False -099999999: False -JpCellularPhoneNumber_Hyphen -020-9999-9999: False -929-9999-9999: False -020-aaaa-aaaa: False -0209-99999-99999: False -0209-9999-9999: False -020-99999-9999: False -020-9999-99999: False -02-999-999: False -02-9999-9999: False -020-999-9999: False -020-9999-999: False -060-9999-9999: False -969-9999-9999: False -060-aaaa-aaaa: False -0609-99999-99999: False -0609-9999-9999: False -060-99999-9999: False -060-9999-99999: False -06-999-999: False -06-9999-9999: False -060-999-9999: False -060-9999-999: False -070-9999-9999: False -979-9999-9999: False -070-aaaa-aaaa: False -0709-99999-99999: False -0709-9999-9999: False -070-99999-9999: False -070-9999-99999: False -07-999-999: False -07-9999-9999: False -070-999-9999: False -070-9999-999: False -080-9999-9999: False -989-9999-9999: False -080-aaaa-aaaa: False -0809-99999-99999: False -0809-9999-9999: False -080-99999-9999: False -080-9999-99999: False -08-999-999: False -08-9999-9999: False -080-999-9999: False -080-9999-999: False -090-9999-9999: False -999-9999-9999: False -090-aaaa-aaaa: False -0909-99999-99999: False -0909-9999-9999: False -090-99999-9999: False -090-9999-99999: False -09-999-999: False -09-9999-9999: False -090-999-9999: False -090-9999-999: False -JpCellularPhoneNumber_NoHyphen -02099999999: False -92999999999: False -020aaaaaaaa: False -020999999999: False -0209999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False -01099999999: False -03099999999: False -04099999999: False -05099999999: True -JpIpPhoneNumber_Hyphen -050-9999-9999: False -959-9999-9999: False -050-aaaa-aaaa: False -0509-99999-99999: False -0509-9999-9999: False -050-99999-9999: False -050-9999-99999: False -05-999-999: False -05-9999-9999: False -050-999-9999: False -050-9999-999: False -9999999999999: False -010-9999-9999: False -020-9999-9999: False -030-9999-9999: False -040-9999-9999: False -060-9999-9999: False -070-9999-9999: False -080-9999-9999: False -090-9999-9999: False -JpIpPhoneNumber_NoHyphen -05099999999: True -95999999999: False -050aaaaaaaa: False -050999999999: False -0509999999: False -01099999999: False -02099999999: False -03099999999: False -04099999999: False -06099999999: False -07099999999: False -08099999999: False -09099999999: False ----------------------------------------------------------------------------------------------------- -StringConverter.ToHankaku - アアア: アアア -StringConverter.ToZenkaku - アアア: アアア -StringConverter.ToHiragana - アアア: あああ -StringConverter.ToKatakana - あああ: アアア ----------------------------------------------------------------------------------------------------- -FormatConverter.SeirekiToWareki -1977/4/24, ggy年M月d日(ddd): 昭和52年4月24日(日) -1977/4/24, ggy年M月d日(ddd)H:m:s: 昭和52年4月24日(日)0:0:0 -1977/4/24 19:15:12, ggy年M月d日(ddd): 昭和52年4月24日(日) -1977/4/24 19:15:12, ggy年M月d日(ddd)H:m:s: 昭和52年4月24日(日)19:15:12 -1977/4/24 19:15:12, ggy年M月d日(ddd)tt h:m:s: 昭和52年4月24日(日)午後 7:15:12 -1992/2/6 1:1:1, ggyy年MM月dd日 dddd HH:mm:ss: 平成04年02月06日 木曜日 01:01:01 -1992/2/6 13:1:1, ggyy年MM月dd日 dddd tt hh:mm:ss: 平成04年02月06日 木曜日 午後 01:01:01 --------------------------------------------------- -FormatConverter.WarekiToSeireki -昭和52年4月24日(日), ggy年M月d日(ddd): 1977/04/24 0:00:00 -昭和52年4月24日(日)19:15:12, ggy年M月d日(ddd)H:m:s: 1977/04/24 19:15:12 -昭和52年4月24日(日)午後 7:15:12, ggy年M月d日(ddd)tt h:m:s: 1977/04/24 19:15:12 -平成04年02月06日 木曜日 01:01:01, ggyy年MM月dd日 dddd HH:mm:ss: 1992/02/06 1:01:01 -平成04年02月06日 木曜日 午後 01:01:01, ggyy年MM月dd日 dddd tt hh:mm:ss: 1992/02/06 13:01:01 --------------------------------------------------- -FormatConverter.AddFigure3 -12,345 -123,456,789 -123.45 -12,345.6789 --12,345 --123,456,789 --123.45 --12,345.6789 -12,345 -123,456,789 -123.45 -12,345.6789 --12,345 --123,456,789 --123.45 --12,345.6789 ----------------------------------------------------------------------------------------------------- -FormatConverter.AddFigure4 -1,2345 -1,2345,6789 -123.45 -1,2345.6789 --1,2345 --1,2345,6789 --123.45 --1,2345.6789 -1,2345 -1,2345,6789 -123.45 -1,2345.6789 --1,2345 --1,2345,6789 --123.45 --1,2345.6789 ----------------------------------------------------------------------------------------------------- -FormatConverter.Suppress -"", 10, '@': @@@@@@@@@@ -"123456789", 0, '@': 123456789 -"123456789", 1, '@': 123456789 -"123456789", 5, '@': 123456789 -"123456789", 9, '@': 123456789 -"123456789", 10, '@': @123456789 -"123456789", 11, '@': @@123456789 -"123456789", 20, '@': @@@@@@@@@@@123456789 -"", 10, '@': @@@@@@@@@@ -"123456789", 0, '@': abcdefg -"123456789", 1, '@': abcdefg -"123456789", 5, '@': abcdefg -"123456789", 9, '@': @@abcdefg -"123456789", 10, '@': @@@abcdefg -"123456789", 11, '@': @@@@abcdefg -"123456789", 20, '@': @@@@@@@@@@@@@abcdefg ----------------------------------------------------------------------------------------------------- -CustomEncode.HtmlEncode: " id="txtXXXXX" /><script type="text/javascript">alert("XSS!!!")</script><input name="txtXXXXX" type="text" value=" ----------------------------------------------------------------------------------------------------- -CustomEncode.UrlEncode: http://www.google.co.jp/search?hl=ja&q=%26 -CustomEncode.UrlEncode2: http%3A%2F%2Fwww.google.co.jp%2Fsearch%3Fhl%3Dja%26q%3D%26 -CustomEncode.UrlEncode2: http%3A%2F%2Fwww.google.co.jp%2Fsearch%3Fhl%3Dja%26q%3D%3C%3E ----------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +log4net: Configuration update mode [Merge]. +log4net: Retrieving an instance of log4net.Repository.Logger for logger [ACCESS]. +log4net: Setting [ACCESS] additivity to [True]. +log4net: Logger [ACCESS] Level string is [All]. +log4net: Logger [ACCESS] level set to [name="ALL",value=-2147483648]. +log4net: Loading Appender [ACCESS2] type: [log4net.Appender.ConsoleAppender] +log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Setting Property [ConversionPattern] to String value [[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline] +log4net: Converter [literal] Option [[] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [date] Option [yyyy/MM/dd HH:mm:ss,fff] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [level] Option [] Format [min=5,max=2147483647,leftAlign=True] +log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [thread] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [literal] Option [],] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Setting Property [Layout] to object [log4net.Layout.PatternLayout] +log4net: Setting Property [LevelMin] to Level value [DEBUG] +log4net: Setting Property [LevelMax] to Level value [FATAL] +log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.LevelRangeFilter] +log4net: Created Appender [ACCESS2] +log4net: Adding appender named [ACCESS2] to logger [ACCESS]. +log4net: Retrieving an instance of log4net.Repository.Logger for logger [SQLTRACE]. +log4net: Setting [SQLTRACE] additivity to [True]. +log4net: Logger [SQLTRACE] Level string is [All]. +log4net: Logger [SQLTRACE] level set to [name="ALL",value=-2147483648]. +log4net: Loading Appender [SQLTRACE2] type: [log4net.Appender.ConsoleAppender] +log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Setting Property [ConversionPattern] to String value [[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline] +log4net: Converter [literal] Option [[] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [date] Option [yyyy/MM/dd HH:mm:ss,fff] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [level] Option [] Format [min=5,max=2147483647,leftAlign=True] +log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [thread] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [literal] Option [],] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Setting Property [Layout] to object [log4net.Layout.PatternLayout] +log4net: Setting Property [LevelMin] to Level value [DEBUG] +log4net: Setting Property [LevelMax] to Level value [FATAL] +log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.LevelRangeFilter] +log4net: Created Appender [SQLTRACE2] +log4net: Adding appender named [SQLTRACE2] to logger [SQLTRACE]. +log4net: Retrieving an instance of log4net.Repository.Logger for logger [OPERATION]. +log4net: Setting [OPERATION] additivity to [True]. +log4net: Logger [OPERATION] Level string is [All]. +log4net: Logger [OPERATION] level set to [name="ALL",value=-2147483648]. +log4net: Loading Appender [OPERATION2] type: [log4net.Appender.ConsoleAppender] +log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Setting Property [ConversionPattern] to String value [[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline] +log4net: Converter [literal] Option [[] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [date] Option [yyyy/MM/dd HH:mm:ss,fff] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [level] Option [] Format [min=5,max=2147483647,leftAlign=True] +log4net: Converter [literal] Option [],[] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [thread] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [literal] Option [],] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [message] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Converter [newline] Option [] Format [min=-1,max=2147483647,leftAlign=False] +log4net: Setting Property [Layout] to object [log4net.Layout.PatternLayout] +log4net: Setting Property [LevelMin] to Level value [DEBUG] +log4net: Setting Property [LevelMax] to Level value [FATAL] +log4net: Setting Collection Property [AddFilter] to object [log4net.Filter.LevelRangeFilter] +log4net: Created Appender [OPERATION2] +log4net: Adding appender named [OPERATION2] to logger [OPERATION]. +log4net: Hierarchy Threshold [] +[2026/08/08 10:15:49,809],[DEBUG],[2],LogIF.DebugLog("ACCESS"); +[2026/08/08 10:15:49,818],[INFO ],[2],LogIF.InfoLog("ACCESS"); +[2026/08/08 10:15:49,819],[WARN ],[2],LogIF.WarnLog("ACCESS"); +[2026/08/08 10:15:49,819],[ERROR],[2],LogIF.ErrorLog("ACCESS"); +[2026/08/08 10:15:49,819],[FATAL],[2],LogIF.FatalLog("ACCESS"); +---------------------------------------------------------------------------------------------------- +GetMessage: ~メッセージID:I0001に対応する記述(正常系)~ +GetMessage: ~メッセージID:E0001に対応する記述(異常系)~ +-------------------------------------------------- +GetSharedProperty: てすと1 +GetSharedProperty: てすと3 +---------------------------------------------------------------------------------------------------- +StringChecker.IsNumbers - あああ: False +StringChecker.IsNumbers - 111: True +StringChecker.IsNumbers_Hankaku - あああ: False +StringChecker.IsNumbers_Hankaku - 111111: True +StringChecker.IsNumbers_Zenkaku - あああ: False +StringChecker.IsNumbers_Zenkaku - 111: True +---------------------------------------------------------------------------------------------------- +StringChecker.IsAlphabet - あああ: False +StringChecker.IsAlphabet - aaa: True +StringChecker.IsAlphabet_Hankaku - あああ: False +StringChecker.IsAlphabet_Hankaku - aaaaaa: True +StringChecker.IsAlphabet_Zenkaku - あああ: False +StringChecker.IsAlphabet_Zenkaku - aaa: True +---------------------------------------------------------------------------------------------------- +StringChecker.IsHiragana - aaa: False +StringChecker.IsHiragana - あああ: True +---------------------------------------------------------------------------------------------------- +StringChecker.IsKatakana - あああ: False +StringChecker.IsKatakana - アアア: True +StringChecker.IsKatakana_Zenkaku - あああ: False +StringChecker.IsKatakana_Zenkaku - アアア: True +StringChecker.IsKatakana_Zenkaku - アアア: False +StringChecker.IsKatakana_Zenkaku - アアアアアア: True +---------------------------------------------------------------------------------------------------- +StringChecker.IsKanji - あああ: False +StringChecker.IsKanji - 亜亜亜: True +---------------------------------------------------------------------------------------------------- +StringChecker.IsShift_Jis - 鱓鱓鱓: False +StringChecker.IsShift_Jis - 亜亜亜: True +StringChecker.IsShift_Jis_Zenkaku - aaaaaa: False +StringChecker.IsShift_Jis_Zenkaku - 亜亜亜: True +StringChecker.IsShift_Jis_Hankaku - aaa: False +StringChecker.IsShift_Jis_Hankaku - aaaaaa: True +---------------------------------------------------------------------------------------------------- +TestFormatChecker.IsJpZipCode +JpZipCode_Hyphen +000-0000: True +aaa-aaaa: False +0000-00000: False +0000-0000: False +000-00000: False +00-000: False +00-0000: False +000-000: False +JpZipKuCode1_Hyphen +000-00: True +aaa-aa: False +0000-000: False +0000-00: False +000-000: False +00-0: False +00-00: False +000-0: False +JpZipKuCode2_Hyphen +000: True +aaa: False +0000: False +00: False +JpZipCode_NoHyphen +0000000: True +aaaaaaa: False +00000000: False +000000: False +JpZipKuCode1_NoHyphen +00000: True +aaaaa: False +000000: False +0000: False +JpZipKuCode2_NoHyphen +000: True +aaa: False +0000: False +00: False +-------------------------------------------------- +TestFormatChecker.IsJpZipCode_Hyphen +JpZipCode_Hyphen +000-0000: True +aaa-aaaa: False +0000-00000: False +0000-0000: False +000-00000: False +00-000: False +00-0000: False +000-000: False +JpZipKuCode1_Hyphen +000-00: True +aaa-aa: False +0000-000: False +0000-00: False +000-000: False +00-0: False +00-00: False +000-0: False +JpZipKuCode2_Hyphen +000: True +aaa: False +0000: False +00: False +-------------------------------------------------- +TestFormatChecker.IsJpZipCode_NoHyphen +JpZipCode_NoHyphen +0000000: True +aaaaaaa: False +00000000: False +000000: False +JpZipKuCode1_NoHyphen +00000: True +aaaaa: False +000000: False +0000: False +JpZipKuCode2_NoHyphen +000: True +aaa: False +0000: False +00: False +-------------------------------------------------- +TestFormatChecker.IsJpZipCode7 +JpZipCode_Hyphen +000-0000: True +aaa-aaaa: False +0000-00000: False +0000-0000: False +000-00000: False +00-000: False +00-0000: False +000-000: False +JpZipCode_NoHyphen +0000000: True +aaaaaaa: False +00000000: False +000000: False +-------------------------------------------------- +TestFormatChecker.IsJpZipCode7_Hyphen +JpZipCode_Hyphen +000-0000: True +aaa-aaaa: False +0000-00000: False +0000-0000: False +000-00000: False +00-000: False +00-0000: False +000-000: False +-------------------------------------------------- +TestFormatChecker.IsJpZipCode7_NoHyphen +JpZipCode_NoHyphen +0000000: True +aaaaaaa: False +00000000: False +000000: False +-------------------------------------------------- +TestFormatChecker.IsJpZipCode5 +JpZipKuCode1_Hyphen +000-00: True +aaa-aa: False +0000-000: False +0000-00: False +000-000: False +00-0: False +00-00: False +000-0: False +JpZipKuCode2_Hyphen +000: True +aaa: False +0000: False +00: False +JpZipKuCode1_NoHyphen +00000: True +aaaaa: False +000000: False +0000: False +JpZipKuCode2_NoHyphen +000: True +aaa: False +0000: False +00: False +-------------------------------------------------- +TestFormatChecker.IsJpZipCode5_Hyphen +JpZipKuCode1_Hyphen +000-00: True +aaa-aa: False +0000-000: False +0000-00: False +000-000: False +00-0: False +00-00: False +000-0: False +JpZipKuCode2_Hyphen +000: True +aaa: False +0000: False +00: False +-------------------------------------------------- +TestFormatChecker.IsJpZipCode5_NoHyphen +JpZipKuCode1_NoHyphen +00000: True +aaaaa: False +000000: False +0000: False +JpZipKuCode2_NoHyphen +000: True +aaa: False +0000: False +00: False +-------------------------------------------------- +TestFormatChecker.IsJpTelephoneNumber +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: True +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: True +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: True +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: True +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: True +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: True +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: True +020-999-9999: True +020-9999-999: False +060-9999-9999: True +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: True +060-999-9999: True +060-9999-999: False +070-9999-9999: True +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: True +070-999-9999: True +070-9999-999: False +080-9999-9999: True +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: True +080-999-9999: True +080-9999-999: False +090-9999-9999: True +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: True +090-999-9999: True +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: True +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: True +06099999999: True +07099999999: True +08099999999: True +09099999999: True +01099999999: False +03099999999: False +04099999999: False +05099999999: True +JpIpPhoneNumber_Hyphen +050-9999-9999: True +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: True +050-999-9999: True +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: True +030-9999-9999: False +040-9999-9999: False +060-9999-9999: True +070-9999-9999: True +080-9999-9999: True +090-9999-9999: True +JpIpPhoneNumber_NoHyphen +05099999999: True +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: True +01099999999: False +02099999999: True +03099999999: False +04099999999: False +06099999999: True +07099999999: True +08099999999: True +09099999999: True +-------------------------------------------------- +TestFormatChecker.IsJpTelephoneNumber_Hyphen +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: True +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: True +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: True +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: True +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: False +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: True +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: True +020-999-9999: True +020-9999-999: False +060-9999-9999: True +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: True +060-999-9999: True +060-9999-999: False +070-9999-9999: True +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: True +070-999-9999: True +070-9999-999: False +080-9999-9999: True +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: True +080-999-9999: True +080-9999-999: False +090-9999-9999: True +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: True +090-999-9999: True +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: False +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +01099999999: False +03099999999: False +04099999999: False +05099999999: False +JpIpPhoneNumber_Hyphen +050-9999-9999: True +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: True +050-999-9999: True +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: True +030-9999-9999: False +040-9999-9999: False +060-9999-9999: True +070-9999-9999: True +080-9999-9999: True +090-9999-9999: True +JpIpPhoneNumber_NoHyphen +05099999999: False +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: False +01099999999: False +02099999999: False +03099999999: False +04099999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +-------------------------------------------------- +TestFormatChecker.IsJpTelephoneNumber_NoHyphen +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: False +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: False +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: False +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: False +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: True +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: False +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: False +020-999-9999: False +020-9999-999: False +060-9999-9999: False +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: False +060-999-9999: False +060-9999-999: False +070-9999-9999: False +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: False +070-999-9999: False +070-9999-999: False +080-9999-9999: False +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: False +080-999-9999: False +080-9999-999: False +090-9999-9999: False +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: False +090-999-9999: False +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: True +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: True +06099999999: True +07099999999: True +08099999999: True +09099999999: True +01099999999: False +03099999999: False +04099999999: False +05099999999: True +JpIpPhoneNumber_Hyphen +050-9999-9999: False +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: False +050-999-9999: False +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: False +030-9999-9999: False +040-9999-9999: False +060-9999-9999: False +070-9999-9999: False +080-9999-9999: False +090-9999-9999: False +JpIpPhoneNumber_NoHyphen +05099999999: True +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: True +01099999999: False +02099999999: True +03099999999: False +04099999999: False +06099999999: True +07099999999: True +08099999999: True +09099999999: True +-------------------------------------------------- +TestFormatChecker.IsJpFixedLinePhoneNumber +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: True +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: True +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: True +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: True +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: True +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: False +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: True +020-999-9999: True +020-9999-999: False +060-9999-9999: False +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: True +060-999-9999: True +060-9999-999: False +070-9999-9999: False +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: True +070-999-9999: True +070-9999-999: False +080-9999-9999: False +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: True +080-999-9999: True +080-9999-999: False +090-9999-9999: False +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: True +090-999-9999: True +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: False +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: True +06099999999: False +07099999999: False +08099999999: False +09099999999: False +01099999999: False +03099999999: False +04099999999: False +05099999999: False +JpIpPhoneNumber_Hyphen +050-9999-9999: False +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: True +050-999-9999: True +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: False +030-9999-9999: False +040-9999-9999: False +060-9999-9999: False +070-9999-9999: False +080-9999-9999: False +090-9999-9999: False +JpIpPhoneNumber_NoHyphen +05099999999: False +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: True +01099999999: False +02099999999: False +03099999999: False +04099999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +-------------------------------------------------- +TestFormatChecker.IsJpFixedLinePhoneNumber_Hyphen +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: True +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: True +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: True +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: True +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: False +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: False +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: True +020-999-9999: True +020-9999-999: False +060-9999-9999: False +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: True +060-999-9999: True +060-9999-999: False +070-9999-9999: False +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: True +070-999-9999: True +070-9999-999: False +080-9999-9999: False +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: True +080-999-9999: True +080-9999-999: False +090-9999-9999: False +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: True +090-999-9999: True +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: False +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +01099999999: False +03099999999: False +04099999999: False +05099999999: False +JpIpPhoneNumber_Hyphen +050-9999-9999: False +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: True +050-999-9999: True +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: False +030-9999-9999: False +040-9999-9999: False +060-9999-9999: False +070-9999-9999: False +080-9999-9999: False +090-9999-9999: False +JpIpPhoneNumber_NoHyphen +05099999999: False +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: False +01099999999: False +02099999999: False +03099999999: False +04099999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +-------------------------------------------------- +TestFormatChecker.IsJpFixedLinePhoneNumber_NoHyphen +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: False +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: False +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: False +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: False +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: True +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: False +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: False +020-999-9999: False +020-9999-999: False +060-9999-9999: False +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: False +060-999-9999: False +060-9999-999: False +070-9999-9999: False +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: False +070-999-9999: False +070-9999-999: False +080-9999-9999: False +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: False +080-999-9999: False +080-9999-999: False +090-9999-9999: False +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: False +090-999-9999: False +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: False +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: True +06099999999: False +07099999999: False +08099999999: False +09099999999: False +01099999999: False +03099999999: False +04099999999: False +05099999999: False +JpIpPhoneNumber_Hyphen +050-9999-9999: False +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: False +050-999-9999: False +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: False +030-9999-9999: False +040-9999-9999: False +060-9999-9999: False +070-9999-9999: False +080-9999-9999: False +090-9999-9999: False +JpIpPhoneNumber_NoHyphen +05099999999: False +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: True +01099999999: False +02099999999: False +03099999999: False +04099999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +-------------------------------------------------- +TestFormatChecker.IsJpCellularPhoneNumber +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: False +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: False +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: False +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: False +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: False +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: True +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: False +020-999-9999: False +020-9999-999: False +060-9999-9999: True +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: False +060-999-9999: False +060-9999-999: False +070-9999-9999: True +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: False +070-999-9999: False +070-9999-999: False +080-9999-9999: True +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: False +080-999-9999: False +080-9999-999: False +090-9999-9999: True +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: False +090-999-9999: False +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: True +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: False +06099999999: True +07099999999: True +08099999999: True +09099999999: True +01099999999: False +03099999999: False +04099999999: False +05099999999: False +JpIpPhoneNumber_Hyphen +050-9999-9999: False +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: False +050-999-9999: False +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: True +030-9999-9999: False +040-9999-9999: False +060-9999-9999: True +070-9999-9999: True +080-9999-9999: True +090-9999-9999: True +JpIpPhoneNumber_NoHyphen +05099999999: False +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: False +01099999999: False +02099999999: True +03099999999: False +04099999999: False +06099999999: True +07099999999: True +08099999999: True +09099999999: True +-------------------------------------------------- +TestFormatChecker.IsJpCellularPhoneNumber_Hyphen +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: False +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: False +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: False +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: False +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: False +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: True +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: False +020-999-9999: False +020-9999-999: False +060-9999-9999: True +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: False +060-999-9999: False +060-9999-999: False +070-9999-9999: True +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: False +070-999-9999: False +070-9999-999: False +080-9999-9999: True +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: False +080-999-9999: False +080-9999-999: False +090-9999-9999: True +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: False +090-999-9999: False +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: False +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +01099999999: False +03099999999: False +04099999999: False +05099999999: False +JpIpPhoneNumber_Hyphen +050-9999-9999: False +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: False +050-999-9999: False +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: True +030-9999-9999: False +040-9999-9999: False +060-9999-9999: True +070-9999-9999: True +080-9999-9999: True +090-9999-9999: True +JpIpPhoneNumber_NoHyphen +05099999999: False +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: False +01099999999: False +02099999999: False +03099999999: False +04099999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +-------------------------------------------------- +TestFormatChecker.IsJpCellularPhoneNumber_NoHyphen +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: False +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: False +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: False +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: False +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: False +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: False +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: False +020-999-9999: False +020-9999-999: False +060-9999-9999: False +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: False +060-999-9999: False +060-9999-999: False +070-9999-9999: False +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: False +070-999-9999: False +070-9999-999: False +080-9999-9999: False +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: False +080-999-9999: False +080-9999-999: False +090-9999-9999: False +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: False +090-999-9999: False +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: True +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: False +06099999999: True +07099999999: True +08099999999: True +09099999999: True +01099999999: False +03099999999: False +04099999999: False +05099999999: False +JpIpPhoneNumber_Hyphen +050-9999-9999: False +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: False +050-999-9999: False +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: False +030-9999-9999: False +040-9999-9999: False +060-9999-9999: False +070-9999-9999: False +080-9999-9999: False +090-9999-9999: False +JpIpPhoneNumber_NoHyphen +05099999999: False +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: False +01099999999: False +02099999999: True +03099999999: False +04099999999: False +06099999999: True +07099999999: True +08099999999: True +09099999999: True +-------------------------------------------------- +TestFormatChecker.IsJpIpPhoneNumber +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: False +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: False +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: False +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: False +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: False +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: False +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: False +020-999-9999: False +020-9999-999: False +060-9999-9999: False +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: False +060-999-9999: False +060-9999-999: False +070-9999-9999: False +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: False +070-999-9999: False +070-9999-999: False +080-9999-9999: False +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: False +080-999-9999: False +080-9999-999: False +090-9999-9999: False +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: False +090-999-9999: False +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: False +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +01099999999: False +03099999999: False +04099999999: False +05099999999: True +JpIpPhoneNumber_Hyphen +050-9999-9999: True +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: False +050-999-9999: False +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: False +030-9999-9999: False +040-9999-9999: False +060-9999-9999: False +070-9999-9999: False +080-9999-9999: False +090-9999-9999: False +JpIpPhoneNumber_NoHyphen +05099999999: True +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: False +01099999999: False +02099999999: False +03099999999: False +04099999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +-------------------------------------------------- +TestFormatChecker.IsJpIpPhoneNumber_Hyphen +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: False +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: False +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: False +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: False +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: False +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: False +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: False +020-999-9999: False +020-9999-999: False +060-9999-9999: False +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: False +060-999-9999: False +060-9999-999: False +070-9999-9999: False +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: False +070-999-9999: False +070-9999-999: False +080-9999-9999: False +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: False +080-999-9999: False +080-9999-999: False +090-9999-9999: False +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: False +090-999-9999: False +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: False +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +01099999999: False +03099999999: False +04099999999: False +05099999999: False +JpIpPhoneNumber_Hyphen +050-9999-9999: True +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: False +050-999-9999: False +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: False +030-9999-9999: False +040-9999-9999: False +060-9999-9999: False +070-9999-9999: False +080-9999-9999: False +090-9999-9999: False +JpIpPhoneNumber_NoHyphen +05099999999: False +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: False +01099999999: False +02099999999: False +03099999999: False +04099999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +-------------------------------------------------- +TestFormatChecker.IsJpIpPhoneNumber_NoHyphen +JpFixedLinePhoneNumber_Hyphen +09999-9-9999: False +99999-9-9999: False +0aaaa-a-aaaa: False +099999-9-9999: False +09999-99-9999: False +09999-9-99999: False +0999--999: False +0999-9-9999: False +09999--9999: False +09999-9-999: False +0999-99-9999: False +9999-99-9999: False +0aaa-aa-aaaa: False +09999-999-99999: False +09999-99-9999: False +0999-999-9999: False +0999-99-99999: False +099-9-999: False +099-99-9999: False +0999-9-9999: False +0999-99-999: False +099-999-9999: False +999-999-9999: False +0aa-aaa-aaaa: False +0999-9999-99999: False +0999-999-9999: False +099-9999-9999: False +099-999-99999: False +09-99-999: False +09-999-9999: False +099-99-9999: False +099-999-999: False +09-9999-9999: False +99-9999-9999: False +0a-aaaa-aaaa: False +099-99999-99999: False +099-9999-9999: False +09-99999-9999: False +09-9999-99999: False +0-999-999: False +0-9999-9999: False +09-999-9999: False +09-9999-999: False +JpFixedLinePhoneNumber_NoHyphen +0999999999: False +9999999999: False +0aaaaaaaaa: False +09999999999: False +099999999: False +JpCellularPhoneNumber_Hyphen +020-9999-9999: False +929-9999-9999: False +020-aaaa-aaaa: False +0209-99999-99999: False +0209-9999-9999: False +020-99999-9999: False +020-9999-99999: False +02-999-999: False +02-9999-9999: False +020-999-9999: False +020-9999-999: False +060-9999-9999: False +969-9999-9999: False +060-aaaa-aaaa: False +0609-99999-99999: False +0609-9999-9999: False +060-99999-9999: False +060-9999-99999: False +06-999-999: False +06-9999-9999: False +060-999-9999: False +060-9999-999: False +070-9999-9999: False +979-9999-9999: False +070-aaaa-aaaa: False +0709-99999-99999: False +0709-9999-9999: False +070-99999-9999: False +070-9999-99999: False +07-999-999: False +07-9999-9999: False +070-999-9999: False +070-9999-999: False +080-9999-9999: False +989-9999-9999: False +080-aaaa-aaaa: False +0809-99999-99999: False +0809-9999-9999: False +080-99999-9999: False +080-9999-99999: False +08-999-999: False +08-9999-9999: False +080-999-9999: False +080-9999-999: False +090-9999-9999: False +999-9999-9999: False +090-aaaa-aaaa: False +0909-99999-99999: False +0909-9999-9999: False +090-99999-9999: False +090-9999-99999: False +09-999-999: False +09-9999-9999: False +090-999-9999: False +090-9999-999: False +JpCellularPhoneNumber_NoHyphen +02099999999: False +92999999999: False +020aaaaaaaa: False +020999999999: False +0209999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +01099999999: False +03099999999: False +04099999999: False +05099999999: True +JpIpPhoneNumber_Hyphen +050-9999-9999: False +959-9999-9999: False +050-aaaa-aaaa: False +0509-99999-99999: False +0509-9999-9999: False +050-99999-9999: False +050-9999-99999: False +05-999-999: False +05-9999-9999: False +050-999-9999: False +050-9999-999: False +9999999999999: False +010-9999-9999: False +020-9999-9999: False +030-9999-9999: False +040-9999-9999: False +060-9999-9999: False +070-9999-9999: False +080-9999-9999: False +090-9999-9999: False +JpIpPhoneNumber_NoHyphen +05099999999: True +95999999999: False +050aaaaaaaa: False +050999999999: False +0509999999: False +01099999999: False +02099999999: False +03099999999: False +04099999999: False +06099999999: False +07099999999: False +08099999999: False +09099999999: False +---------------------------------------------------------------------------------------------------- +StringVariableOperator.GetPropsFromPropString +[1 組] a=1 + 件数 : 1 + A = 1 +[2 組] a=1;b=2 + 件数 : 2 + A = 1 + B = 2 +[値が空] a=;b=2 + 件数 : 2 + A = + B = 2 +[値に = を含む] a={=};b=2 + 件数 : 2 + A = = + B = 2 +[値に ; を含む] a={;};b=2 + 件数 : 2 + A = ; + B = 2 +[名前に = を含む] a{=}b=1 + 件数 : 1 + A=B = 1 +[= が無い] a + 件数 : 0 +[空文字] + 件数 : 0 +---------------------------------------------------------------------------------------------------- +StringVariableOperator.BuiltStringIntoEnvironmentVariable +[そのまま] abc → abc +[埋め込み] x%OPENTOURYO_TEST_VAR%y → xVALUEy +[2 回] %OPENTOURYO_TEST_VAR%-%OPENTOURYO_TEST_VAR% → VALUE-VALUE +[未定義] x%OPENTOURYO_NOT_EXIST%y → xy +[閉じていない] x%OPENTOURYO_TEST_VAR → x%OPENTOURYO_TEST_VAR +[null] (null) → (null) +[空文字] → +---------------------------------------------------------------------------------------------------- +StringExtractor.GetParameterFromQueryString +[先頭の値] a → "1" +[途中の値] b → "xyz" +[空の値] c → "" +[無い名前] z → "" +[クエリ無し] a → "" +[前方一致の紛れ] a → "1" +---------------------------------------------------------------------------------------------------- +StringExtractor.GetAttributeFromXml +[最初の属性] id → "1" +[2 番目の属性] name → "abc" +[無い属性] notexist → "" +---------------------------------------------------------------------------------------------------- +ToStringExtension.XmlToString +宣言なし : <root><child id="1">値</child></root> +インデントあり : +<root> + <child id="1">値</child> +</root> +---------------------------------------------------------------------------------------------------- +PubCmnFunction +ChangeType string → int : 123 (Int32) +ChangeType int → string : 123 (String) +ChangeType string → int? : 123 (Int32) +ChangeType null → int? : null +ChangeType string → decimal : 1.5 (Decimal) +ChangeType 変換できない : 例外 System.FormatException +GetUnderlyingType(int?) : Int32 +GetUnderlyingType(int) : (null) +GetUnderlyingType(string): (null) +ToUnixTime : 1786019696 +GetFileNameNoEx(パス付き) : a +GetFileNameNoEx(二重拡張子) : a.b +GetFileNameNoEx(拡張子なし) : +GetFileNameNoEx(区切りを「.」): "" +GetCurrentMethodName : GetCurrentMethodName +---------------------------------------------------------------------------------------------------- +ArrayOperator +CopyArray(3 → 2) : [1, 2] +CopyArray(3 → 5) : 例外 System.ArgumentException +CopyArray(読取開始位置をずらす) : [2, 3] +CopyArray(書込開始位置をずらす) : 例外 System.ArgumentException +CombineArray : [1, 2, 3, 4, 5] +ShortenByteArray(8 → 3) : [2, 15, 5] +ArrayOperator.GetLongFromByte +1 byte : 1 +2 byte : 258 +3 byte : 66051 +3 byte(上位のみ) : 65536 +8 byte : 72623859790382856 +8 byte(最上位ビット) : -1 +0 byte : 例外 System.ArgumentOutOfRangeException +9 byte : 例外 System.ArgumentOutOfRangeException +null : 例外 System.ArgumentNullException +---------------------------------------------------------------------------------------------------- +GetConfigParameter / EnvInfo +GetConfigValue(FxBusinessMessageCulture) : ja-JP +無いキー : null または空 +EnvInfo.MachineName が取れる : True +EnvInfo.OsVersionString が取れる : True +EnvInfo.ProcessBit が 32 または 64 : True +---------------------------------------------------------------------------------------------------- +StringConverter.ToHankaku - アアア: アアア +StringConverter.ToZenkaku - アアア: アアア +StringConverter.ToHiragana - アアア: あああ +StringConverter.ToKatakana - あああ: アアア +---------------------------------------------------------------------------------------------------- +FormatConverter.SeirekiToWareki +1977/4/24, ggy年M月d日(ddd): 昭和52年4月24日(日) +1977/4/24, ggy年M月d日(ddd)H:m:s: 昭和52年4月24日(日)0:0:0 +1977/4/24 19:15:12, ggy年M月d日(ddd): 昭和52年4月24日(日) +1977/4/24 19:15:12, ggy年M月d日(ddd)H:m:s: 昭和52年4月24日(日)19:15:12 +1977/4/24 19:15:12, ggy年M月d日(ddd)tt h:m:s: 昭和52年4月24日(日)午後 7:15:12 +1992/2/6 1:1:1, ggyy年MM月dd日 dddd HH:mm:ss: 平成04年02月06日 木曜日 01:01:01 +1992/2/6 13:1:1, ggyy年MM月dd日 dddd tt hh:mm:ss: 平成04年02月06日 木曜日 午後 01:01:01 +-------------------------------------------------- +FormatConverter.WarekiToSeireki +昭和52年4月24日(日), ggy年M月d日(ddd): 1977/04/24 0:00:00 +昭和52年4月24日(日)19:15:12, ggy年M月d日(ddd)H:m:s: 1977/04/24 19:15:12 +昭和52年4月24日(日)午後 7:15:12, ggy年M月d日(ddd)tt h:m:s: 1977/04/24 19:15:12 +平成04年02月06日 木曜日 01:01:01, ggyy年MM月dd日 dddd HH:mm:ss: 1992/02/06 1:01:01 +平成04年02月06日 木曜日 午後 01:01:01, ggyy年MM月dd日 dddd tt hh:mm:ss: 1992/02/06 13:01:01 +-------------------------------------------------- +FormatConverter.AddFigure3 +12,345 +123,456,789 +123.45 +12,345.6789 +-12,345 +-123,456,789 +-123.45 +-12,345.6789 +12,345 +123,456,789 +123.45 +12,345.6789 +-12,345 +-123,456,789 +-123.45 +-12,345.6789 +---------------------------------------------------------------------------------------------------- +FormatConverter.AddFigure4 +1,2345 +1,2345,6789 +123.45 +1,2345.6789 +-1,2345 +-1,2345,6789 +-123.45 +-1,2345.6789 +1,2345 +1,2345,6789 +123.45 +1,2345.6789 +-1,2345 +-1,2345,6789 +-123.45 +-1,2345.6789 +---------------------------------------------------------------------------------------------------- +FormatConverter.Suppress +"", 10, '@': @@@@@@@@@@ +"123456789", 0, '@': 123456789 +"123456789", 1, '@': 123456789 +"123456789", 5, '@': 123456789 +"123456789", 9, '@': 123456789 +"123456789", 10, '@': @123456789 +"123456789", 11, '@': @@123456789 +"123456789", 20, '@': @@@@@@@@@@@123456789 +"", 10, '@': @@@@@@@@@@ +"123456789", 0, '@': abcdefg +"123456789", 1, '@': abcdefg +"123456789", 5, '@': abcdefg +"123456789", 9, '@': @@abcdefg +"123456789", 10, '@': @@@abcdefg +"123456789", 11, '@': @@@@abcdefg +"123456789", 20, '@': @@@@@@@@@@@@@abcdefg +---------------------------------------------------------------------------------------------------- +CustomEncode.HtmlEncode: " id="txtXXXXX" /><script type="text/javascript">alert("XSS!!!")</script><input name="txtXXXXX" type="text" value=" +---------------------------------------------------------------------------------------------------- +CustomEncode.UrlEncode: http://www.google.co.jp/search?hl=ja&q=%26 +CustomEncode.UrlEncode2: http%3A%2F%2Fwww.google.co.jp%2Fsearch%3Fhl%3Dja%26q%3D%26 +CustomEncode.UrlEncode2: http%3A%2F%2Fwww.google.co.jp%2Fsearch%3Fhl%3Dja%26q%3D%3C%3E +---------------------------------------------------------------------------------------------------- jis2k4.GetStringInfo - あああ: Char長:3; 文字列長3; バイト長6; - ----------------------------------------------------------------------------------------------------- -jis2k4.CheckSurrogatesPairChar - あああ: False -jis2k4.CheckSurrogatesPairChar - あ𩸽あ: True -jis2k4.CheckSurrogatesPairChar - あああ: -1文字目 -jis2k4.CheckSurrogatesPairChar - あ𩸽あ: 1文字目 ----------------------------------------------------------------------------------------------------- -jis2k4.DeleteSurrogatesPairChar - あ𩸽あ: ああ -jis2k4.DeleteSurrogatesPairChar - あ𩸽あ: あ●あ -jis2k4.DeleteSurrogatesPairChar - あ𩸽あ: あ●あ ----------------------------------------------------------------------------------------------------- -jis2k4.CheckCharAddedWithJIS2k4 - あああ: False -jis2k4.CheckCharAddedWithJIS2k4 - あ噓あ: True -jis2k4.CheckCharAddedWithJIS2k4 - あああ: -1文字目 -jis2k4.CheckCharAddedWithJIS2k4 - あ噓あ: 1文字目 ----------------------------------------------------------------------------------------------------- -jis2k4.DeleteCharAddedWithJIS2k4 - あ噓あ: ああ -jis2k4.DeleteCharAddedWithJIS2k4 - あ噓あ: あ●あ -jis2k4.DeleteCharAddedWithJIS2k4 - あ噓あ: あ●あ ----------------------------------------------------------------------------------------------------- -Friday > Friday -Wednesday > Wednesday -Saturday > Saturday -Friday > Friday -Saturday > Saturday -------------------------- -Friday > Friday -Wednesday > Wednesday -Saturday > Saturday -Friday > Friday -Saturday > Saturday --------------------------------------------------- -V2 > V2 -V3 > V3 -V4 > V4 -------------------------- -V2 > V2 -V3 > V3 -V4 > V4 --------------------------------------------------- -V0 > V0 -V2 > V2 -V4 > V4 -------------------------- -V0 > V0 -V2 > V2 -V4 > V4 --------------------------------------------------- -One > One -One,Two > One,Two -Three > Three -Four > Four -------------------------- -One > One -One,Two > One, Two -Three > Three -Four > Four ----------------------------------------------------------------------------------------------------- -XmlLib > is working properly. ----------------------------------------------------------------------------------------------------- -DeflateCompression(FileStream)-1 > is working properly. -DeflateCompression(FileStream)-2 > is working properly. --------------------------------------------------- -DeflateCompression(MemoryStream) > is working properly. ----------------------------------------------------------------------------------------------------- - log4net: Shutdown called on Hierarchy [log4net-default-repository] + +---------------------------------------------------------------------------------------------------- +jis2k4.CheckSurrogatesPairChar - あああ: False +jis2k4.CheckSurrogatesPairChar - あ𩸽あ: True +jis2k4.CheckSurrogatesPairChar - あああ: -1文字目 +jis2k4.CheckSurrogatesPairChar - あ𩸽あ: 1文字目 +---------------------------------------------------------------------------------------------------- +jis2k4.DeleteSurrogatesPairChar - あ𩸽あ: ああ +jis2k4.DeleteSurrogatesPairChar - あ𩸽あ: あ●あ +jis2k4.DeleteSurrogatesPairChar - あ𩸽あ: あ●あ +---------------------------------------------------------------------------------------------------- +jis2k4.CheckCharAddedWithJIS2k4 - あああ: False +jis2k4.CheckCharAddedWithJIS2k4 - あ噓あ: True +jis2k4.CheckCharAddedWithJIS2k4 - あああ: -1文字目 +jis2k4.CheckCharAddedWithJIS2k4 - あ噓あ: 1文字目 +---------------------------------------------------------------------------------------------------- +jis2k4.DeleteCharAddedWithJIS2k4 - あ噓あ: ああ +jis2k4.DeleteCharAddedWithJIS2k4 - あ噓あ: あ●あ +jis2k4.DeleteCharAddedWithJIS2k4 - あ噓あ: あ●あ +---------------------------------------------------------------------------------------------------- +Friday > Friday +Wednesday > Wednesday +Saturday > Saturday +Friday > Friday +Saturday > Saturday +------------------------- +Friday > Friday +Wednesday > Wednesday +Saturday > Saturday +Friday > Friday +Saturday > Saturday +-------------------------------------------------- +V2 > V2 +V3 > V3 +V4 > V4 +------------------------- +V2 > V2 +V3 > V3 +V4 > V4 +-------------------------------------------------- +V0 > V0 +V2 > V2 +V4 > V4 +------------------------- +V0 > V0 +V2 > V2 +V4 > V4 +-------------------------------------------------- +One > One +One,Two > One,Two +Three > Three +Four > Four +------------------------- +One > One +One,Two > One, Two +Three > Three +Four > Four +---------------------------------------------------------------------------------------------------- +XmlLib > is working properly. +---------------------------------------------------------------------------------------------------- +DeflateCompression(FileStream)-1 > is working properly. +DeflateCompression(FileStream)-2 > is working properly. +-------------------------------------------------- +DeflateCompression(MemoryStream) > is working properly. +---------------------------------------------------------------------------------------------------- +ResourceLoader +絶対パスで解決 : True +絶対パスで読み込み : リソースの内容 +環境変数入りで解決 : True +配置フォルダ基準 : True +見つからない(解決) : null +見つからない(Exists): False +見つからない(例外) : System.ArgumentException +空文字(解決) : null +null(解決) : null +---------------------------------------------------------------------------------------------------- +EmbeddedResourceLoader +存在する : True +読み込み : 埋め込まれたリソースの内容 / embedded resource +存在しない : False +存在しない(例外) : System.ArgumentException +---------------------------------------------------------------------------------------------------- +ZipperV2 → UnZipperV2(往復) +解凍した件数 : 4 + root/a.txt + root/b.log + root/sub/c.txt + root/日本語.txt +内容が一致 : True +---------------------------------------------------------------------------------------------------- +暗号化 +[暗号化なし] 往復して一致 : True +[PkzipWeak] 往復して一致 : True +[WinZipAes128] 往復して一致 : True +[WinZipAes256] 往復して一致 : True +[パスワード誤り] 例外 ICSharpCode.SharpZipLib.Zip.ZipException +[パスワード未指定] 例外 System.ArgumentException +---------------------------------------------------------------------------------------------------- +選択デリゲート +[圧縮時に .log を除く] + a.txt + sub/c.txt + 日本語.txt +[上書き時の動作] + DoNotOverwrite の解凍件数 : 0 + OverwriteSilently の解凍件数 : 3 + Throw : 例外 System.IO.IOException +[上書きの問い合わせ] + 上書きすると答えた : 問い合わせ 3 件 / 解凍 3 件 + 答えない(既定) : 解凍 0 件 + 打ち切る : 解凍 0 件 +---------------------------------------------------------------------------------------------------- +進捗イベント +SaveProgress : Saving_Started, Saving_BeforeWriteEntry, Saving_EntryBytesRead, Saving_AfterWriteEntry, Saving_Completed +ExtractProgress : Extracting_Started, Extracting_BeforeExtractEntry, Extracting_EntryBytesWritten, Extracting_AfterExtractEntry, Extracting_Completed +無圧縮より BestCompression の方が小さい : True +---------------------------------------------------------------------------------------------------- +DataToPoco +[DataTableToList : 名前が一致] +件数 : 2 +OrderID=1, Note=x, Qty=0 +OrderID=2, Note=(null), Qty=0 +[DataTableToPOCO : 先頭行だけ] +OrderID=1, Note=x, Qty=0 +[マップ無 : 列名が PK_OrderID] +件数 : 1 +OrderID=0, Note=y, Qty=0 +[マップ有 : OrderID → PK_OrderID] +件数 : 1 +OrderID=9, Note=y, Qty=0 +---------------------------------------------------------------------------------------------------- +PocoToPoco +[Map : 同名のみ] +OrderID=3, Note=z, Qty=0 +[Map : Qty ← OrderID] +OrderID=3, Note=z, Qty=3 +---------------------------------------------------------------------------------------------------- +DataToDictionary +OrderID : 4 +Note : w +OrderDate : 2026/08/06 12:34:56 +---------------------------------------------------------------------------------------------------- +DTTable +[FromDataTable] +表名 : TestOrders +列 : OrderID, Note +行 : 5, a +行 : 6, b +[文字列との往復] +表の数 : 1 +表名 : TestOrders +列 : OrderID, Note +行 : 5, a +行 : 6, b +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : 基本の型 +[null] +null +[int] +123 +[string] +"あいう" +[bool] +True +[空文字] +"" +[int[]] +[1, 2, 3] +[int[] (8 要素)] +[1, 2, 3, 4, 5, 6, 7, 8] +[List<string>] +["a", "b"] +[Dictionary] +[x = 1, y = 2] +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : POCO +[入れ子が null] +[Name = "外側", Inner = null, Numbers = [10, 20]] +[入れ子に値] +[Name = "外側", Inner = [Code = "C1", Value = 99], Numbers = [10, 20]] +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : 深さの上限 +[入れ子 8 段] +[Level = 1, Child = [Level = 2, Child = [Level = 3, Child = [Level = 4, Child = [Level = -over-, Child = -over-]]]]] +[循環参照] +[Level = 1, Child = [Level = 1, Child = [Level = 1, Child = [Level = 1, Child = [Level = -over-, Child = -over-]]]]] +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : 日時 +[DateTime(書式あり)] +2026/08/06 12:34:56 +[TimeSpan(書式あり)] +1.02:03:04 +---------------------------------------------------------------------------------------------------- +ObjectInspector.Inspect : 除外 +[除外なし] +[Name = "外側", Inner = [Code = "C2", Value = 1], Numbers = [1]] +[InnerPoco を除外] +[Name = "外側", Inner = excluded. TestCode.TestObjectInspector+InnerPoco, Numbers = [1]] +---------------------------------------------------------------------------------------------------- +Latebind.InvokeMethod +[引数なし] PublicMethod +[引数あり] WithArgs:1:x +[static] StaticMethod +[private] PrivateMethod +[基底のメソッド] BaseMethod +[呼び先が例外] 例外 : System.Reflection.TargetInvocationException +---------------------------------------------------------------------------------------------------- +Latebind : メソッドが無いとき +[InvokeMethod] 例外 : System.ArgumentException +[InvokeMethod_NoErr] null +---------------------------------------------------------------------------------------------------- +Latebind : オーバーロード +[引数 1 個] Overloaded(int):1 +[引数 2 個] Overloaded(int,int):1:2 +[引数 3 個(該当なし)] 例外 : System.ArgumentException +---------------------------------------------------------------------------------------------------- +Latebind : 型とメソッドの確認 +CheckTypeOfBaseClass(Target, TargetBase) : True +CheckTypeOfBaseClass(Target, string) : False +CheckTypeOfMethodByName(PublicMethod) : True +CheckTypeOfMethodByName(PrivateMethod) : True +CheckTypeOfMethodByName(NotExist) : False +---------------------------------------------------------------------------------------------------- +InstanceCreator<T>.Factory +生成できた : True +別のインスタンス : True +既定値(Id) : 0 +既定値(Name) : (null) +---------------------------------------------------------------------------------------------------- +AccessorCacher.CacheAccessor +件数 : 5 +Count : 型=Nullable`1, 実体型=Int32, Get=True, Set=True +Field : 型=String, 実体型=(null), Get=True, Set=True +Id : 型=Int32, 実体型=(null), Get=True, Set=True +Name : 型=String, 実体型=(null), Get=True, Set=True +ReadOnly : 型=String, 実体型=(null), Get=True, Set=False +Set → Get : 設定した値 +再取得しても同じ : True +---------------------------------------------------------------------------------------------------- +CompiledExpressionCreater +プロパティ Id : 42 +フィールド Field : フィールドの値 +存在しないメンバ : 例外 System.ArgumentException +---------------------------------------------------------------------------------------------------- +log4net: Shutdown called on Hierarchy [log4net-default-repository] diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestDto.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestDto.cs new file mode 100644 index 000000000..7f055a6fc --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestDto.cs @@ -0,0 +1,324 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestDto +//* クラス日本語名 :Public.Dtoのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#522) +//********************************************************************************** + +using System; +using System.Collections.Generic; +using System.Data; + +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.Dto; + +namespace TestCode +{ + /// <summary>Public.Dtoのテスト</summary> + /// <remarks> + /// 項目移送(DataToPoco / PocoToPoco / DataToDictionary)と、 + /// マーシャリング可能な自前 DataTable(DTTable)を確認する(#522)。 + /// + /// <なぜここを優先するか> + /// 自動生成 Dao の項目移送の中核で、壊れると DTO 全体に波及する。 + /// **突合はプロパティ名で行う**ため、名前が変わると + /// **例外にならずに値が入らない**。件数や型では気付けない。 + /// 実際、#293 では「PK_ 接頭辞を付けた EntityTemplate」が + /// この方式と噛み合わず、既定のテンプレートから外された経緯がある。 + /// </remarks> + public class TestDto + { + #region public + + /// <summary>Root</summary> + public static void Root() + { + TestDto.TestDataToPoco(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestDto.TestPocoToPoco(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestDto.TestDataToDictionary(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestDto.TestDTTable(); + } + + #endregion + + #region テスト用の POCO + + /// <summary>移送先の POCO</summary> + /// <remarks>Qty は DataTable 側に列が無い。既定値のままになること。</remarks> + public class OrderPoco + { + /// <summary>OrderID</summary> + public int OrderID { get; set; } + + /// <summary>Note</summary> + public string Note { get; set; } + + /// <summary>Qty</summary> + public int Qty { get; set; } + } + + /// <summary>移送元の POCO</summary> + public class OrderSource + { + /// <summary>OrderID</summary> + public int OrderID { get; set; } + + /// <summary>Note</summary> + public string Note { get; set; } + + /// <summary>Memo(移送先には同名が無い)</summary> + public string Memo { get; set; } + } + + #endregion + + #region private + + /// <summary>DataToPoco のテスト</summary> + private static void TestDataToPoco() + { + MyDebug.OutputDebugAndConsole("DataToPoco"); + + // --- 名前が一致する場合 --- + // ・一致した列だけ値が入る + // ・POCO にしか無い Qty は既定値のまま + // ・DataTable にしか無い Extra は無視される + // ・DBNull は「指定しない」=既定値のまま + DataTable dt = new DataTable(); + dt.Columns.Add("OrderID", typeof(int)); + dt.Columns.Add("Note", typeof(string)); + dt.Columns.Add("Extra", typeof(string)); + + DataRow dr1 = dt.NewRow(); + dr1["OrderID"] = 1; + dr1["Note"] = "x"; + dr1["Extra"] = "無視される"; + dt.Rows.Add(dr1); + + DataRow dr2 = dt.NewRow(); + dr2["OrderID"] = 2; + dr2["Note"] = DBNull.Value; + dr2["Extra"] = "無視される"; + dt.Rows.Add(dr2); + + MyDebug.OutputDebugAndConsole("[DataTableToList : 名前が一致]"); + TestDto.OutputPocoList(DataToPoco.DataTableToList<OrderPoco>(dt)); + + // --- 先頭行だけを取る --- + MyDebug.OutputDebugAndConsole("[DataTableToPOCO : 先頭行だけ]"); + TestDto.OutputPoco(DataToPoco.DataTableToPOCO<OrderPoco>(dt)); + + // --- 名前が一致しない場合 --- + // **例外にならず、値が入らないだけ。** ここが気付きにくい。 + DataTable dtPk = new DataTable(); + dtPk.Columns.Add("PK_OrderID", typeof(int)); + dtPk.Columns.Add("Note", typeof(string)); + + DataRow drPk = dtPk.NewRow(); + drPk["PK_OrderID"] = 9; + drPk["Note"] = "y"; + dtPk.Rows.Add(drPk); + + MyDebug.OutputDebugAndConsole("[マップ無 : 列名が PK_OrderID]"); + TestDto.OutputPocoList(DataToPoco.DataTableToList<OrderPoco>(dtPk)); + + // --- マップで対応付ける場合 --- + // マップの向きは「POCO のプロパティ名 → DataTable の列名」。 + Dictionary<string, string> map = new Dictionary<string, string>(); + map.Add("OrderID", "PK_OrderID"); + + MyDebug.OutputDebugAndConsole("[マップ有 : OrderID → PK_OrderID]"); + TestDto.OutputPocoList(DataToPoco.DataTableToList<OrderPoco>(dtPk, map)); + } + + /// <summary>PocoToPoco のテスト</summary> + private static void TestPocoToPoco() + { + MyDebug.OutputDebugAndConsole("PocoToPoco"); + + OrderSource src = new OrderSource(); + src.OrderID = 3; + src.Note = "z"; + src.Memo = "移送先に同名が無い"; + + // 同名のプロパティだけが移送される。 + MyDebug.OutputDebugAndConsole("[Map : 同名のみ]"); + TestDto.OutputPoco(PocoToPoco.Map<OrderSource, OrderPoco>(src)); + + // マップで名前の違うプロパティを繋ぐ。 + Dictionary<string, string> map = new Dictionary<string, string>(); + map.Add("Qty", "OrderID"); + + MyDebug.OutputDebugAndConsole("[Map : Qty ← OrderID]"); + TestDto.OutputPoco(PocoToPoco.Map<OrderSource, OrderPoco>(src, map)); + } + + /// <summary>DataToDictionary のテスト</summary> + /// <remarks> + /// 日時の書式は**必ず明示する**。既定のままだと実行環境のロケールで変わり、 + /// 期待結果と一致しなくなる。 + /// </remarks> + private static void TestDataToDictionary() + { + MyDebug.OutputDebugAndConsole("DataToDictionary"); + + DataTable dt = new DataTable(); + dt.Columns.Add("OrderID", typeof(int)); + dt.Columns.Add("Note", typeof(string)); + dt.Columns.Add("OrderDate", typeof(DateTime)); + + DataRow dr = dt.NewRow(); + dr["OrderID"] = 4; + dr["Note"] = "w"; + dr["OrderDate"] = new DateTime(2026, 8, 6, 12, 34, 56); + dt.Rows.Add(dr); + + DataToDictionary d2d = new DataToDictionary(null, "yyyy/MM/dd HH:mm:ss", ""); + Dictionary<string, string> dic = d2d.DataTableToDictionary(dt); + + // キーの並びは実装依存のため、名前を指定して取り出す。 + MyDebug.OutputDebugAndConsole("OrderID : " + TestDto.GetValue(dic, "OrderID")); + MyDebug.OutputDebugAndConsole("Note : " + TestDto.GetValue(dic, "Note")); + MyDebug.OutputDebugAndConsole("OrderDate : " + TestDto.GetValue(dic, "OrderDate")); + } + + /// <summary>DTTable のテスト</summary> + /// <remarks> + /// DTTable はマーシャリング可能な自前の DataTable。 + /// DataTable からの変換と、文字列との往復を確認する。 + /// </remarks> + private static void TestDTTable() + { + MyDebug.OutputDebugAndConsole("DTTable"); + + DataTable dt = new DataTable("TestOrders"); + dt.Columns.Add("OrderID", typeof(int)); + dt.Columns.Add("Note", typeof(string)); + + DataRow dr1 = dt.NewRow(); + dr1["OrderID"] = 5; + dr1["Note"] = "a"; + dt.Rows.Add(dr1); + + DataRow dr2 = dt.NewRow(); + dr2["OrderID"] = 6; + dr2["Note"] = "b"; + dt.Rows.Add(dr2); + + DTTable dtt = DTTable.FromDataTable(dt); + + MyDebug.OutputDebugAndConsole("[FromDataTable]"); + TestDto.OutputDTTable(dtt); + + // 文字列との往復(マーシャリング) + DTTables dtts = new DTTables(); + dtts.Add(dtt); + + string text = DTTables.DTTablesToString(dtts); + DTTables restored = DTTables.StringToDTTables(text); + + MyDebug.OutputDebugAndConsole("[文字列との往復]"); + MyDebug.OutputDebugAndConsole("表の数 : " + restored.Count); + TestDto.OutputDTTable(restored[0]); + } + + #endregion + + #region 出力のヘルパ + + /// <summary>POCO の一覧を出力する</summary> + /// <param name="list">POCO の一覧</param> + private static void OutputPocoList(List<OrderPoco> list) + { + MyDebug.OutputDebugAndConsole("件数 : " + list.Count); + + foreach (OrderPoco poco in list) + { + TestDto.OutputPoco(poco); + } + } + + /// <summary>POCO を 1 件出力する</summary> + /// <param name="poco">POCO</param> + /// <remarks>null は "(null)" と出す。既定値のままかどうかを見るため。</remarks> + private static void OutputPoco(OrderPoco poco) + { + if (poco == null) + { + MyDebug.OutputDebugAndConsole("(null)"); + return; + } + + MyDebug.OutputDebugAndConsole( + "OrderID=" + poco.OrderID + + ", Note=" + (poco.Note == null ? "(null)" : poco.Note) + + ", Qty=" + poco.Qty); + } + + /// <summary>DTTable を出力する</summary> + /// <param name="dtt">DTTable</param> + private static void OutputDTTable(DTTable dtt) + { + MyDebug.OutputDebugAndConsole("表名 : " + dtt.TableName); + + string cols = ""; + foreach (DTColumn col in dtt.Cols) + { + cols += (cols == "" ? "" : ", ") + col.ColName; + } + MyDebug.OutputDebugAndConsole("列 : " + cols); + + foreach (DTRow row in dtt.Rows) + { + MyDebug.OutputDebugAndConsole( + "行 : " + row["OrderID"] + ", " + row["Note"]); + } + } + + /// <summary>Dictionary から値を取り出す</summary> + /// <param name="dic">Dictionary</param> + /// <param name="key">キー</param> + /// <returns>値(無い場合は "(なし)")</returns> + private static string GetValue(Dictionary<string, string> dic, string key) + { + if (dic != null && dic.ContainsKey(key)) + { + return dic[key]; + } + + return "(なし)"; + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestEmbedded.txt b/root/programs/CS/Frameworks/Tests/TestCode/TestEmbedded.txt new file mode 100644 index 000000000..3752c2e00 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestEmbedded.txt @@ -0,0 +1 @@ +埋め込まれたリソースの内容 / embedded resource diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestFastReflection.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestFastReflection.cs new file mode 100644 index 000000000..d26e9326b --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestFastReflection.cs @@ -0,0 +1,202 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestFastReflection +//* クラス日本語名 :FastReflectionのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#522) +//********************************************************************************** + +using System; +using System.Collections.Generic; + +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.FastReflection; + +namespace TestCode +{ + /// <summary>FastReflectionのテスト</summary> + /// <remarks> + /// 反射を式木にコンパイルして高速化する部品(#522)。 + /// + /// <なぜここを見るか> + /// **DataToPoco / PocoToPoco がこれに乗っている。** + /// AccessorCacher が返す AccessorName で列と突合するため、 + /// ここが変わると項目移送の挙動がそのまま変わる(TestDto と対で見ること)。 + /// + /// <キャッシュは静的> + /// AccessorCacher.CncDic は**プロセス全体で共有**される。 + /// 型ごとに一度だけ構築され、二度目以降は再利用される。 + /// </remarks> + public class TestFastReflection + { + #region public + + /// <summary>Root</summary> + public static void Root() + { + TestFastReflection.TestInstanceCreator(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestFastReflection.TestAccessorCacher(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestFastReflection.TestCompiledExpression(); + } + + #endregion + + #region テスト用の POCO + + /// <summary>アクセサの確認に使う</summary> + /// <remarks>プロパティとフィールドの両方を持たせる。</remarks> + public class AccessorPoco + { + /// <summary>読み書きできるプロパティ</summary> + public int Id { get; set; } + + /// <summary>読み書きできるプロパティ(文字列)</summary> + public string Name { get; set; } + + /// <summary>Nullable なプロパティ</summary> + public int? Count { get; set; } + + /// <summary>読み取り専用のプロパティ</summary> + public string ReadOnly + { + get { return "ReadOnly"; } + } + + /// <summary>フィールド</summary> + public string Field = ""; + } + + #endregion + + #region private + + /// <summary>InstanceCreator</summary> + /// <remarks>毎回、別のインスタンスが返ること。</remarks> + private static void TestInstanceCreator() + { + MyDebug.OutputDebugAndConsole("InstanceCreator<T>.Factory"); + + AccessorPoco a = InstanceCreator<AccessorPoco>.Factory(); + AccessorPoco b = InstanceCreator<AccessorPoco>.Factory(); + + MyDebug.OutputDebugAndConsole("生成できた : " + (a != null)); + MyDebug.OutputDebugAndConsole("別のインスタンス : " + (!object.ReferenceEquals(a, b))); + MyDebug.OutputDebugAndConsole("既定値(Id) : " + a.Id); + MyDebug.OutputDebugAndConsole("既定値(Name) : " + (a.Name == null ? "(null)" : a.Name)); + } + + /// <summary>AccessorCacher</summary> + /// <remarks> + /// プロパティとフィールドの両方が拾われる。 + /// **列挙の順序は反射に依存する**ため、名前で並べ替えてから出力する。 + /// </remarks> + private static void TestAccessorCacher() + { + MyDebug.OutputDebugAndConsole("AccessorCacher.CacheAccessor"); + + AccessorPoco poco = new AccessorPoco(); + AccessorCacher.CacheAccessor(poco); + + List<AccessorInfo> list = AccessorCacher.CncDic[poco.GetType()]; + + // 順序が実装に依存しないよう、名前で並べ替える。 + List<AccessorInfo> sorted = new List<AccessorInfo>(list); + sorted.Sort(delegate(AccessorInfo x, AccessorInfo y) + { + return string.CompareOrdinal(x.AccessorName, y.AccessorName); + }); + + MyDebug.OutputDebugAndConsole("件数 : " + sorted.Count); + + foreach (AccessorInfo ai in sorted) + { + MyDebug.OutputDebugAndConsole( + ai.AccessorName + + " : 型=" + ai.AccessorType.Name + + ", 実体型=" + (ai.UnderlyingType == null ? "(null)" : ai.UnderlyingType.Name) + + ", Get=" + (ai.GetDelegate != null) + + ", Set=" + (ai.SetDelegate != null)); + } + + // デリゲート経由での読み書き + AccessorInfo target = sorted.Find(delegate(AccessorInfo ai) { return ai.AccessorName == "Name"; }); + target.SetDelegate(poco, "設定した値"); + + MyDebug.OutputDebugAndConsole("Set → Get : " + target.GetDelegate(poco)); + + // 二度目は同じキャッシュが使われる(静的なため)。 + AccessorCacher.CacheAccessor(new AccessorPoco()); + MyDebug.OutputDebugAndConsole( + "再取得しても同じ : " + + object.ReferenceEquals(list, AccessorCacher.CncDic[poco.GetType()])); + } + + /// <summary>CompiledExpressionCreater</summary> + /// <remarks>プロパティ・フィールドの getter / setter を直接作る。</remarks> + private static void TestCompiledExpression() + { + MyDebug.OutputDebugAndConsole("CompiledExpressionCreater"); + + Type t = typeof(AccessorPoco); + AccessorPoco poco = new AccessorPoco(); + + // プロパティ + Action<object, object> setId = + CompiledExpressionCreater.CreateSetterOfPropertyOrField(t, "Id"); + Func<object, object> getId = + CompiledExpressionCreater.CreateGetterOfPropertyOrField(t, "Id"); + + setId(poco, 42); + MyDebug.OutputDebugAndConsole("プロパティ Id : " + getId(poco)); + + // フィールド + Action<object, object> setField = + CompiledExpressionCreater.CreateSetterOfPropertyOrField(t, "Field"); + Func<object, object> getField = + CompiledExpressionCreater.CreateGetterOfPropertyOrField(t, "Field"); + + setField(poco, "フィールドの値"); + MyDebug.OutputDebugAndConsole("フィールド Field : " + getField(poco)); + + // 存在しないメンバ + try + { + CompiledExpressionCreater.CreateGetterOfPropertyOrField(t, "NotExist"); + MyDebug.OutputDebugAndConsole("存在しないメンバ : 例外にならない"); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole("存在しないメンバ : 例外 " + ex.GetType().FullName); + } + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestLatebind.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestLatebind.cs new file mode 100644 index 000000000..4ffb79991 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestLatebind.cs @@ -0,0 +1,281 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestLatebind +//* クラス日本語名 :Latebindのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#522) +//********************************************************************************** + +using System; + +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.Reflection; + +namespace TestCode +{ + /// <summary>Latebindのテスト</summary> + /// <remarks> + /// フレームワークの**動的呼び出しの心臓部**(#522)。 + /// B層・D層の自動振り分け(UOC_ メソッドの解決)がこれに依存するため、 + /// 壊れるとフレームワーク全体が動かなくなる。 + /// + /// <押さえる観点> + /// ・**private / static も呼べる**(BindingFlags に NonPublic を含む) + /// ・メソッド が無いとき、例外を投げる版と null を返す版がある + /// ・**オーバーロードは引数の「数」でしか解決しない**(型では解決しない) + /// ・呼び先が投げた例外は、そのままではなく包まれて伝わる + /// </remarks> + public class TestLatebind + { + #region public + + /// <summary>Root</summary> + public static void Root() + { + TestLatebind.TestInvoke(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestLatebind.TestNotFound(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestLatebind.TestOverload(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestLatebind.TestCheck(); + } + + #endregion + + #region テスト用の型 + + /// <summary>呼び出される側の基底</summary> + public class TargetBase + { + /// <summary>基底のメソッド</summary> + /// <returns>固定値</returns> + public string BaseMethod() + { + return "BaseMethod"; + } + } + + /// <summary>呼び出される側</summary> + public class Target : TargetBase + { + /// <summary>引数なし</summary> + /// <returns>固定値</returns> + public string PublicMethod() + { + return "PublicMethod"; + } + + /// <summary>引数あり</summary> + /// <param name="a">数値</param> + /// <param name="b">文字列</param> + /// <returns>連結した文字列</returns> + public string WithArgs(int a, string b) + { + return "WithArgs:" + a + ":" + b; + } + + /// <summary>static</summary> + /// <returns>固定値</returns> + public static string StaticMethod() + { + return "StaticMethod"; + } + + /// <summary>private</summary> + /// <returns>固定値</returns> + /// <remarks> + /// **BindingFlags に NonPublic が含まれるため、外から呼べる。** + /// フレームワークが protected な UOC_ メソッドを解決できるのはこのため。 + /// </remarks> + private string PrivateMethod() + { + return "PrivateMethod"; + } + + /// <summary>オーバーロード(引数 1 個)</summary> + /// <param name="a">数値</param> + /// <returns>固定値</returns> + public string Overloaded(int a) + { + return "Overloaded(int):" + a; + } + + /// <summary>オーバーロード(引数 2 個)</summary> + /// <param name="a">数値</param> + /// <param name="b">数値</param> + /// <returns>固定値</returns> + public string Overloaded(int a, int b) + { + return "Overloaded(int,int):" + a + ":" + b; + } + + /// <summary>例外を投げる</summary> + public void ThrowsInside() + { + throw new InvalidOperationException("呼び先で投げた例外"); + } + } + + #endregion + + #region private + + /// <summary>呼び出せること</summary> + private static void TestInvoke() + { + MyDebug.OutputDebugAndConsole("Latebind.InvokeMethod"); + + Target target = new Target(); + + TestLatebind.Output("引数なし", target, "PublicMethod", new object[] { }); + TestLatebind.Output("引数あり", target, "WithArgs", new object[] { 1, "x" }); + TestLatebind.Output("static", target, "StaticMethod", new object[] { }); + + // **private も呼べる。** + TestLatebind.Output("private", target, "PrivateMethod", new object[] { }); + + // 基底クラスのメソッド + TestLatebind.Output("基底のメソッド", target, "BaseMethod", new object[] { }); + + // 呼び先が投げた例外は、そのままではなく包まれて伝わる。 + TestLatebind.Output("呼び先が例外", target, "ThrowsInside", new object[] { }); + } + + /// <summary>メソッドが無いとき</summary> + /// <remarks> + /// 例外を投げる版と、null を返す版がある。 + /// **null を返す版は「メッセージにメソッド名が含まれるか」で判別している** + /// (Latebind.cs の InvokeMethod_NoErr)。実装のコメントにも + /// 「Exception.Message を修正すると影響がある」と注意書きがある。 + /// </remarks> + private static void TestNotFound() + { + MyDebug.OutputDebugAndConsole("Latebind : メソッドが無いとき"); + + Target target = new Target(); + + // 例外を投げる版 + TestLatebind.Output("InvokeMethod", target, "NotExist", new object[] { }); + + // null を返す版 + try + { + object ret = Latebind.InvokeMethod_NoErr(target, "NotExist", new object[] { }); + MyDebug.OutputDebugAndConsole( + "[InvokeMethod_NoErr] " + (ret == null ? "null" : ret.ToString())); + } + catch (Exception ex) + { + MyDebug.OutputDebugAndConsole("[InvokeMethod_NoErr] 例外 : " + ex.GetType().FullName); + } + } + + /// <summary>オーバーロードの解決</summary> + /// <remarks> + /// オーバーロードがあると GetMethod が AmbiguousMatchException を投げるため、 + /// Latebind は**引数の「数」が一致するもの**を探して呼ぶ。 + /// + /// **型までは解決しない。** 引数の数が同じオーバーロード + /// (例:Foo(int) と Foo(string))は、どちらが呼ばれるか保証されない。 + /// このため、ここでは引数の数が違うものだけを確認している。 + /// </remarks> + private static void TestOverload() + { + MyDebug.OutputDebugAndConsole("Latebind : オーバーロード"); + + Target target = new Target(); + + TestLatebind.Output("引数 1 個", target, "Overloaded", new object[] { 1 }); + TestLatebind.Output("引数 2 個", target, "Overloaded", new object[] { 1, 2 }); + + // 引数の数が一致しない場合 + TestLatebind.Output("引数 3 個(該当なし)", target, "Overloaded", new object[] { 1, 2, 3 }); + } + + /// <summary>型・メソッドの確認</summary> + private static void TestCheck() + { + MyDebug.OutputDebugAndConsole("Latebind : 型とメソッドの確認"); + + Target target = new Target(); + + MyDebug.OutputDebugAndConsole( + "CheckTypeOfBaseClass(Target, TargetBase) : " + + Latebind.CheckTypeOfBaseClass(typeof(Target), typeof(TargetBase))); + + MyDebug.OutputDebugAndConsole( + "CheckTypeOfBaseClass(Target, string) : " + + Latebind.CheckTypeOfBaseClass(typeof(Target), typeof(string))); + + MyDebug.OutputDebugAndConsole( + "CheckTypeOfMethodByName(PublicMethod) : " + + Latebind.CheckTypeOfMethodByName(target, "PublicMethod")); + + // **private も「存在する」と判定される。** + MyDebug.OutputDebugAndConsole( + "CheckTypeOfMethodByName(PrivateMethod) : " + + Latebind.CheckTypeOfMethodByName(target, "PrivateMethod")); + + MyDebug.OutputDebugAndConsole( + "CheckTypeOfMethodByName(NotExist) : " + + Latebind.CheckTypeOfMethodByName(target, "NotExist")); + } + + #endregion + + #region 出力のヘルパ + + /// <summary>呼び出して結果を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="target">対象</param> + /// <param name="methodName">メソッド名</param> + /// <param name="paramSet">引数</param> + /// <remarks> + /// 例外はメッセージではなく**型名だけ**を出す。 + /// メッセージは実行環境の言語で変わり、期待結果と一致しなくなるため。 + /// </remarks> + private static void Output(string caseName, object target, string methodName, object[] paramSet) + { + try + { + object ret = Latebind.InvokeMethod(target, methodName, paramSet); + + MyDebug.OutputDebugAndConsole( + "[" + caseName + "] " + (ret == null ? "null" : ret.ToString())); + } + catch (Exception ex) + { + MyDebug.OutputDebugAndConsole("[" + caseName + "] 例外 : " + ex.GetType().FullName); + } + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestObjectInspector.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestObjectInspector.cs new file mode 100644 index 000000000..c4168a40a --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestObjectInspector.cs @@ -0,0 +1,285 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestObjectInspector +//* クラス日本語名 :ObjectInspectorのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#522) +//********************************************************************************** + +using System; +using System.Collections.Generic; + +using Touryo.Infrastructure.Public.Diagnostics; + +namespace TestCode +{ + /// <summary>ObjectInspectorのテスト</summary> + /// <remarks> + /// オブジェクトの中身を文字列に落とす部品(#522)。 + /// + /// <なぜここを優先するか> + /// **調査やログで使う道具そのもの**なので、これが壊れると + /// 他の不具合を追うときの足場が崩れる。 + /// 出力が決定的で、結果ファイルの比較にそのまま載る。 + /// + /// <静的な設定を持つことに注意> + /// DateTimeFormat / TimeSpanFormat / ExclusionFullyQualifiedNameParts は + /// **static**。設定したまま戻さないと、後続のテストの出力が変わる。 + /// このテストは必ず元に戻す。 + /// </remarks> + public class TestObjectInspector + { + #region public + + /// <summary>Root</summary> + public static void Root() + { + // 静的な設定を退避する。 + string orgDateTimeFormat = ObjectInspector.DateTimeFormat; + string orgTimeSpanFormat = ObjectInspector.TimeSpanFormat; + string[] orgExclusion = ObjectInspector.ExclusionFullyQualifiedNameParts; + + try + { + TestObjectInspector.TestBasic(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestObjectInspector.TestPoco(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestObjectInspector.TestDepthLimit(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestObjectInspector.TestDateTime(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestObjectInspector.TestExclusion(); + } + finally + { + // **必ず戻す。** 後続のテストの出力に影響するため。 + ObjectInspector.DateTimeFormat = orgDateTimeFormat; + ObjectInspector.TimeSpanFormat = orgTimeSpanFormat; + ObjectInspector.ExclusionFullyQualifiedNameParts = orgExclusion; + } + } + + #endregion + + #region テスト用の POCO + + /// <summary>入れ子にする側</summary> + public class InnerPoco + { + /// <summary>Code</summary> + public string Code { get; set; } + + /// <summary>Value</summary> + public int Value { get; set; } + } + + /// <summary>入れ子を持つ側</summary> + public class OuterPoco + { + /// <summary>Name</summary> + public string Name { get; set; } + + /// <summary>Inner(入れ子)</summary> + public InnerPoco Inner { get; set; } + + /// <summary>Numbers(配列)</summary> + public int[] Numbers { get; set; } + } + + /// <summary>自分自身を入れ子にできる型</summary> + /// <remarks>深さの上限と、循環参照の確認に使う。</remarks> + public class NestPoco + { + /// <summary>Level</summary> + public int Level { get; set; } + + /// <summary>Child(自分自身)</summary> + public NestPoco Child { get; set; } + } + + #endregion + + #region private + + /// <summary>基本の型</summary> + private static void TestBasic() + { + MyDebug.OutputDebugAndConsole("ObjectInspector.Inspect : 基本の型"); + + TestObjectInspector.Output("null", null); + TestObjectInspector.Output("int", 123); + TestObjectInspector.Output("string", "あいう"); + TestObjectInspector.Output("bool", true); + TestObjectInspector.Output("空文字", ""); + + // 配列・コレクション + TestObjectInspector.Output("int[]", new int[] { 1, 2, 3 }); + + // 要素が多い場合。**入れ子は浅いので、全要素が出るのが期待。** + TestObjectInspector.Output("int[] (8 要素)", new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }); + + List<string> list = new List<string>(); + list.Add("a"); + list.Add("b"); + TestObjectInspector.Output("List<string>", list); + + Dictionary<string, int> dic = new Dictionary<string, int>(); + dic.Add("x", 1); + dic.Add("y", 2); + TestObjectInspector.Output("Dictionary", dic); + } + + /// <summary>POCO(入れ子と配列を含む)</summary> + private static void TestPoco() + { + MyDebug.OutputDebugAndConsole("ObjectInspector.Inspect : POCO"); + + OuterPoco outer = new OuterPoco(); + outer.Name = "外側"; + outer.Numbers = new int[] { 10, 20 }; + + // 入れ子が null の場合 + TestObjectInspector.Output("入れ子が null", outer); + + // 入れ子に値がある場合 + InnerPoco inner = new InnerPoco(); + inner.Code = "C1"; + inner.Value = 99; + outer.Inner = inner; + + TestObjectInspector.Output("入れ子に値", outer); + } + + /// <summary>深さの上限と循環参照</summary> + /// <remarks> + /// **再帰には深さの上限がある**(ObjectInspector の内部で 5 段)。 + /// 超えた先は "-over-" になり、それ以上は辿らない。 + /// + /// <幅は深さを消費しない> + /// 入口で加算し、出口で減算する深さカウンタなので、 + /// 要素数がいくら多くても打ち切られない(上の「int[] (8 要素)」)。 + /// + /// <循環参照> + /// 自分自身を指していても、深さの上限で止まる。 + /// **この上限が壊れると停止しなくなる**ため、ここで固定しておく。 + /// </remarks> + private static void TestDepthLimit() + { + MyDebug.OutputDebugAndConsole("ObjectInspector.Inspect : 深さの上限"); + + // 深い入れ子(8 段) + NestPoco deep = new NestPoco(); + deep.Level = 1; + + NestPoco current = deep; + for (int i = 2; i <= 8; i++) + { + current.Child = new NestPoco(); + current.Child.Level = i; + current = current.Child; + } + + TestObjectInspector.Output("入れ子 8 段", deep); + + // 循環参照(自分自身を指す) + NestPoco cyclic = new NestPoco(); + cyclic.Level = 1; + cyclic.Child = cyclic; + + TestObjectInspector.Output("循環参照", cyclic); + } + + /// <summary>日時(書式の指定)</summary> + /// <remarks> + /// **DateTimeFormat を指定しないと ToString() になり、実行環境のロケールで変わる。** + /// 期待結果の比較に載せるものは、必ず書式を指定すること。 + /// ここでは「指定した場合」だけを記録する(未指定は環境で変わるため記録できない)。 + /// </remarks> + private static void TestDateTime() + { + MyDebug.OutputDebugAndConsole("ObjectInspector.Inspect : 日時"); + + DateTime dt = new DateTime(2026, 8, 6, 12, 34, 56); + TimeSpan ts = new TimeSpan(1, 2, 3, 4); + + ObjectInspector.DateTimeFormat = "yyyy/MM/dd HH:mm:ss"; + ObjectInspector.TimeSpanFormat = "d\\.hh\\:mm\\:ss"; + + TestObjectInspector.Output("DateTime(書式あり)", dt); + TestObjectInspector.Output("TimeSpan(書式あり)", ts); + + ObjectInspector.DateTimeFormat = ""; + ObjectInspector.TimeSpanFormat = ""; + } + + /// <summary>除外の指定</summary> + /// <remarks> + /// ExclusionFullyQualifiedNameParts に含まれる型は、中身を展開せず + /// 「excluded.」を前置して ToString() の結果を出す。 + /// 大きなオブジェクトや、展開すると副作用のある型を避けるための仕組み。 + /// </remarks> + private static void TestExclusion() + { + MyDebug.OutputDebugAndConsole("ObjectInspector.Inspect : 除外"); + + InnerPoco inner = new InnerPoco(); + inner.Code = "C2"; + inner.Value = 1; + + OuterPoco outer = new OuterPoco(); + outer.Name = "外側"; + outer.Inner = inner; + outer.Numbers = new int[] { 1 }; + + // 除外なし + ObjectInspector.ExclusionFullyQualifiedNameParts = new string[] { }; + TestObjectInspector.Output("除外なし", outer); + + // InnerPoco を除外する + ObjectInspector.ExclusionFullyQualifiedNameParts = new string[] { "InnerPoco" }; + TestObjectInspector.Output("InnerPoco を除外", outer); + + ObjectInspector.ExclusionFullyQualifiedNameParts = new string[] { }; + } + + /// <summary>1 件分を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="obj">対象</param> + private static void Output(string caseName, object obj) + { + MyDebug.OutputDebugAndConsole("[" + caseName + "]"); + MyDebug.OutputDebugAndConsole(ObjectInspector.Inspect(obj)); + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestResourceLoader.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestResourceLoader.cs new file mode 100644 index 000000000..a21583891 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestResourceLoader.cs @@ -0,0 +1,199 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestResourceLoader +//* クラス日本語名 :ResourceLoader・EmbeddedResourceLoaderのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#522) +//********************************************************************************** + +using System; +using System.IO; +using System.Text; + +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.IO; + +namespace TestCode +{ + /// <summary>ResourceLoader・EmbeddedResourceLoaderのテスト</summary> + /// <remarks> + /// SQL 定義ファイルやログ設定など、**リソースの読み込み全般がここに乗る**(#522)。 + /// + /// <なぜここを見るか> + /// 実際に踏んだ失敗がある。SimpleBatch が + /// resource file [C:\...\ShipperCount.sql] was not found. + /// で落ちたのは、この経路で解決できなかったため。 + /// + /// <埋め込みリソース> + /// MyBaseDao.UseEmbeddedResource を立てると、SQL 定義ファイルを + /// DLL に埋め込んだ構成に切り替わる(PaaS 向け)。その読み手がこちら。 + /// + /// <出力にパスを出さないこと> + /// 一時フォルダも配置フォルダも実行環境で変わる。 + /// **結果ファイルの比較に載せるのは、真偽と中身だけにする。** + /// </remarks> + public class TestResourceLoader + { + #region 定数 + + /// <summary>埋め込みリソースの論理名</summary> + /// <remarks> + /// csproj で LogicalName を明示しているため、net48 と .NET (Core) で同じ名前になる。 + /// **既定のままだと "既定の名前空間 + ファイル名" になり、 + /// プロジェクト名が違う分だけ名前が食い違う。** + /// </remarks> + private const string EmbeddedName = "TestCode.TestEmbedded.txt"; + + #endregion + + #region public + + /// <summary>Root</summary> + public static void Root() + { + TestResourceLoader.TestResolveAndLoad(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestResourceLoader.TestEmbedded(); + } + + #endregion + + #region private + + /// <summary>実ファイルの解決と読み込み</summary> + private static void TestResolveAndLoad() + { + MyDebug.OutputDebugAndConsole("ResourceLoader"); + + string dir = Path.Combine(Path.GetTempPath(), "OpenTouryoTestResource"); + string path = Path.Combine(dir, "TestResource.txt"); + + Directory.CreateDirectory(dir); + File.WriteAllText(path, "リソースの内容", new UTF8Encoding(false)); + + const string envName = "OPENTOURYO_TEST_RESDIR"; + string orgEnv = Environment.GetEnvironmentVariable(envName, EnvironmentVariableTarget.Process); + + try + { + // --- 絶対パス --- + MyDebug.OutputDebugAndConsole( + "絶対パスで解決 : " + (ResourceLoader.ResolveFilePath(path) != null)); + MyDebug.OutputDebugAndConsole( + "絶対パスで読み込み : " + ResourceLoader.LoadAsString(path, Encoding.UTF8)); + + // --- 環境変数入りのパス --- + // ResolveFilePath は先頭で環境変数を展開する。 + Environment.SetEnvironmentVariable(envName, dir, EnvironmentVariableTarget.Process); + + MyDebug.OutputDebugAndConsole( + "環境変数入りで解決 : " + + (ResourceLoader.ResolveFilePath("%" + envName + "%\\TestResource.txt") != null)); + + // --- EXE の配置フォルダ基準の相対パス --- + // SampleLogConf.xml は出力フォルダにコピーされる(csproj の Content)。 + // カレント ディレクトリに関係なく解決できること。 + MyDebug.OutputDebugAndConsole( + "配置フォルダ基準 : " + + (ResourceLoader.ResolveFilePath("SampleLogConf.xml") != null)); + + // --- 見つからない場合 --- + MyDebug.OutputDebugAndConsole( + "見つからない(解決) : " + + (ResourceLoader.ResolveFilePath("NotExist_OpenTouryo.txt") == null ? "null" : "not null")); + + MyDebug.OutputDebugAndConsole( + "見つからない(Exists): " + + ResourceLoader.Exists("NotExist_OpenTouryo.txt", false)); + + // throwException = true の場合 + try + { + ResourceLoader.Exists("NotExist_OpenTouryo.txt", true); + MyDebug.OutputDebugAndConsole("見つからない(例外) : 例外にならない"); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole("見つからない(例外) : " + ex.GetType().FullName); + } + + // --- 空とnull --- + MyDebug.OutputDebugAndConsole( + "空文字(解決) : " + + (ResourceLoader.ResolveFilePath("") == null ? "null" : "not null")); + MyDebug.OutputDebugAndConsole( + "null(解決) : " + + (ResourceLoader.ResolveFilePath(null) == null ? "null" : "not null")); + } + finally + { + // 後始末。**環境変数は必ず戻す。** + Environment.SetEnvironmentVariable(envName, orgEnv, EnvironmentVariableTarget.Process); + + try + { + File.Delete(path); + Directory.Delete(dir); + } + catch + { + // 消せなくてもテストの成否には関係しない。 + } + } + } + + /// <summary>埋め込みリソースの読み込み</summary> + private static void TestEmbedded() + { + MyDebug.OutputDebugAndConsole("EmbeddedResourceLoader"); + + MyDebug.OutputDebugAndConsole( + "存在する : " + + EmbeddedResourceLoader.Exists(TestResourceLoader.EmbeddedName, false)); + + MyDebug.OutputDebugAndConsole( + "読み込み : " + + EmbeddedResourceLoader.LoadAsString(TestResourceLoader.EmbeddedName, Encoding.UTF8).Trim()); + + MyDebug.OutputDebugAndConsole( + "存在しない : " + + EmbeddedResourceLoader.Exists("TestCode.NotExist.txt", false)); + + // throwException = true の場合 + try + { + EmbeddedResourceLoader.Exists("TestCode.NotExist.txt", true); + MyDebug.OutputDebugAndConsole("存在しない(例外) : 例外にならない"); + } + catch (Exception ex) + { + MyDebug.OutputDebugAndConsole("存在しない(例外) : " + ex.GetType().FullName); + } + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestStringExtractor.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestStringExtractor.cs new file mode 100644 index 000000000..d7bc79cc5 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestStringExtractor.cs @@ -0,0 +1,176 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestStringExtractor +//* クラス日本語名 :StringExtractor・ToStringExtensionのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#522) +//********************************************************************************** + +using System; +using System.Xml; + +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.Str; + +namespace TestCode +{ + /// <summary>StringExtractor・ToStringExtensionのテスト</summary> + /// <remarks> + /// 文字列からの抽出(クエリ文字列・XML 属性)と、XmlDocument の文字列化(#522)。 + /// </remarks> + public class TestStringExtractor + { + #region public + + /// <summary>Root</summary> + public static void Root() + { + TestStringExtractor.TestGetParameterFromQueryString(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestStringExtractor.TestGetAttributeFromXml(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestStringExtractor.TestXmlToString(); + } + + #endregion + + #region private + + /// <summary>クエリ文字列からの抽出</summary> + private static void TestGetParameterFromQueryString() + { + MyDebug.OutputDebugAndConsole("StringExtractor.GetParameterFromQueryString"); + + const string url = "/path/page?a=1&b=xyz&c="; + + TestStringExtractor.OutputQuery("先頭の値", "a", url); + TestStringExtractor.OutputQuery("途中の値", "b", url); + TestStringExtractor.OutputQuery("空の値", "c", url); + TestStringExtractor.OutputQuery("無い名前", "z", url); + + // クエリ文字列が無い場合 + TestStringExtractor.OutputQuery("クエリ無し", "a", "/path/page"); + + // 名前の一部が他の名前に含まれる場合 + // ("a" が "ab" に前方一致してしまわないこと) + TestStringExtractor.OutputQuery("前方一致の紛れ", "a", "/p?ab=9&a=1"); + } + + /// <summary>XML の属性値の抽出</summary> + /// <remarks> + /// XML パーサを通さない文字列処理。整形式でなくても動く代わりに、 + /// **同名の属性が複数あると先頭が取れる**などの癖がある。 + /// </remarks> + private static void TestGetAttributeFromXml() + { + MyDebug.OutputDebugAndConsole("StringExtractor.GetAttributeFromXml"); + + const string xml = "<root id=\"1\" name=\"abc\"><child id=\"2\" /></root>"; + + TestStringExtractor.OutputAttr("最初の属性", xml, "id"); + TestStringExtractor.OutputAttr("2 番目の属性", xml, "name"); + TestStringExtractor.OutputAttr("無い属性", xml, "notexist"); + } + + /// <summary>XmlDocument の文字列化</summary> + /// <remarks> + /// **XmlWriterSettings を明示する。** 既定のままだと改行や宣言の有無が + /// 実装に依存し、期待結果と一致しなくなる。 + /// </remarks> + private static void TestXmlToString() + { + MyDebug.OutputDebugAndConsole("ToStringExtension.XmlToString"); + + XmlDocument doc = new XmlDocument(); + doc.LoadXml("<root><child id=\"1\">値</child></root>"); + + // 宣言なし・インデントなしで、1 行に固定する。 + XmlWriterSettings settings = new XmlWriterSettings(); + settings.OmitXmlDeclaration = true; + settings.Indent = false; + + MyDebug.OutputDebugAndConsole("宣言なし : " + doc.XmlToString(settings)); + + // インデントあり(改行が入る) + XmlWriterSettings indented = new XmlWriterSettings(); + indented.OmitXmlDeclaration = true; + indented.Indent = true; + indented.IndentChars = " "; + indented.NewLineChars = "\n"; + + MyDebug.OutputDebugAndConsole("インデントあり :"); + MyDebug.OutputDebugAndConsole(doc.XmlToString(indented)); + } + + #endregion + + #region 出力のヘルパ + + /// <summary>クエリ文字列の抽出結果を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="paramName">パラメタ名</param> + /// <param name="rawUrl">URL</param> + private static void OutputQuery(string caseName, string paramName, string rawUrl) + { + try + { + string ret = StringExtractor.GetParameterFromQueryString(paramName, rawUrl); + + MyDebug.OutputDebugAndConsole( + "[" + caseName + "] " + paramName + " → " + + (ret == null ? "(null)" : "\"" + ret + "\"")); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole("[" + caseName + "] 例外 : " + ex.GetType().FullName); + } + } + + /// <summary>XML 属性の抽出結果を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="xml">XML</param> + /// <param name="attrName">属性名</param> + private static void OutputAttr(string caseName, string xml, string attrName) + { + try + { + string ret = StringExtractor.GetAttributeFromXml(xml, attrName); + + MyDebug.OutputDebugAndConsole( + "[" + caseName + "] " + attrName + " → " + + (ret == null ? "(null)" : "\"" + ret + "\"")); + } + catch (Exception ex) + { + MyDebug.OutputDebugAndConsole("[" + caseName + "] 例外 : " + ex.GetType().FullName); + } + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestStringVariableOperator.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestStringVariableOperator.cs new file mode 100644 index 000000000..b4bd5284d --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestStringVariableOperator.cs @@ -0,0 +1,195 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestStringVariableOperator +//* クラス日本語名 :StringVariableOperatorのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#522) +//********************************************************************************** + +using System; +using System.Collections.Generic; + +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.Str; + +namespace TestCode +{ + /// <summary>StringVariableOperatorのテスト</summary> + /// <remarks> + /// プロパティ文字列の解析と、環境変数の埋め込みを確認する(#522)。 + /// + /// <GetCommandArgs は対象外> + /// **Environment.CommandLine を直接読むため、単体テストでは扱えない。** + /// 引数を変えて確かめるには、実際にプロセスを起動するしかない。 + /// このため 3_SmokeTest.ps1 の DaoGen_Tool(CUI)が実質の確認になっている。 + /// + /// **なお、あちらには「\ がエスケープ文字」という罠がある**(#508 で踏んだ)。 + /// パス区切りに \ を使うと消えてしまい、**終了コードは 0 のまま + /// 別の場所に出力される**。詳細は Tools/DaoGen_Tool/README.md。 + /// </remarks> + public class TestStringVariableOperator + { + #region public + + /// <summary>Root</summary> + public static void Root() + { + TestStringVariableOperator.TestGetPropsFromPropString(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestStringVariableOperator.TestBuiltStringIntoEnvironmentVariable(); + } + + #endregion + + #region private + + /// <summary>プロパティ文字列の解析</summary> + /// <remarks> + /// 書式は [property=value[;property=value]]。 + /// 値に「=」「;」が混じる場合は { } で囲ってエスケープする({=} / {;})。 + /// **{ } 自体はエスケープできない**(実装の制約)。 + /// </remarks> + private static void TestGetPropsFromPropString() + { + MyDebug.OutputDebugAndConsole("StringVariableOperator.GetPropsFromPropString"); + + // 基本 + TestStringVariableOperator.OutputProps("1 組", "a=1"); + TestStringVariableOperator.OutputProps("2 組", "a=1;b=2"); + + // 値が空 + TestStringVariableOperator.OutputProps("値が空", "a=;b=2"); + + // エスケープ(値に「=」「;」を含める) + TestStringVariableOperator.OutputProps("値に = を含む", "a={=};b=2"); + TestStringVariableOperator.OutputProps("値に ; を含む", "a={;};b=2"); + + // 名前側のエスケープ + TestStringVariableOperator.OutputProps("名前に = を含む", "a{=}b=1"); + + // 異常系(書式エラーは例外) + TestStringVariableOperator.OutputProps("= が無い", "a"); + TestStringVariableOperator.OutputProps("空文字", ""); + } + + /// <summary>環境変数の埋め込み</summary> + /// <remarks> + /// 「%環境変数名%」を値に置き換える。 + /// **テスト専用の環境変数を自分で設定してから使う。** + /// 既存の環境変数(TEMP など)に依存すると、実行環境で結果が変わる。 + /// </remarks> + private static void TestBuiltStringIntoEnvironmentVariable() + { + MyDebug.OutputDebugAndConsole("StringVariableOperator.BuiltStringIntoEnvironmentVariable"); + + const string name = "OPENTOURYO_TEST_VAR"; + string org = Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process); + + try + { + Environment.SetEnvironmentVariable(name, "VALUE", EnvironmentVariableTarget.Process); + + TestStringVariableOperator.OutputEnvVar("そのまま", "abc"); + TestStringVariableOperator.OutputEnvVar("埋め込み", "x%" + name + "%y"); + TestStringVariableOperator.OutputEnvVar("2 回", "%" + name + "%-%" + name + "%"); + + // 存在しない環境変数 + TestStringVariableOperator.OutputEnvVar("未定義", "x%OPENTOURYO_NOT_EXIST%y"); + + // 「%」が奇数個(閉じていない) + TestStringVariableOperator.OutputEnvVar("閉じていない", "x%" + name); + + // null と空文字 + TestStringVariableOperator.OutputEnvVar("null", null); + TestStringVariableOperator.OutputEnvVar("空文字", ""); + } + finally + { + // **必ず戻す。** 後続のテストや同一プロセス内の他の処理に影響するため。 + Environment.SetEnvironmentVariable(name, org, EnvironmentVariableTarget.Process); + } + } + + #endregion + + #region 出力のヘルパ + + /// <summary>プロパティ文字列の解析結果を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="propString">プロパティ文字列</param> + /// <remarks> + /// 例外はメッセージではなく**型名だけ**を出す。 + /// メッセージは実行環境の言語で変わり、期待結果と一致しなくなるため。 + /// </remarks> + private static void OutputProps(string caseName, string propString) + { + MyDebug.OutputDebugAndConsole("[" + caseName + "] " + propString); + + try + { + Dictionary<string, string> dic = + StringVariableOperator.GetPropsFromPropString(propString); + + // 並び順が実装に依存しないよう、キーを並べ替えてから出す。 + List<string> keys = new List<string>(dic.Keys); + keys.Sort(StringComparer.Ordinal); + + MyDebug.OutputDebugAndConsole(" 件数 : " + dic.Count); + + foreach (string key in keys) + { + MyDebug.OutputDebugAndConsole(" " + key + " = " + dic[key]); + } + } + catch (Exception ex) + { + MyDebug.OutputDebugAndConsole(" 例外 : " + ex.GetType().FullName); + } + } + + /// <summary>環境変数の埋め込み結果を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="builtString">環境変数名入り文字列</param> + private static void OutputEnvVar(string caseName, string builtString) + { + try + { + string result = StringVariableOperator.BuiltStringIntoEnvironmentVariable(builtString); + + MyDebug.OutputDebugAndConsole( + "[" + caseName + "] " + + (builtString == null ? "(null)" : builtString) + + " → " + + (result == null ? "(null)" : result)); + } + catch (Exception ex) + { + MyDebug.OutputDebugAndConsole("[" + caseName + "] 例外 : " + ex.GetType().FullName); + } + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestUtil.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestUtil.cs new file mode 100644 index 000000000..5a0e9fa7e --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestUtil.cs @@ -0,0 +1,320 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestUtil +//* クラス日本語名 :Public.Utilのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#522) +//********************************************************************************** + +using System; + +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.Util; + +namespace TestCode +{ + /// <summary>Public.Utilのテスト</summary> + /// <remarks> + /// 型変換・配列操作・設定の読み取り(#522)。 + /// + /// <対象を絞っている> + /// このクラス群には**実行環境で値が変わるもの**が混ざる。 + /// 結果ファイルの比較に載せられないため、次は値を出さない。 + /// ・EnvInfo … マシン名・OS・ビット数など + /// ・GetConfigParameter … 設定値そのもの(net48 と .NET (Core) でパス区切りが違う) + /// 「取得できること」「無いキーは null」までに留める。 + /// + /// RandomValueGenerator / PerformanceRecorder は実行ごとに変わるため対象外。 + /// </remarks> + public class TestUtil + { + #region public + + /// <summary>Root</summary> + public static void Root() + { + TestUtil.TestPubCmnFunction(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestUtil.TestArrayOperator(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestUtil.TestConfigAndEnv(); + } + + #endregion + + #region private + + /// <summary>PubCmnFunction</summary> + /// <remarks> + /// ChangeType と GetUnderlyingType は **DataToPoco が型変換に使う**。 + /// ここが変わると項目移送の挙動が変わる(TestDto と対で見ること)。 + /// </remarks> + private static void TestPubCmnFunction() + { + MyDebug.OutputDebugAndConsole("PubCmnFunction"); + + // --- ChangeType --- + TestUtil.OutputChangeType("string → int", "123", typeof(int)); + TestUtil.OutputChangeType("int → string", 123, typeof(string)); + TestUtil.OutputChangeType("string → int?", "123", typeof(int?)); + TestUtil.OutputChangeType("null → int?", null, typeof(int?)); + TestUtil.OutputChangeType("string → decimal", "1.5", typeof(decimal)); + TestUtil.OutputChangeType("変換できない", "abc", typeof(int)); + + // --- GetUnderlyingType --- + // Nullable は実体型に、そうでなければ null。 + MyDebug.OutputDebugAndConsole( + "GetUnderlyingType(int?) : " + TestUtil.TypeName(PubCmnFunction.GetUnderlyingType(typeof(int?)))); + MyDebug.OutputDebugAndConsole( + "GetUnderlyingType(int) : " + TestUtil.TypeName(PubCmnFunction.GetUnderlyingType(typeof(int)))); + MyDebug.OutputDebugAndConsole( + "GetUnderlyingType(string): " + TestUtil.TypeName(PubCmnFunction.GetUnderlyingType(typeof(string)))); + + // --- ToUnixTime --- + // 固定の日時を与えれば決定的。UTC で与えること。 + DateTimeOffset dto = new DateTimeOffset(2026, 8, 6, 12, 34, 56, TimeSpan.Zero); + MyDebug.OutputDebugAndConsole("ToUnixTime : " + PubCmnFunction.ToUnixTime(dto)); + + // --- GetFileNameNoEx --- + // **第 2 引数は「パス区切り」であって、拡張子の区切りではない。** + // (1) 区切り文字で分けて末尾=ファイル名を取り出す + // (2) それを「.」で分けて、最後の 1 つ(拡張子)を落として繋ぎ直す + // 「.」を渡すと (1) で拡張子だけが残り、(2) で全部落ちて空になる。 + MyDebug.OutputDebugAndConsole( + "GetFileNameNoEx(パス付き) : " + PubCmnFunction.GetFileNameNoEx("C:\\dir\\a.txt", '\\')); + MyDebug.OutputDebugAndConsole( + "GetFileNameNoEx(二重拡張子) : " + PubCmnFunction.GetFileNameNoEx("C:\\dir\\a.b.txt", '\\')); + MyDebug.OutputDebugAndConsole( + "GetFileNameNoEx(拡張子なし) : " + PubCmnFunction.GetFileNameNoEx("C:\\dir\\abc", '\\')); + MyDebug.OutputDebugAndConsole( + "GetFileNameNoEx(区切りを「.」): \"" + PubCmnFunction.GetFileNameNoEx("a.txt", '.') + "\""); + + // --- 呼び出し元の情報 --- + // メソッド名は固定なので決定的。 + // **ファイル パスと行番号は出さない**(環境と編集で変わるため)。 + MyDebug.OutputDebugAndConsole( + "GetCurrentMethodName : " + PubCmnFunction.GetCurrentMethodName()); + } + + /// <summary>ArrayOperator</summary> + private static void TestArrayOperator() + { + MyDebug.OutputDebugAndConsole("ArrayOperator"); + + int[] src = new int[] { 1, 2, 3 }; + byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + + // 縮める + TestUtil.OutputArray("CopyArray(3 → 2)", delegate { return ArrayOperator.CopyArray<int>(src, 2); }); + + // **伸ばせない。** 指定したサイズ分を元配列から読むため、元より大きいと例外になる。 + TestUtil.OutputArray("CopyArray(3 → 5)", delegate { return ArrayOperator.CopyArray<int>(src, 5); }); + + // 開始位置を指定 + // + // **コピーする長さは「コピー先配列の長さ」で固定されている。** + // Array.Copy(src, srcStart, dst, dstStart, dstArraySize) + // そのため書込開始位置を 0 より後ろにすると、必ずコピー先が溢れる。 + // 実質「読取開始位置をずらす」用途にしか使えない。 + TestUtil.OutputArray("CopyArray(読取開始位置をずらす)", + delegate { return ArrayOperator.CopyArray<int>(src, 2, 1, 0); }); + TestUtil.OutputArray("CopyArray(書込開始位置をずらす)", + delegate { return ArrayOperator.CopyArray<int>(src, 2, 0, 1); }); + + // 連結 + TestUtil.OutputArray("CombineArray", + delegate { return ArrayOperator.CombineArray<int>(src, new int[] { 4, 5 }); }); + + // バイト配列 + TestUtil.OutputArray("ShortenByteArray(8 → 3)", + delegate { return ArrayOperator.ShortenByteArray(bytes, 3); }); + + TestUtil.TestGetLongFromByte(); + } + + /// <summary>GetLongFromByte</summary> + /// <remarks> + /// ビッグ エンディアンとして解釈する。**桁の境界を必ず押さえる。** + /// + /// 2026/08/06 まで、桁の重みを 256 * j(掛け算)で求めていたため + /// **3 byte 目から誤った値**を返していた(#522)。 + /// 1〜2 byte は 256 * 1 == 256 ^ 1 でたまたま一致するため、 + /// **2 byte までしか見ないと不具合に気付けない。** + /// </remarks> + private static void TestGetLongFromByte() + { + MyDebug.OutputDebugAndConsole("ArrayOperator.GetLongFromByte"); + + // 桁の境界。3 byte 目が 65536(256 ^ 2)の重みを持つこと。 + TestUtil.OutputLong("1 byte", new byte[] { 0x01 }); // 1 + TestUtil.OutputLong("2 byte", new byte[] { 0x01, 0x02 }); // 258 + TestUtil.OutputLong("3 byte", new byte[] { 0x01, 0x02, 0x03 }); // 66051 + TestUtil.OutputLong("3 byte(上位のみ)", new byte[] { 0x01, 0x00, 0x00 }); // 65536 + + // 8 byte(上限) + TestUtil.OutputLong("8 byte", + new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }); // 0x0102030405060708 + + // 8 byte で最上位ビットが立つと、Int64 の範囲を超えて負になる。 + TestUtil.OutputLong("8 byte(最上位ビット)", + new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); // -1 + + // 範囲外 + TestUtil.OutputLong("0 byte", new byte[] { }); + TestUtil.OutputLong("9 byte", new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); + + // null は ArgumentNullException(2026/08/06 まで NullReferenceException だった) + TestUtil.OutputLong("null", null); + } + + /// <summary>設定と環境情報</summary> + /// <remarks> + /// **値は出さない。** 実行環境で変わるため。 + /// 「取れること」「無いキーは null」までを確認する。 + /// </remarks> + private static void TestConfigAndEnv() + { + MyDebug.OutputDebugAndConsole("GetConfigParameter / EnvInfo"); + + // App.config / appsettings.json の両方に同じ値を書いてあるキー。 + MyDebug.OutputDebugAndConsole( + "GetConfigValue(FxBusinessMessageCulture) : " + + GetConfigParameter.GetConfigValue("FxBusinessMessageCulture")); + + // 無いキー + string notExist = GetConfigParameter.GetConfigValue("OpenTouryo_NotExistKey"); + MyDebug.OutputDebugAndConsole( + "無いキー : " + (string.IsNullOrEmpty(notExist) ? "null または空" : "値あり")); + + // 環境情報は**取得できることだけ**を見る。 + MyDebug.OutputDebugAndConsole( + "EnvInfo.MachineName が取れる : " + !string.IsNullOrEmpty(EnvInfo.MachineName)); + MyDebug.OutputDebugAndConsole( + "EnvInfo.OsVersionString が取れる : " + !string.IsNullOrEmpty(EnvInfo.OsVersionString)); + MyDebug.OutputDebugAndConsole( + "EnvInfo.ProcessBit が 32 または 64 : " + + (EnvInfo.ProcessBit == 32 || EnvInfo.ProcessBit == 64)); + } + + #endregion + + #region 出力のヘルパ + + /// <summary>ChangeType の結果を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="src">変換元</param> + /// <param name="dstType">変換先の型</param> + private static void OutputChangeType(string caseName, object src, Type dstType) + { + try + { + object ret = PubCmnFunction.ChangeType(src, dstType); + + MyDebug.OutputDebugAndConsole( + "ChangeType " + caseName + " : " + + (ret == null ? "null" : ret.ToString() + " (" + ret.GetType().Name + ")")); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole( + "ChangeType " + caseName + " : 例外 " + ex.GetType().FullName); + } + } + + /// <summary>型名を返す</summary> + /// <param name="t">型</param> + /// <returns>型名(null の場合は "(null)")</returns> + private static string TypeName(Type t) + { + return (t == null) ? "(null)" : t.Name; + } + + /// <summary>配列を返す処理</summary> + /// <returns>配列</returns> + private delegate Array ArrayFunc(); + + /// <summary>配列操作の結果を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="func">配列を返す処理</param> + /// <remarks> + /// **例外を必ず捕まえる。** 捕まえないと Program.Main まで抜けて実行が中断し、 + /// さらに**パス入りのスタック トレースが結果ファイルに出る**(環境依存の差分になる)。 + /// </remarks> + private static void OutputArray(string caseName, ArrayFunc func) + { + try + { + MyDebug.OutputDebugAndConsole(caseName + " : " + TestUtil.Join(func())); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole(caseName + " : 例外 " + ex.GetType().FullName); + } + } + + /// <summary>GetLongFromByte の結果を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="bytes">バイト配列</param> + private static void OutputLong(string caseName, byte[] bytes) + { + try + { + MyDebug.OutputDebugAndConsole( + caseName + " : " + ArrayOperator.GetLongFromByte(bytes)); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole(caseName + " : 例外 " + ex.GetType().FullName); + } + } + + /// <summary>配列を連結して出力用の文字列にする</summary> + /// <param name="array">配列</param> + /// <returns>連結した文字列</returns> + private static string Join(Array array) + { + if (array == null) + { + return "(null)"; + } + + string ret = ""; + + foreach (object o in array) + { + ret += (ret == "" ? "" : ", ") + o.ToString(); + } + + return "[" + ret + "]"; + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/TestZipV2.cs b/root/programs/CS/Frameworks/Tests/TestCode/TestZipV2.cs new file mode 100644 index 000000000..792689eb5 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestCode/TestZipV2.cs @@ -0,0 +1,529 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestZipV2 +//* クラス日本語名 :ZipperV2・UnZipperV2のテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/08 玄人 幸道 新規作成(#524) +//********************************************************************************** + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.IO; + +namespace TestCode +{ + /// <summary>ZipperV2・UnZipperV2のテスト</summary> + /// <remarks> + /// SharpZipLib による ZIP 部品の復元(#524)。 + /// + /// <ZIP のバイト列は結果ファイルに載せない> + /// 圧縮結果はライブラリの実装と実行日時で変わるため、比較できない。 + /// **「往復して一致するか」「エントリ名」「例外の型名」だけを記録する。** + /// + /// <作業フォルダ> + /// 実行のたびに一時フォルダを作って、終わったら消す。 + /// **パスは出力しない**(環境依存になるため)。 + /// </remarks> + public class TestZipV2 + { + #region public + + /// <summary>Root</summary> + public static void Root() + { + TestZipV2.Run("往復", TestZipV2.TestRoundTrip); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestZipV2.Run("暗号化", TestZipV2.TestEncryption); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestZipV2.Run("選択デリゲート", TestZipV2.TestSelectionAndOverwrite); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestZipV2.Run("進捗イベント", TestZipV2.TestProgressAndSafety); + } + + #endregion + + #region 実行のヘルパ + + /// <summary>テストの本体</summary> + private delegate void TestBody(); + + /// <summary>1 節を実行する</summary> + /// <param name="name">節の名前</param> + /// <param name="body">テストの本体</param> + /// <remarks> + /// **例外を必ず捕まえる。** 捕まえないと Program.Main まで抜けて + /// 以降のテストが動かなくなり、さらに**パス入りのスタック トレースが + /// 結果ファイルに出る**(環境依存の差分になる)。 + /// </remarks> + private static void Run(string name, TestBody body) + { + try + { + body(); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole("[" + name + "] 例外 " + ex.GetType().FullName); + } + } + + #endregion + + #region private + + /// <summary>圧縮 → 解凍の往復</summary> + /// <remarks> + /// 階層と日本語のファイル名を含める。 + /// **区切りは "/" になること**も見る(ZIP の仕様)。 + /// </remarks> + private static void TestRoundTrip() + { + MyDebug.OutputDebugAndConsole("ZipperV2 → UnZipperV2(往復)"); + + string work = TestZipV2.CreateWorkDir(); + + try + { + string src = TestZipV2.CreateSampleTree(work); + string dst = Path.Combine(work, "out"); + + ZipperV2 z = new ZipperV2(); + z.CreateZipFromFolder( + Path.Combine(work, "archive"), src, + null, null, "root", null, + ZipEncryptionAlgorithmV2.None, null, + ZipCompressionLevelV2.Default); + + UnZipperV2 uz = new UnZipperV2(); + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.OverwriteSilently, null, null); + + // 解凍したファイルの一覧(旧 StatusMSG の解析の代替) + MyDebug.OutputDebugAndConsole("解凍した件数 : " + uz.ExtractedFiles.Length); + + foreach (string s in TestZipV2.ToRelativeSorted(uz.ExtractedFiles, dst)) + { + MyDebug.OutputDebugAndConsole(" " + s); + } + + // 内容が一致するか + MyDebug.OutputDebugAndConsole( + "内容が一致 : " + TestZipV2.AreSameTree(src, Path.Combine(dst, "root"))); + } + finally { TestZipV2.DeleteWorkDir(work); } + } + + /// <summary>暗号化</summary> + private static void TestEncryption() + { + MyDebug.OutputDebugAndConsole("暗号化"); + + TestZipV2.OutputEncryption("暗号化なし", ZipEncryptionAlgorithmV2.None, null, null); + TestZipV2.OutputEncryption("PkzipWeak", ZipEncryptionAlgorithmV2.PkzipWeak, "pass", "pass"); + TestZipV2.OutputEncryption("WinZipAes128", ZipEncryptionAlgorithmV2.WinZipAes128, "pass", "pass"); + TestZipV2.OutputEncryption("WinZipAes256", ZipEncryptionAlgorithmV2.WinZipAes256, "pass", "pass"); + + // パスワードが違う + TestZipV2.OutputEncryption("パスワード誤り", ZipEncryptionAlgorithmV2.WinZipAes256, "pass", "wrong"); + + // 暗号化するのにパスワードが無い + TestZipV2.OutputEncryption("パスワード未指定", ZipEncryptionAlgorithmV2.WinZipAes256, null, null); + } + + /// <summary>選択デリゲートと上書きの動作</summary> + private static void TestSelectionAndOverwrite() + { + MyDebug.OutputDebugAndConsole("選択デリゲート"); + + string work = TestZipV2.CreateWorkDir(); + + try + { + string src = TestZipV2.CreateSampleTree(work); + string dst = Path.Combine(work, "out"); + + // 圧縮時に .log を除く + ZipperV2 z = new ZipperV2(); + z.CreateZipFromFolder( + Path.Combine(work, "archive"), src, + new ZipBaseV2.SelectionDelegate(TestZipV2.SelectByExtension), ".log", + "", null, + ZipEncryptionAlgorithmV2.None, null, + ZipCompressionLevelV2.Default); + + UnZipperV2 uz = new UnZipperV2(); + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.OverwriteSilently, null, null); + + MyDebug.OutputDebugAndConsole("[圧縮時に .log を除く]"); + foreach (string s in TestZipV2.ToRelativeSorted(uz.ExtractedFiles, dst)) + { + MyDebug.OutputDebugAndConsole(" " + s); + } + + #region 上書き時の動作 + + MyDebug.OutputDebugAndConsole("[上書き時の動作]"); + + // DoNotOverwrite … 飛ばすので ExtractedFiles に載らない + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.DoNotOverwrite, null, null); + MyDebug.OutputDebugAndConsole(" DoNotOverwrite の解凍件数 : " + uz.ExtractedFiles.Length); + + // OverwriteSilently … 全件やり直す + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.OverwriteSilently, null, null); + MyDebug.OutputDebugAndConsole(" OverwriteSilently の解凍件数 : " + uz.ExtractedFiles.Length); + + // Throw … 例外 + try + { + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.Throw, null, null); + MyDebug.OutputDebugAndConsole(" Throw : 例外にならなかった"); + } + catch (Exception ex) + { + MyDebug.OutputDebugAndConsole(" Throw : 例外 " + ex.GetType().FullName); + } + + #endregion + + #region 上書きをハンドラに問い合わせる + + // InvokeExtractProgressEvent … 1 件ずつ問い合わせる。 + // DeployZipPackWithHTTP が上書き確認ダイアログに使っている(#528)。 + MyDebug.OutputDebugAndConsole("[上書きの問い合わせ]"); + + // (1) 問い合わせに「上書きする」と答える + int asked = 0; + uz.ExtractProgress = delegate (object sender, ZipProgressEventArgsV2 e) + { + if (e.EventType == ZipProgressEventTypeV2.Extracting_ExtractEntryWouldOverwrite + && e.IsQuery) + { + asked++; + e.ExtractExistingFile = ExtractExistingFileActionV2.OverwriteSilently; + } + }; + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.InvokeExtractProgressEvent, null, null); + MyDebug.OutputDebugAndConsole( + " 上書きすると答えた : 問い合わせ " + asked + " 件 / 解凍 " + uz.ExtractedFiles.Length + " 件"); + + // (2) 何も答えない … 既定は「上書きしない」(安全側) + uz.ExtractProgress = null; + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.InvokeExtractProgressEvent, null, null); + MyDebug.OutputDebugAndConsole( + " 答えない(既定) : 解凍 " + uz.ExtractedFiles.Length + " 件"); + + // (3) 1 件目で打ち切る + uz.ExtractProgress = delegate (object sender, ZipProgressEventArgsV2 e) + { + if (e.EventType == ZipProgressEventTypeV2.Extracting_ExtractEntryWouldOverwrite + && e.IsQuery) + { + e.Cancel = true; + } + }; + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.InvokeExtractProgressEvent, null, null); + MyDebug.OutputDebugAndConsole( + " 打ち切る : 解凍 " + uz.ExtractedFiles.Length + " 件"); + + uz.ExtractProgress = null; + + #endregion + } + finally { TestZipV2.DeleteWorkDir(work); } + } + + /// <summary>進捗イベントと安全性</summary> + private static void TestProgressAndSafety() + { + MyDebug.OutputDebugAndConsole("進捗イベント"); + + string work = TestZipV2.CreateWorkDir(); + + try + { + string src = TestZipV2.CreateSampleTree(work); + string dst = Path.Combine(work, "out"); + + // **回数は数えない。** バッファ サイズとファイル サイズで変わるため。 + // 「どの種別が起きたか」だけを記録する。 + List<string> saving = new List<string>(); + List<string> extracting = new List<string>(); + + ZipperV2 z = new ZipperV2(); + z.SaveProgress = delegate (object sender, ZipProgressEventArgsV2 e) + { + string s = e.EventType.ToString(); + if (!saving.Contains(s)) { saving.Add(s); } + }; + + z.CreateZipFromFolder( + Path.Combine(work, "archive"), src, + null, null, "", null, + ZipEncryptionAlgorithmV2.None, null, + ZipCompressionLevelV2.Default); + + UnZipperV2 uz = new UnZipperV2(); + uz.ExtractProgress = delegate (object sender, ZipProgressEventArgsV2 e) + { + string s = e.EventType.ToString(); + if (!extracting.Contains(s)) { extracting.Add(s); } + }; + + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.OverwriteSilently, null, null); + + MyDebug.OutputDebugAndConsole("SaveProgress : " + string.Join(", ", saving.ToArray())); + MyDebug.OutputDebugAndConsole("ExtractProgress : " + string.Join(", ", extracting.ToArray())); + + #region 圧縮レベル + + // **サイズは出さない。** 実装で変わるため、大小関係だけを見る。 + long none = TestZipV2.GetZipLength(work, src, ZipCompressionLevelV2.None); + long best = TestZipV2.GetZipLength(work, src, ZipCompressionLevelV2.BestCompression); + + MyDebug.OutputDebugAndConsole( + "無圧縮より BestCompression の方が小さい : " + (best < none)); + + #endregion + } + finally { TestZipV2.DeleteWorkDir(work); } + } + + #endregion + + #region ヘルパ + + /// <summary>拡張子で選択する</summary> + /// <param name="o">FileInfo</param> + /// <param name="info">除く拡張子</param> + /// <returns>圧縮するか</returns> + private static bool SelectByExtension(object o, object info) + { + FileInfo f = o as FileInfo; + if (f == null) { return true; } + + return !string.Equals(f.Extension, (string)info, StringComparison.OrdinalIgnoreCase); + } + + /// <summary>暗号化の結果を出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="cyp">暗号化</param> + /// <param name="passOnZip">圧縮時のパスワード</param> + /// <param name="passOnUnZip">解凍時のパスワード</param> + private static void OutputEncryption( + string caseName, + ZipEncryptionAlgorithmV2 cyp, + string passOnZip, + string passOnUnZip) + { + string work = TestZipV2.CreateWorkDir(); + + try + { + string src = TestZipV2.CreateSampleTree(work); + string dst = Path.Combine(work, "out"); + + ZipperV2 z = new ZipperV2(); + z.CreateZipFromFolder( + Path.Combine(work, "archive"), src, + null, null, "", null, cyp, passOnZip, + ZipCompressionLevelV2.Default); + + UnZipperV2 uz = new UnZipperV2(); + uz.ExtractFileFromZip( + Path.Combine(work, "archive.zip"), dst, + null, null, + ExtractExistingFileActionV2.OverwriteSilently, null, passOnUnZip); + + MyDebug.OutputDebugAndConsole( + "[" + caseName + "] 往復して一致 : " + TestZipV2.AreSameTree(src, dst)); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole("[" + caseName + "] 例外 " + ex.GetType().FullName); + } + finally { TestZipV2.DeleteWorkDir(work); } + } + + /// <summary>指定の圧縮レベルで圧縮し、サイズを返す</summary> + /// <param name="work">作業フォルダ</param> + /// <param name="src">圧縮対象</param> + /// <param name="cmpLv">圧縮レベル</param> + /// <returns>書庫のバイト数</returns> + private static long GetZipLength(string work, string src, ZipCompressionLevelV2 cmpLv) + { + string name = Path.Combine(work, "lv" + ((int)cmpLv).ToString()); + + ZipperV2 z = new ZipperV2(); + z.CreateZipFromFolder( + name, src, null, null, "", null, + ZipEncryptionAlgorithmV2.None, null, cmpLv); + + return new FileInfo(name + ".zip").Length; + } + + /// <summary>作業フォルダを作る</summary> + /// <returns>作業フォルダ</returns> + private static string CreateWorkDir() + { + string work = Path.Combine(Path.GetTempPath(), "OpenTouryoZipV2_" + Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(work); + return work; + } + + /// <summary>作業フォルダを消す</summary> + /// <param name="work">作業フォルダ</param> + private static void DeleteWorkDir(string work) + { + try { Directory.Delete(work, true); } + catch { /* 後始末なので握り潰す。 */ } + } + + /// <summary>圧縮対象のフォルダを作る</summary> + /// <param name="work">作業フォルダ</param> + /// <returns>圧縮対象フォルダ</returns> + /// <remarks> + /// 階層・日本語のファイル名・空でない複数ファイルを含める。 + /// **内容は固定**(実行のたびに変わってはならない)。 + /// </remarks> + private static string CreateSampleTree(string work) + { + string src = Path.Combine(work, "src"); + Directory.CreateDirectory(src); + Directory.CreateDirectory(Path.Combine(src, "sub")); + + // 圧縮が効くように、同じ内容を繰り返す。 + string body = string.Empty; + for (int i = 0; i < 200; i++) { body += "あいうえお ABCDE 12345\r\n"; } + + File.WriteAllText(Path.Combine(src, "a.txt"), body, Encoding.UTF8); + File.WriteAllText(Path.Combine(src, "b.log"), body, Encoding.UTF8); + File.WriteAllText(Path.Combine(src, "日本語.txt"), body, Encoding.UTF8); + File.WriteAllText(Path.Combine(src, "sub", "c.txt"), body, Encoding.UTF8); + + return src; + } + + /// <summary>解凍したパスを、比較できる形にして並べ替える</summary> + /// <param name="paths">解凍したパス</param> + /// <param name="root">基準フォルダ</param> + /// <returns>並べ替えた相対パス</returns> + /// <remarks> + /// **絶対パスは出力しない**(環境依存になるため)。 + /// 列挙の順序はファイル システム依存なので、**必ず並べ替える。** + /// </remarks> + private static string[] ToRelativeSorted(string[] paths, string root) + { + List<string> list = new List<string>(); + + foreach (string p in paths) + { + string r = p.Substring(root.Length).Replace('\\', '/').TrimStart('/'); + list.Add(r); + } + + list.Sort(StringComparer.Ordinal); + return list.ToArray(); + } + + /// <summary>2 つのフォルダの内容が同じか</summary> + /// <param name="dir1">フォルダ1</param> + /// <param name="dir2">フォルダ2</param> + /// <returns>同じならtrue</returns> + private static bool AreSameTree(string dir1, string dir2) + { + if (!Directory.Exists(dir1) || !Directory.Exists(dir2)) { return false; } + + Dictionary<string, string> m1 = TestZipV2.ReadAll(dir1); + Dictionary<string, string> m2 = TestZipV2.ReadAll(dir2); + + if (m1.Count != m2.Count) { return false; } + + foreach (KeyValuePair<string, string> kv in m1) + { + if (!m2.ContainsKey(kv.Key)) { return false; } + if (m2[kv.Key] != kv.Value) { return false; } + } + + return true; + } + + /// <summary>フォルダ以下を「相対パス → 内容」で読む</summary> + /// <param name="dir">フォルダ</param> + /// <returns>相対パスと内容</returns> + private static Dictionary<string, string> ReadAll(string dir) + { + Dictionary<string, string> map = new Dictionary<string, string>(); + string root = Path.GetFullPath(dir); + + foreach (string p in Directory.GetFiles(root, "*", SearchOption.AllDirectories)) + { + string r = Path.GetFullPath(p).Substring(root.Length) + .Replace('\\', '/').TrimStart('/'); + + map[r] = File.ReadAllText(p, Encoding.UTF8); + } + + return map; + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestCode/appsettings.json b/root/programs/CS/Frameworks/Tests/TestCode/appsettings.json index b2c8044b1..db08d90ce 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/appsettings.json +++ b/root/programs/CS/Frameworks/Tests/TestCode/appsettings.json @@ -7,6 +7,11 @@ // 埋め込まれたリソースの場合 // "FxXMLMSGDefinition": "TestCodeCore.MSGDefinition.xml", // "FxXMLSPDefinition": "TestCodeCore.SPDefinition.xml", + // メッセージの言語を固定する + // GetMessage は、指定が無ければ CurrentUICulture から MSGDefinition_xx.xml を選ぶ。 + // 期待結果は日本語で記録されているため、実行環境の表示言語に依存しないよう固定する。 + // (英語環境では既定の MSGDefinition.xml=英語版に落ち、例外にならないので気付きにくい) + "FxBusinessMessageCulture": "ja-JP", // Log4Netのコンフィグファイルへのパス // リソース ファイルの場合 "FxLog4NetConfFile": "SampleLogConf.xml" diff --git a/root/programs/CS/Frameworks/Tests/TestCode/core100/TestCodeCore.csproj b/root/programs/CS/Frameworks/Tests/TestCode/core100/TestCodeCore.csproj index 4aae226a3..51f06a115 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/core100/TestCodeCore.csproj +++ b/root/programs/CS/Frameworks/Tests/TestCode/core100/TestCodeCore.csproj @@ -14,15 +14,24 @@ <Compile Include="..\Program.cs" Link="Program.cs" /> <Compile Include="..\TestCustomEncode.cs" Link="TestCustomEncode.cs" /> <Compile Include="..\TestDeflateCompression.cs" Link="TestDeflateCompression.cs" /> + <Compile Include="..\TestDto.cs" Link="TestDto.cs" /> <Compile Include="..\TestEnumToStringExtensions.cs" Link="TestEnumToStringExtensions.cs" /> + <Compile Include="..\TestFastReflection.cs" Link="TestFastReflection.cs" /> <Compile Include="..\TestFormatChecker.cs" Link="TestFormatChecker.cs" /> <Compile Include="..\TestFormatConverter.cs" Link="TestFormatConverter.cs" /> <Compile Include="..\TestGetMessageAndProperty.cs" Link="TestGetMessageAndProperty.cs" /> <Compile Include="..\TestJISCode.cs" Link="TestJISCode.cs" /> + <Compile Include="..\TestLatebind.cs" Link="TestLatebind.cs" /> + <Compile Include="..\TestResourceLoader.cs" Link="TestResourceLoader.cs" /> + <Compile Include="..\TestObjectInspector.cs" Link="TestObjectInspector.cs" /> <Compile Include="..\TestOutputLog.cs" Link="TestOutputLog.cs" /> <Compile Include="..\TestStringChecker.cs" Link="TestStringChecker.cs" /> <Compile Include="..\TestStringConverter.cs" Link="TestStringConverter.cs" /> + <Compile Include="..\TestStringExtractor.cs" Link="TestStringExtractor.cs" /> + <Compile Include="..\TestStringVariableOperator.cs" Link="TestStringVariableOperator.cs" /> + <Compile Include="..\TestUtil.cs" Link="TestUtil.cs" /> <Compile Include="..\TestXmlLib.cs" Link="TestXmlLib.cs" /> + <Compile Include="..\TestZipV2.cs" Link="TestZipV2.cs" /> </ItemGroup> <ItemGroup> @@ -31,6 +40,12 @@ </Content> </ItemGroup> + <ItemGroup> + <!--LogicalName を明示する。既定のままだと「既定の名前空間 + ファイル名」になり、 + net48(TestCodeFx)と .NET (Core)(TestCodeCore)で名前が食い違うため。--> + <EmbeddedResource Include="..\TestEmbedded.txt" LogicalName="TestCode.TestEmbedded.txt" /> + </ItemGroup> + <ItemGroup> <None Include="..\appsettings.json" Link="appsettings.json"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> @@ -38,10 +53,13 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="log4net" Version="3.1.0" /> + <PackageReference Include="log4net" Version="3.3.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="9.0.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.6" /> + <!--フレームワークは HintPath で参照しており、NuGet の推移的依存が効かない。 + OpenTouryo.Public が使うパッケージは、ここにも並べる必要がある。--> + <PackageReference Include="SharpZipLib" Version="1.4.2" /> <PackageReference Include="Zipangu" Version="1.1.8" /> </ItemGroup> diff --git a/root/programs/CS/Frameworks/Tests/TestCode/net48/TestCodeFx.csproj b/root/programs/CS/Frameworks/Tests/TestCode/net48/TestCodeFx.csproj index 2f17a61cd..0c96a9d4e 100644 --- a/root/programs/CS/Frameworks/Tests/TestCode/net48/TestCodeFx.csproj +++ b/root/programs/CS/Frameworks/Tests/TestCode/net48/TestCodeFx.csproj @@ -68,9 +68,15 @@ <Compile Include="..\TestDeflateCompression.cs"> <Link>TestDeflateCompression.cs</Link> </Compile> + <Compile Include="..\TestDto.cs"> + <Link>TestDto.cs</Link> + </Compile> <Compile Include="..\TestEnumToStringExtensions.cs"> <Link>TestEnumToStringExtensions.cs</Link> </Compile> + <Compile Include="..\TestFastReflection.cs"> + <Link>TestFastReflection.cs</Link> + </Compile> <Compile Include="..\TestFormatChecker.cs"> <Link>TestFormatChecker.cs</Link> </Compile> @@ -83,6 +89,15 @@ <Compile Include="..\TestJISCode.cs"> <Link>TestJISCode.cs</Link> </Compile> + <Compile Include="..\TestLatebind.cs"> + <Link>TestLatebind.cs</Link> + </Compile> + <Compile Include="..\TestResourceLoader.cs"> + <Link>TestResourceLoader.cs</Link> + </Compile> + <Compile Include="..\TestObjectInspector.cs"> + <Link>TestObjectInspector.cs</Link> + </Compile> <Compile Include="..\TestOutputLog.cs"> <Link>TestOutputLog.cs</Link> </Compile> @@ -92,9 +107,21 @@ <Compile Include="..\TestStringConverter.cs"> <Link>TestStringConverter.cs</Link> </Compile> + <Compile Include="..\TestStringExtractor.cs"> + <Link>TestStringExtractor.cs</Link> + </Compile> + <Compile Include="..\TestStringVariableOperator.cs"> + <Link>TestStringVariableOperator.cs</Link> + </Compile> + <Compile Include="..\TestUtil.cs"> + <Link>TestUtil.cs</Link> + </Compile> <Compile Include="..\TestXmlLib.cs"> <Link>TestXmlLib.cs</Link> </Compile> + <Compile Include="..\TestZipV2.cs"> + <Link>TestZipV2.cs</Link> + </Compile> </ItemGroup> <ItemGroup> <Content Include="..\SampleLogConf.xml"> @@ -102,6 +129,14 @@ <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup> + <ItemGroup> + <!--LogicalName を明示する。既定のままだと「既定の名前空間 + ファイル名」になり、 + net48(TestCodeFx)と .NET (Core)(TestCodeCore)で名前が食い違うため。--> + <EmbeddedResource Include="..\TestEmbedded.txt"> + <Link>TestEmbedded.txt</Link> + <LogicalName>TestCode.TestEmbedded.txt</LogicalName> + </EmbeddedResource> + </ItemGroup> <ItemGroup> <PackageReference Include="OssCons.DotNetSubcommittee.TestClassLibrary1"> <Version>0.1.1</Version> diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/App.config b/root/programs/CS/Frameworks/Tests/TestDataAccess/App.config new file mode 100644 index 000000000..73ee6e55e --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/App.config @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <connectionStrings> + <!--SQL Server(CI でも使う。ここだけは必ず接続できること)--> + <add name="ConnectionString_SQL" connectionString="Data Source=localhost;Initial Catalog=Northwind;User ID=sa;Password=seigi@123;Encrypt=false;" /> + <!--OLEDB--> + <add name="ConnectionString_OLE" connectionString="Provider=SQLOLEDB;Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;" /> + <!--ODBC--> + <add name="ConnectionString_ODBC" connectionString="Dsn=odbc_test1" /> + <!--Oracle(ODP.NET)--> + <add name="ConnectionString_ODP" connectionString="User Id=SCOTT;Password=tiger;Data Source=localhost/XE;" /> + <!--MySQL(Connector/NET)--> + <add name="ConnectionString_MCN" connectionString="Server=localhost;Database=test;User Id=root;Password=seigi@123" /> + <!--PostgreSQL(Npgsql)は DamPstGrS が .NET (Core) 専用のため、net48 では使わない--> + </connectionStrings> + <appSettings> + <!--リソース ファイルの場合--> + <add key="FxXMLMSGDefinition" value="C:\root\files\resource\Xml\MSGDefinition.xml" /> + <add key="FxXMLSPDefinition" value="C:\root\files\resource\Xml\SPDefinition.xml" /> + + <!--メッセージの言語を固定する--> + <!--GetMessage は、指定が無ければ CurrentUICulture から MSGDefinition_xx.xml を選ぶ。 + 期待結果は日本語で記録されているため、実行環境の表示言語に依存しないよう固定する。 + (英語環境では既定の MSGDefinition.xml=英語版に落ち、例外にならないので気付きにくい)--> + <add key="FxBusinessMessageCulture" value="ja-JP" /> + + <!--静的SQL・動的SQLの格納フォルダ--> + <add key="SqlTextFilePath" value="C:\root\files\resource\Sql" /> + + <!-- Log4Netのコンフィグファイルへのパス --> + <add key="FxLog4NetConfFile" value="SampleLogConf.xml" /> + </appSettings> +</configuration> diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/AssemblyInfo.cs b/root/programs/CS/Frameworks/Tests/TestDataAccess/AssemblyInfo.cs new file mode 100644 index 000000000..3a01633c2 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/AssemblyInfo.cs @@ -0,0 +1,45 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :AssemblyInfo +//* クラス日本語名 :アセンブリ情報 +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/05 玄人 幸道 新規作成(#520) +//********************************************************************************** + +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("TestDataAccess")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestDataAccess")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] +[assembly: Guid("7285aed0-058a-4c30-a3e5-83bf430aef47")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/DataProvider.cs b/root/programs/CS/Frameworks/Tests/TestDataAccess/DataProvider.cs new file mode 100644 index 000000000..302296d4d --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/DataProvider.cs @@ -0,0 +1,151 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :DataProvider +//* クラス日本語名 :データ プロバイダごとの差異の吸収 +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#520) +//********************************************************************************** + +using Touryo.Infrastructure.Public.Db; +using Touryo.Infrastructure.Public.Util; + +namespace TestDataAccess +{ + /// <summary>データ プロバイダごとの差異を吸収する</summary> + /// <remarks> + /// 識別子(dap)は MyBaseLogic の ActionType 先頭と同じ文字列を使う。 + /// SQL … SQL Server / ODP … Oracle / MCN … MySQL / NPS … PostgreSQL + /// テスト クラスから共通に使うため、ここに集約する。 + /// </remarks> + public class DataProvider + { + /// <summary>データ プロバイダに対応する Dam を生成する</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <returns>BaseDam(未対応の場合は null)</returns> + /// <remarks> + /// 対応関係は MyBaseLogic のデータ プロバイダ選択に合わせている。 + /// PostgreSQL(NPS)は DamPstGrS が .NET (Core) 専用のため、net48 では生成しない。 + /// </remarks> + public static BaseDam CreateDam(string dap) + { + switch (dap) + { + case "SQL": + return new DamSqlSvr(); + + case "ODP": + return new DamManagedOdp(); + + case "MCN": + return new DamMySQL(); + +#if NET48 +#else + case "NPS": + return new DamPstGrS(); +#endif + + default: + return null; + } + } + + /// <summary>データ プロバイダに対応する接続文字列</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <returns>接続文字列</returns> + public static string GetConnectionString(string dap) + { + return GetConfigParameter.GetConnectionString("ConnectionString_" + dap); + } + + /// <summary>データ プロバイダに対応する DBMS の種類</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <returns>DBMSType(SQLUtility に渡す)</returns> + public static DbEnum.DBMSType GetDbmsType(string dap) + { + switch (dap) + { + case "ODP": + return DbEnum.DBMSType.Oracle; + + case "MCN": + return DbEnum.DBMSType.MySQL; + + case "NPS": + return DbEnum.DBMSType.PstGrS; + + default: + return DbEnum.DBMSType.SQLServer; + } + } + + /// <summary>識別子を囲う</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <param name="name">識別子</param> + /// <returns>囲った識別子</returns> + /// <remarks> + /// **SQLUtility が生成する囲い文字と必ず一致させること。** + /// Oracle は囲わないと大文字、PostgreSQL は囲わないと小文字に畳まれるため、 + /// 表を作るときも同じ囲い方をしないと、生成された SQL から列が見えなくなる。 + /// </remarks> + public static string Quote(string dap, string name) + { + switch (dap) + { + case "SQL": + return "[" + name + "]"; + + case "MCN": + return "`" + name + "`"; + + default: + // Oracle・PostgreSQL は二重引用符 + return "\"" + name + "\""; + } + } + + /// <summary>データ プロバイダに対応する SQL の格納フォルダ</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <returns>root/files/resource/Sql からの相対フォルダ名</returns> + public static string GetSqlFolder(string dap) + { + switch (dap) + { + case "SQL": + return "sqlserver"; + + case "ODP": + return "oracle"; + + case "MCN": + return "mysql"; + + case "NPS": + return "pstgrs"; + + default: + return ""; + } + } + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/ExecLocalTest.bat b/root/programs/CS/Frameworks/Tests/TestDataAccess/ExecLocalTest.bat new file mode 100644 index 000000000..0f5dfb63c --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/ExecLocalTest.bat @@ -0,0 +1,58 @@ +setlocal + +@rem -------------------------------------------------- +@rem Turn off the echo function. +@rem -------------------------------------------------- +@echo off + +@rem -------------------------------------------------- +@rem Cross DB test (for local execution only). +@rem +@rem Start the containers of LocalServicesOnDocker first. +@rem This can not run on the CI because each DBMS runs on a Linux container. +@rem See root\programs\TESTING.md for the details. +@rem -------------------------------------------------- + +@rem -------------------------------------------------- +@rem Get the path to the executable file. +@rem -------------------------------------------------- +set CURRENT_DIR=%~dp0 +cd /d "%CURRENT_DIR%" + +@rem -------------------------------------------------- +@rem About the output files. +@rem +@rem Write to ResultLocal*.txt, never to Result*.txt. +@rem Result*.txt are the expected values of 2_RunAllTests.ps1, +@rem which are recorded with /MODE SQLONLY. +@rem The output of /MODE LOCAL varies with the running DBMS, +@rem so overwriting them breaks the expected values. +@rem -------------------------------------------------- + +@rem -------------------------------------------------- +@rem About "echo. |". +@rem +@rem Program.cs calls Console.ReadKey() at the end. +@rem Without redirecting the stdin, it really waits for a key press. +@rem -------------------------------------------------- + +@echo -------------------------------------------------- +@echo net48 : SQL Server / Oracle / MySQL +@echo -------------------------------------------------- +echo. | "net48\bin\Debug\TestDataAccessFx.exe" /MODE LOCAL > "%CURRENT_DIR%ResultLocal48.txt" + +@echo -------------------------------------------------- +@echo net10.0 : SQL Server / Oracle / MySQL / PostgreSQL +@echo -------------------------------------------------- +cd /d "%CURRENT_DIR%core100\bin\Debug\net10.0" +echo. | dotnet "TestDataAccessCore.dll" -- /MODE LOCAL > "%CURRENT_DIR%ResultLocalCore100.txt" +cd /d "%CURRENT_DIR%" + +@echo -------------------------------------------------- +@echo Output : ResultLocal48.txt / ResultLocalCore100.txt +@echo -------------------------------------------------- + +pause + +rem ------------------------------------------------------- +endlocal \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/Program.cs b/root/programs/CS/Frameworks/Tests/TestDataAccess/Program.cs new file mode 100644 index 000000000..e98c9a73e --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/Program.cs @@ -0,0 +1,181 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :Program +//* クラス日本語名 :データ アクセスのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/05 玄人 幸道 新規作成(#520) +//********************************************************************************** + +using System; +using System.Collections.Generic; +using System.Text; + +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.Str; +using Touryo.Infrastructure.Public.Util; + +namespace TestDataAccess +{ + /// <summary>Program</summary> + /// <remarks> + /// データ アクセスのパターンを、複数の DBMS に対して確認する(#520)。 + /// + /// <なぜ TestCode と分けるか> + /// **このプロジェクトは DB を前提にする。** TestCode は前提にしない。 + /// 混ぜると「DB が無い環境では TestCode ごと動かない」ことになる。 + /// + /// ※ ただし**個々のテストが全て接続するわけではない。** + ///   SQL を組み立てるだけのものは接続を必要としない(下の region を参照)。 + /// + /// <実行モード> + /// クロス DB は GitHub Actions では実行できない(Docker の各 DB が Linux + /// コンテナで、windows-latest は Linux コンテナを動かせないため)。 + /// このため、対象を切り替えられるようにしてある。 + /// + /// <詳細> + /// 何をなぜそう確認するかは、同じフォルダの README.md が一次情報。 + /// </remarks> + public class Program + { + #region 定数 + + /// <summary>SQL Server だけを対象にする(既定)</summary> + /// <remarks>CI(GitHub Actions)はこちら。</remarks> + public const string ModeSqlOnly = "SQLONLY"; + + /// <summary>ローカルで起動している DBMS をすべて対象にする</summary> + /// <remarks>LocalServicesOnDocker の各コンテナを起動しておくこと。</remarks> + public const string ModeLocal = "LOCAL"; + + #endregion + + /// <summary>Main</summary> + /// <param name="args">string[]</param> + public static void Main(string[] args) + { + // configの初期化(無くても動くようにせねば。) +#if NETCOREAPP + GetConfigParameter.InitConfiguration("appsettings.json"); + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); +#endif + + try + { + string mode = Program.GetMode(); + string[] daps = Program.GetDataProviders(mode); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + MyDebug.OutputDebugAndConsole("実行モード : " + mode); + MyDebug.OutputDebugAndConsole("対象データプロバイダ : " + string.Join(", ", daps)); + + // 分かれ目は「接続するか」ではなく「実行するか、組み立てだけか」。 + // TestDataAccessDpq は中で両方を行うため、クラス単位でも分けられない。 + + #region SQLを組み立てるだけ(接続しない) + // 実行モードによらず、対象データプロバイダにもよらず、常に 4 DBMS 分を行う。 + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestSQLUtility.Root(); + #endregion + + #region 実行して結果を見る(接続する) + // ※ TestDataAccessDpq は、末尾で ExecGenerateSQL による + //   「組み立てるだけ」の確認も行う(そこは接続を必要としない)。 + TestDataAccessPattern.Root(daps); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + MyDebug.OutputDebugAndConsole("更新系(専用の表を作って落とす)"); + TestDataAccessUpdate.Root(daps); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + MyDebug.OutputDebugAndConsole("動的パラメタライズドクエリ"); + TestDataAccessDpq.Root(daps); + #endregion + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + // echoすると例外 + try + { + Console.ReadKey(); + } + catch { } + } + catch (Exception ex) + { + MyDebug.OutputDebugAndConsole(ex.ToString()); + } + } + + #region private + + /// <summary>コマンドラインから実行モードを取得する</summary> + /// <returns>ModeSqlOnly または ModeLocal</returns> + /// <remarks> + /// 指定が無い場合は ModeSqlOnly。 + /// 結果ファイル(Result*.txt)は、この既定で実行したものを期待値としている。 + /// </remarks> + private static string GetMode() + { + List<string> valsLst = null; + Dictionary<string, string> argsDic = null; + + // コマンドラインをバラす関数がある。 + StringVariableOperator.GetCommandArgs('/', out argsDic, out valsLst); + + if (argsDic != null && argsDic.ContainsKey("/MODE")) + { + string mode = argsDic["/MODE"].ToUpper(); + + if (mode == Program.ModeLocal) + { + return Program.ModeLocal; + } + } + + return Program.ModeSqlOnly; + } + + /// <summary>実行モードから、対象のデータ プロバイダを決める</summary> + /// <param name="mode">実行モード</param> + /// <returns>データ プロバイダの識別子(MyBaseLogic の ActionType 先頭と同じ)</returns> + /// <remarks> + /// net48 と .NET (Core) で使えるものが異なる。 + /// PostgreSQL(NPS)は DamPstGrS が .NET (Core) 専用のため、net48 では対象外。 + /// </remarks> + private static string[] GetDataProviders(string mode) + { + if (mode == Program.ModeLocal) + { +#if NET48 + return new string[] { "SQL", "ODP", "MCN" }; +#else + return new string[] { "SQL", "ODP", "MCN", "NPS" }; +#endif + } + + return new string[] { "SQL" }; + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/README.md b/root/programs/CS/Frameworks/Tests/TestDataAccess/README.md new file mode 100644 index 000000000..15f6e9de5 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/README.md @@ -0,0 +1,399 @@ +# TestDataAccess — データ アクセスのテスト + +`Dam` を通したデータ アクセスを、**複数の DBMS に対して**確認する(#520)。 + +| | | +|---|---| +| 実行と判定 | [`root/programs/TESTING.md`](../../../../TESTING.md)(`2_RunAllTests.ps1` が回す) | +| CI での前提の揃え方 | [`root/programs/BUILDING.md`](../../../../BUILDING.md) 9 節 | +| SQL 定義ファイルの書式 | `opentouryo-query-definition` スキル | + +**本書は、このプロジェクトが何をどう確認しているかを述べる。** +`TESTING.md` は 8 ケース全体の運用を扱い、こちらの詳細は持たない。 + +--- + +## 実行モード(`/MODE`) + +**クロス DB は CI では実行できない。** LocalServicesOnDocker の各 DBMS は Linux コンテナで、 +`windows-latest` は Linux コンテナを動かせないため([`BUILDING.md`](BUILDING.md) 9 節)。 +このため対象を切り替えられるようにしてある。 + +``` +TestDataAccessFx.exe /MODE SQLONLY … SQL Server だけ(既定。CI はこちら) +TestDataAccessFx.exe /MODE LOCAL … ローカルで起動している DBMS をすべて +``` + +**期待値(`Result*.txt`)は `SQLONLY` で記録している。** `y_Build_TestCode_DataAccess.bat` も +`SQLONLY` を明示して呼ぶ。`LOCAL` は手元での確認用で、比較の対象にはしない。 + +> `LOCAL` の対象は net48 と .NET (Core) で異なる。 +> **PostgreSQL(`NPS`)は `DamPstGrS` が .NET (Core) 専用**のため、net48 では対象外。 + +`TestCode` と分けているのは、**このプロジェクトが DB を前提にする**ため。 +混ぜると、DB が無い環境では `TestCode` ごと動かなくなる。 + +> **ただし、個々のテストが全て接続するわけではない。** +> SQL を組み立てるだけのものは接続を必要としない(次節)。 + +## 何をテストしているか + +**分かれ目は「接続するか」ではなく「実行するか、組み立てだけか」。** +クラス単位でもない。`TestDataAccessDpq` は中で両方を行う。 + +| クラス/観点 | 見るもの | DB | +|---|---|---| +| `TestSQLUtility` | `SQLUtility` が生成する SQL を **4 DBMS 分**(#515) | **要らない** | +| `TestDataAccessPattern` | `Dam` の実行系メソッドを一通り | 要る | +| `TestDataAccessUpdate` | 更新系(INSERT / UPDATE / DELETE)とトランザクション | 要る | +| `TestDataAccessDpq` 1〜5 | 動的 SQL の組み立て結果を**件数**で | 要る | +| `TestDataAccessDpq` 6 | 動的 SQL の**組み立て結果そのもの**(`ExecGenerateSQL`) | **要らない** | +| `DataProvider` | データ プロバイダごとの差異(Dam・囲い文字・パラメタ記号)を吸収 | — | +| `TestTable` | テスト用の表 `TestOrders` の作成・投入・破棄 | — | + +> **`ExecGenerateSQL` は接続を使わない。** +> 他の `Exec*` と違って `_cmd.Connection` を設定せず、`PreExecQuery` も +> `CommandText` とパラメタしか触らない。 +> **実装の都合で接続下から呼んでいるだけ**で、機能としては接続を必要としない。 + +### `TestSQLUtility` と `TestDataAccessUpdate` の役割分担 + +**重なっているのは「複合主キーの INSERT / UPDATE」だけ。** 残りは片方でしか見られない。 + +| 観点 | `TestSQLUtility` | `TestDataAccessUpdate` | +|---|---|---| +| 単一主キー | ○ | × | +| 複合主キー | ○ | ○(**重複**) | +| **生成しないこと**(更新対象列なし・主キーなし) | **○** | **×** | +| 生成された SQL テキストそのもの | ○ | × | +| 正しい行に正しい値が入るか | × | ○ | +| **CI での 4 DBMS 分の生成** | **○** | ×(CI は SQL Server のみ) | + +**「生成しないこと」は実行では確かめられない。** 生成物が無いので実行しようがない。 +これは #515 で追加したガード(`colSet.Count == 0 \|\| colWhere.Count == 0` の早期 return)の +回帰テストで、**外すと "SE" や "WH" のような壊れた文字列を返す退行を検知できなくなる。** + +**CI で 4 DBMS 分を見られるのも `TestSQLUtility` だけ。** CI は SQL Server にしか接続しない。 +**#515 は PostgreSQL / MySQL の不具合**だったので、ここが CI での唯一の防波堤になる。 + +`TestDataAccessPattern` が呼ぶのは次の 5 つ。いずれも `Shippers`(3 件)に対する読み取りで、 +**件数だけを出力する**ため、DBMS が違っても結果は同じになる。 + +``` +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 ← 静的SQL(DBMS ごとのフォルダから読む) +``` + +**`Dam` を直接使っている。** B層・D層を経由すると引数クラス・戻り値クラス・ +`LayerB` / `LayerD` の一式が要るが、ここで見たいのは実行系の挙動だから。 +B層・D層を通した確認は `TestBatch`(SimpleBatch)が担う。 + +### 更新系(`TestDataAccessUpdate`) + +**専用の表 `TestOrders` を自分で作り、最後に落とす。** Northwind の表を更新すると +`SimpleBatch` や `3_SmokeTest.ps1` の前提が壊れるため、**既存のデータには一切触れない。** + +``` +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z ← 更新対象外。無傷であること +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +``` + +**`SQLUtility` が生成した SQL を実際に実行し、結果まで検証する。** +#515 は「構文としては妥当でも、**誤った行に誤った値が入る**」不具合だった。 +生成結果の目視では見つけにくいため、**更新対象外の行 (3,30) を 1 件混ぜ、 +無傷であることまで確認する。** ここが崩れたら複合主キーの扱いが壊れている。 + +> PostgreSQL と MySQL は `CASE ... WHEN ... THEN` による一括 UPDATE という別実装。 +> #515 の該当パスであり、実 DB での確認はこの 2 つで特に意味がある。 + +#### 表を作るときの注意 + +**囲い文字を `SQLUtility` が生成するものと一致させること。** + +| DBMS | 囲い文字 | 囲わないと | +|---|---|---| +| SQL Server | `[ ]` | (既定の照合順序では問題にならない) | +| Oracle | `" "` | **大文字**に畳まれる | +| PostgreSQL | `" "` | **小文字**に畳まれる | +| MySQL | `` ` `` | (列名は大小同一視) | + +Oracle と PostgreSQL は、囲わずに表を作ると生成された SQL の `"Qty"` が +**「存在しない列」**になる。`DataProvider.Quote` に集約してある。 + +> `DROP TABLE IF EXISTS` は Oracle では 23ai 以降でしか使えないため、 +> 分岐せずに「投げて握る」形にしている。 +> DDL は Oracle では暗黙にコミットされるため、トランザクションの外で行う。 + +> **接続できない場合も落とさない。** `LOCAL` でコンテナが起動していないときは、 +> 例外の**型名だけ**を出して次のデータ プロバイダへ進む。 +> メッセージを出さないのは、OS の表示言語で変わり差分になるため(`BUILDING.md` 9 節)。 +> +> ``` +> [ODP] +> - 例外 : Oracle.ManagedDataAccess.Client.OracleException +> ``` + + +### 動的パラメタライズドクエリ(`TestDataAccessDpq`) + +**同じ 1 本の XML から、パラメタの与え方だけで異なる SQL が組み立つ**ことを見る。 +仕様は `opentouryo-query-definition` スキルが一次情報。 + +#### 6 つの観点 + +| # | 観点 | 見るもの | +|---|---|---| +| 1 | `<WHERE>` / `<IF>` の組み合わせ | 条件の増減と、先頭 `AND` の除去 | +| 2 | **`<IF>` / `<ELSE>`** | **「未設定」と「`null` を設定」は別物**。テキスト内・タグ内の両方 | +| 3 | `<LIST>` | IN 句への自動展開 | +| 4 | パラメタの作用範囲 | テキスト内は全タグ、タグ内は最初の 1 タグ | +| 5 | `<DELCMA>` / `<INSCOL>` | 要素が消えたときのカンマ処理 | +| 6 | 組み立て結果そのもの | `ExecGenerateSQL`(実行しない) | + +**1〜5 は件数で見る。** DBMS ごとに型や表示が変わるため、値を出すと差分になる。 +**6 は組み立て結果を見る。** 分岐やエスケープは実行しなくても分かり、表の中身にも依存しない。 + +#### 1. `<WHERE>` / `<IF>` の組み合わせ + +`<IF>` が 2 つなので、設定/未設定の組み合わせは **2 の 2 乗 = 4 通り**。 +**全数を通したうえで**、AND であることを判別する 1 件を足している。 + +| ケース | P1 | P2 | 結果 | 検証対象 | +|---|---|---|---|---| +| 両方指定 | ○ | ○ | 1 件 | 両方が入る(正の確認) | +| **両方指定(不一致)** | ○ | ○ | **0 件** | **AND であること** | +| OrderIDのみ | ○ | × | 1 件 | **末尾**の `<IF>` が落ちる | +| Qtyのみ | × | ○ | 1 件 | **先頭**が落ちたとき `AND` が除去される | +| 指定なし | × | × | 4 件 | `<WHERE>` ごと消える | + +**「Qtyのみ」が最も壊れやすい箇所を見ている。** +2 番目以降の `<IF>` は**テキストの先頭に `AND` を書く**規約なので、 +1 番目が落ちたときに除去されないと `WHERE AND ...` となって構文エラーになる。 + +**「両方指定(不一致)」は判別のために足した。** +`P1=1`(1 行目)と `P2=888`(2 行目)で**指す行をずらしてある**。 + +| 実装が実際には… | 結果 | +|---|---| +| AND で連結(正しい) | **0 件** | +| OR で連結(誤り) | 2 件 | +| 片方を無視(誤り) | 1 件 | + +3 者が異なる件数になるため、1 ケースで判別できる。 +**「両方指定」だけでは、どれでも 1 件になり判別できない。** + +#### 2. `<IF>` / `<ELSE>`(テキスト内・タグ内の両方) + +**パラメタの種類で、状態の数が違う。両方を通す。** + +```xml +<IF>AND "Note" = @P3<ELSE>AND "Note" IS NULL</ELSE></IF> ← テキスト内 +<IF name="F1">AND "Note" = 'x'<ELSE>AND "Note" IS NULL</ELSE></IF> ← タグ内 +``` + +| | 有効(`<IF>`) | `<ELSE>` | ブロック削除 | 状態数 | +|---|---|---|---|---| +| テキスト内(`@P3`) | 値を設定 | **`null`** | 未設定 | 3 | +| タグ内(`name="F1"`) | `true` | **`false`** / `null` | 未設定 | **4** | + +**タグ内には `false` という状態が増える。** テキスト内に「偽」は無く、値か `null` か未設定しかない。 + +| ケース | 結果 | +|---|---| +| テキスト内 : 値 / `null` / 未設定 | 1 件 / 1 件 / 4 件 | +| タグ内 : `true` / `false` / `null` / 未設定 | 1 件 / 1 件 / 1 件 / 4 件 | + +> **条件から外したいときに `null` を渡してはならない。** +> 逆に `IS NULL` が残って外れない。外したいなら**設定しない**。 +> **実行時エラーにならず件数が静かに変わる**ので、気付きにくい。 + +このため、テスト用の表には **`Note` が NULL の行を 1 件**入れてある。 + +#### 3. `<LIST>`(IN 句) + +1 つのパラメタ名に複数値を与えると `@名_1, @名_2 …` へ自動展開される。 +**与えた数がそのまま件数に出る**ため、展開されたかを件数で判別できる(2 値 → 2 件、3 値 → 3 件)。 + +#### 4. パラメタの作用範囲 + +**同名を書いたときの作用範囲が違う。** + +| | 書き方 | 作用範囲 | +|---|---|---| +| テキスト内パラメタ | `<IF>AND X = @P1</IF>` | **同名を書いた全タグ** | +| タグ内パラメタ | `<IF name="F1">` | **最初の 1 タグだけ** | + +判別できるように、2 つの `<IF>` が**両立しない条件**にしてある。 + +| | 結果 | 意味 | +|---|---|---| +| テキスト内 | **0 件** | 両方に作用(`OrderID = 1` かつ `= 2`) | +| タグ内 | **1 件** | 最初だけ作用(`OrderID = 1`) | + +#### 5. `<DELCMA>` / `<INSCOL>` + +列と値を対で増減させ、**どの要素が残っても構文が壊れない**ことを実際に INSERT して確かめる。 +末尾を落とす場合と**先頭を落とす場合**の両方を通す(先頭側のカンマ除去が要るため)。 + +#### 6. 組み立て結果だけを見る(`ExecGenerateSQL`) + +| 対象 | 確認 | +|---|---| +| `<SELECT>` / `<CASE>` / `<DEFAULT>` | 値による分岐(`a1` / `b2` / 一致なし) | +| 比較演算子 | `<` と `<![CDATA[ ]]>` の両方が正しく組み立つ | +| **`<JOIN>` / `<SUB>`** | **結合・副問い合わせが丸ごと出入りする** | +| `IsDPQ` | `.xml`(タグあり)は `True`、`.sql` は `False` | + +``` +比較演算子 : SELECT [OrderID] FROM [TestOrders] WHERE [Qty] < 900 AND [Qty] > 100 + +JOIN+SUB あり : SELECT o.[OrderID] FROM [TestOrders] o + INNER JOIN [OtherTable] t ON o.[OrderID] = t.[OrderID] + WHERE o.[Qty] = 999 AND o.[OrderID] IN (SELECT [OrderID] FROM [OtherTable]) +JOIN のみ : ... INNER JOIN [OtherTable] t ON ... WHERE o.[Qty] = 999 +JOIN+SUB なし : SELECT o.[OrderID] FROM [TestOrders] o +``` + +> **実行しないので、存在しない表を書いてよい。** +> `<JOIN>` / `<SUB>` は結合や副問い合わせを扱うため +> 「表が 1 つでは組めない」と考えがちだが、**組み立てだけなら表の実在は要らない。** + +> **無効にするときは「設定しない」。** `false` や `null` を渡すと `<ELSE>` が要り、 +> 無ければエラーになる(`<JOIN>` / `<SUB>` は `true` / `false` / `null` 以外もエラー)。 + +> **`ExecGenerateSQL` を実装しているのは `DamSqlSvr` だけ。** +> 他は `NotImplementedException` を投げるため、「未実装」と出して先へ進める。 +> 組み立て結果は DBMS によらないので、SQL Server で見れば足りる。 + +#### 書くときに踏んだ落とし穴 + +| 事象 | 原因 | +|---|---| +| `<IF>` で `ArgumentException` | **パラメタも `name` 属性も無い `<IF>`**。有効・無効の判断材料が無い。CDATA 内のパラメタは認識される | +| 整形式でない `.xml` で例外 | 「書式が不正なら静的にフォールバック」は**タグの綴り等**の話。XML として壊れていれば例外 | + +#### パラメタの先頭記号は DBMS で異なる + +| DBMS | 記号 | +|---|---| +| Oracle(`ODP`) | **`:`** | +| SQL Server / MySQL / PostgreSQL | `@` | + +PostgreSQL は `:` から `@` に変更された経緯がある(`DamPstGrS.cs` の更新履歴)。 + +**XML は実行時に書き出して捨てる。** 記号と囲い文字が DBMS で異なるため、 +共有の SQL 置き場に置くと 4 方言ぶんの重複になる。表と同じ考え方。 + +#### 記法の参考 + +`root/files/resource/Test/dpq/query/` に `DPQuery_Tool` 用の資産がある +(`<SUB>` / `<JOIN>` を使った複雑な例も含む)。 + +> あちらの `<PARAM>` タグは**ツールが値を与えるためのもの**。 +> 実行時は `SetParameter` / `SetUserParameter` で与える。 + +#### 対象外 + +| 項目 | 理由 | +|---|---| +| パラメタの型・サイズ指定 | `SetParameter` の 3〜5 引数版 | +| Out / RetVal パラメタ、ストアド | 4 DBMS で書き方が大きく異なる | +| 埋め込みリソース | `MyBaseDao.UseEmbeddedResource`。配布形態の話 | +## クロス DB テストの実施手順(`LOCAL`) + +**① DBMS を起動する** + +各 DBMS は [LocalServicesOnDocker](https://github.com/NetDevInfraWGinOSSConsortium/LocalServicesOnDocker) +のコンテナで動かす。 + +```powershell +cd <LocalServicesOnDocker のパス> +.\Start-Services.ps1 +``` + +`test\dotnet\start.bat` で、各サービスへ接続できるかを先に確かめられる。 +**ここで NG のものは、こちらのテストでも当然 NG になる。** + +**② ビルドする** + +```powershell +cd root\programs\CS +cmd /c "echo. | call y_Build_TestCode_DataAccess.bat" +``` + +**③ `/MODE LOCAL` で実行する** + +```powershell +# net48(SQL Server / Oracle / MySQL) +cd root\programs\CS\Frameworks\Tests\TestDataAccess\net48\bin\Debug +.\TestDataAccessFx.exe /MODE LOCAL + +# .NET 10(+ PostgreSQL) +cd root\programs\CS\Frameworks\Tests\TestDataAccess\core100\bin\Debug\net10.0 +dotnet TestDataAccessCore.dll -- /MODE LOCAL +``` + +**`2_RunAllTests.ps1` からは実行できない。** バッチが `/MODE SQLONLY` を明示して呼び、 +その出力を `Result*.txt` に書くため。 +**`LOCAL` の出力で上書きすると期待値が壊れる**(起動している DBMS の数で内容が変わる)。 +手動実行だけにしてあるのはこのため。 + +#### 接続文字列 + +`App.config`(net48)と `appsettings.json`(.NET (Core))に持っている。 +LocalServicesOnDocker の既定値に合わせてあるので、**そのまま使えば通る**。 + +| DAP | キー | 既定値の要点 | +|---|---|---| +| `SQL` | `ConnectionString_SQL` | `localhost` / `sa` / `Northwind` | +| `ODP` | `ConnectionString_ODP` | `SCOTT` / `tiger` / `localhost/XE` | +| `MCN` | `ConnectionString_MCN` | `localhost` / `root` / `test` | +| `NPS` | `ConnectionString_NPS` | `localhost` / `postgres` / `postgres`(.NET (Core) のみ) | + +> **ADO.NET のキー=値形式では、パスワードの `@` をエンコードしない。** +> `Password=seigi@123` のままでよい。`%40` が要るのは Mongo のような URI 形式のみ。 + +#### 実測(全 DBMS 起動時) + +| DBMS | 参照系 5 パターン | 更新系 | +|---|---|---| +| SQL Server(`SQL`) | net48 5/5 / .NET 10 5/5 | **全項目一致** | +| Oracle(`ODP`) | net48 5/5 / .NET 10 5/5 | **全項目一致** | +| MySQL(`MCN`) | net48 5/5 / .NET 10 5/5 | **全項目一致** | +| PostgreSQL(`NPS`) | net48 対象外 / .NET 10 5/5 | **全項目一致**(.NET 10 のみ) | + +更新系は **4 DBMS が同一の出力**になる(件数と値だけを出しているため)。 + +#### 失敗したときの切り分け + +**例外の型名だけでは足りないことがある。** その場合はエラー番号まで見る。 + +| 症状 | 番号・型 | 原因 | +|---|---|---| +| MySQL に繋がらない | `1042` | **コンテナが起動していない**(ポートを待ち受けていない) | +| 同上 | `1130` | サーバには届いている。アカウントのホスト パターン不一致 | +| 同上 | `1045` | 認証情報の誤り | +| Oracle が `FileNotFoundException` | — | **パッケージ名が net48 と違う。**<br>.NET (Core) は `Oracle.ManagedDataAccess.Core` | + +ポートの待ち受けは次で確認できる。空なら①が済んでいない。 + +```powershell +Get-NetTCPConnection -LocalPort 3306 -State Listen # MySQL +Get-NetTCPConnection -LocalPort 1521 -State Listen # Oracle +Get-NetTCPConnection -LocalPort 5432 -State Listen # PostgreSQL +Get-NetTCPConnection -LocalPort 1433 -State Listen # SQL Server +``` + diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/Result48.txt b/root/programs/CS/Frameworks/Tests/TestDataAccess/Result48.txt new file mode 100644 index 000000000..dd09ef32f --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/Result48.txt @@ -0,0 +1,171 @@ +---------------------------------------------------------------------------------------------------- +実行モード : SQLONLY +対象データプロバイダ : SQL +---------------------------------------------------------------------------------------------------- +SQLUtility.GetUpdateSQLParts +[単一主キー] +- SQLServer +UPDATE Orders SET [Qty] = 100, [Note] = Convert(nvarchar(1), 'a') WHERE [OrderID] = 1 +UPDATE Orders SET [Qty] = 200, [Note] = Convert(nvarchar(1), 'b') WHERE [OrderID] = 2 +- Oracle +UPDATE Orders SET "Qty" = 100, "Note" = CAST('a' AS varchar2(1)) WHERE "OrderID" = 1 +UPDATE Orders SET "Qty" = 200, "Note" = CAST('b' AS varchar2(1)) WHERE "OrderID" = 2 +- PstGrS +UPDATE Orders SET "Qty" = CASE + WHEN "OrderID" = 1 THEN 100 + WHEN "OrderID" = 2 THEN 200 + ELSE "Qty" + END, + "Note" = CASE + WHEN "OrderID" = 1 THEN Cast('a' as text) + WHEN "OrderID" = 2 THEN Cast('b' as text) + ELSE "Note" + END +WHERE ("OrderID" = 1) + OR ("OrderID" = 2) +- MySQL +UPDATE Orders SET `Qty` = CASE + WHEN `OrderID` = 1 THEN 100 + WHEN `OrderID` = 2 THEN 200 + ELSE `Qty` + END, + `Note` = CASE + WHEN `OrderID` = 1 THEN Cast('a' as char(1)) + WHEN `OrderID` = 2 THEN Cast('b' as char(1)) + ELSE `Note` + END +WHERE (`OrderID` = 1) + OR (`OrderID` = 2) +[複合主キー] +- SQLServer +UPDATE Orders SET [Qty] = 100, [Note] = Convert(nvarchar(1), 'a') WHERE [OrderID] = 1 AND [ProductID] = 10 +UPDATE Orders SET [Qty] = 200, [Note] = Convert(nvarchar(1), 'b') WHERE [OrderID] = 2 AND [ProductID] = 20 +- Oracle +UPDATE Orders SET "Qty" = 100, "Note" = CAST('a' AS varchar2(1)) WHERE "OrderID" = 1 AND "ProductID" = 10 +UPDATE Orders SET "Qty" = 200, "Note" = CAST('b' AS varchar2(1)) WHERE "OrderID" = 2 AND "ProductID" = 20 +- PstGrS +UPDATE Orders SET "Qty" = CASE + WHEN "OrderID" = 1 AND "ProductID" = 10 THEN 100 + WHEN "OrderID" = 2 AND "ProductID" = 20 THEN 200 + ELSE "Qty" + END, + "Note" = CASE + WHEN "OrderID" = 1 AND "ProductID" = 10 THEN Cast('a' as text) + WHEN "OrderID" = 2 AND "ProductID" = 20 THEN Cast('b' as text) + ELSE "Note" + END +WHERE ("OrderID" = 1 AND "ProductID" = 10) + OR ("OrderID" = 2 AND "ProductID" = 20) +- MySQL +UPDATE Orders SET `Qty` = CASE + WHEN `OrderID` = 1 AND `ProductID` = 10 THEN 100 + WHEN `OrderID` = 2 AND `ProductID` = 20 THEN 200 + ELSE `Qty` + END, + `Note` = CASE + WHEN `OrderID` = 1 AND `ProductID` = 10 THEN Cast('a' as char(1)) + WHEN `OrderID` = 2 AND `ProductID` = 20 THEN Cast('b' as char(1)) + ELSE `Note` + END +WHERE (`OrderID` = 1 AND `ProductID` = 10) + OR (`OrderID` = 2 AND `ProductID` = 20) +[更新対象列なし] +- SQLServer +(生成なし) +- Oracle +(生成なし) +- PstGrS +(生成なし) +- MySQL +(生成なし) +[主キーなし] +- SQLServer +(生成なし) +- Oracle +(生成なし) +- PstGrS +(生成なし) +- MySQL +(生成なし) +---------------------------------------------------------------------------------------------------- +SQLUtility.GetInsertSQLParts +- SQLServer +([OrderID], [ProductID], [Qty], [Note]) +(1, 10, 100, Convert(nvarchar(1), 'a')) +(2, 20, 200, Convert(nvarchar(1), 'b')) +- Oracle +("OrderID", "ProductID", "Qty", "Note") +(1, 10, 100, CAST('a' AS varchar2(1))) +(2, 20, 200, CAST('b' AS varchar2(1))) +- PstGrS +("OrderID", "ProductID", "Qty", "Note") +(1, 10, 100, Cast('a' as text)) +(2, 20, 200, Cast('b' as text)) +- MySQL +(`OrderID`, `ProductID`, `Qty`, `Note`) +(1, 10, 100, Cast('a' as char(1))) +(2, 20, 200, Cast('b' as char(1))) +---------------------------------------------------------------------------------------------------- +[SQL] +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 +---------------------------------------------------------------------------------------------------- +更新系(専用の表を作って落とす) +---------------------------------------------------------------------------------------------------- +[SQL] +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +---------------------------------------------------------------------------------------------------- +動的パラメタライズドクエリ +---------------------------------------------------------------------------------------------------- +[SQL] +- WHERE / IF の組み合わせ + 両方指定 : 1 件 + 両方指定(不一致) : 0 件 + OrderIDのみ : 1 件 + Qtyのみ : 1 件 + 指定なし : 4 件 +- IF / ELSE(テキスト内パラメタ) + 値を設定 : 1 件 + nullを設定 : 1 件 + 未設定 : 4 件 +- IF / ELSE(タグ内パラメタ) + true : 1 件 + false : 1 件 + null : 1 件 + 未設定 : 4 件 +- LIST(IN 句) + 2 値 : 2 件 + 3 値 : 3 件 +- パラメタの作用範囲 + テキスト内(全タグ) : 0 件 + タグ内(最初の1つ) : 1 件 +- DELCMA / INSCOL + 両方の列 : 1 件 + Qtyのみ : 1 件 + Noteのみ : 1 件 + 投入後の件数 : 7 +- 組み立てのみ(ExecGenerateSQL) + CASE(a1) : SELECT 1 AS X + CASE(b2) : SELECT 2 AS X + DEFAULT : SELECT 9 AS X + 比較演算子 : SELECT [OrderID] FROM [TestOrders] WHERE [Qty] < 900 AND [Qty] > 100 + JOIN+SUB あり : SELECT o.[OrderID] FROM [TestOrders] o INNER JOIN [OtherTable] t ON o.[OrderID] = t.[OrderID] WHERE o.[Qty] = 999 AND o.[OrderID] IN (SELECT [OrderID] FROM [OtherTable]) + JOIN のみ : SELECT o.[OrderID] FROM [TestOrders] o INNER JOIN [OtherTable] t ON o.[OrderID] = t.[OrderID] WHERE o.[Qty] = 999 + JOIN+SUB なし : SELECT o.[OrderID] FROM [TestOrders] o + IsDPQ(タグあり): True + IsDPQ(タグなし): False +---------------------------------------------------------------------------------------------------- diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/ResultCore100.txt b/root/programs/CS/Frameworks/Tests/TestDataAccess/ResultCore100.txt new file mode 100644 index 000000000..dd09ef32f --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/ResultCore100.txt @@ -0,0 +1,171 @@ +---------------------------------------------------------------------------------------------------- +実行モード : SQLONLY +対象データプロバイダ : SQL +---------------------------------------------------------------------------------------------------- +SQLUtility.GetUpdateSQLParts +[単一主キー] +- SQLServer +UPDATE Orders SET [Qty] = 100, [Note] = Convert(nvarchar(1), 'a') WHERE [OrderID] = 1 +UPDATE Orders SET [Qty] = 200, [Note] = Convert(nvarchar(1), 'b') WHERE [OrderID] = 2 +- Oracle +UPDATE Orders SET "Qty" = 100, "Note" = CAST('a' AS varchar2(1)) WHERE "OrderID" = 1 +UPDATE Orders SET "Qty" = 200, "Note" = CAST('b' AS varchar2(1)) WHERE "OrderID" = 2 +- PstGrS +UPDATE Orders SET "Qty" = CASE + WHEN "OrderID" = 1 THEN 100 + WHEN "OrderID" = 2 THEN 200 + ELSE "Qty" + END, + "Note" = CASE + WHEN "OrderID" = 1 THEN Cast('a' as text) + WHEN "OrderID" = 2 THEN Cast('b' as text) + ELSE "Note" + END +WHERE ("OrderID" = 1) + OR ("OrderID" = 2) +- MySQL +UPDATE Orders SET `Qty` = CASE + WHEN `OrderID` = 1 THEN 100 + WHEN `OrderID` = 2 THEN 200 + ELSE `Qty` + END, + `Note` = CASE + WHEN `OrderID` = 1 THEN Cast('a' as char(1)) + WHEN `OrderID` = 2 THEN Cast('b' as char(1)) + ELSE `Note` + END +WHERE (`OrderID` = 1) + OR (`OrderID` = 2) +[複合主キー] +- SQLServer +UPDATE Orders SET [Qty] = 100, [Note] = Convert(nvarchar(1), 'a') WHERE [OrderID] = 1 AND [ProductID] = 10 +UPDATE Orders SET [Qty] = 200, [Note] = Convert(nvarchar(1), 'b') WHERE [OrderID] = 2 AND [ProductID] = 20 +- Oracle +UPDATE Orders SET "Qty" = 100, "Note" = CAST('a' AS varchar2(1)) WHERE "OrderID" = 1 AND "ProductID" = 10 +UPDATE Orders SET "Qty" = 200, "Note" = CAST('b' AS varchar2(1)) WHERE "OrderID" = 2 AND "ProductID" = 20 +- PstGrS +UPDATE Orders SET "Qty" = CASE + WHEN "OrderID" = 1 AND "ProductID" = 10 THEN 100 + WHEN "OrderID" = 2 AND "ProductID" = 20 THEN 200 + ELSE "Qty" + END, + "Note" = CASE + WHEN "OrderID" = 1 AND "ProductID" = 10 THEN Cast('a' as text) + WHEN "OrderID" = 2 AND "ProductID" = 20 THEN Cast('b' as text) + ELSE "Note" + END +WHERE ("OrderID" = 1 AND "ProductID" = 10) + OR ("OrderID" = 2 AND "ProductID" = 20) +- MySQL +UPDATE Orders SET `Qty` = CASE + WHEN `OrderID` = 1 AND `ProductID` = 10 THEN 100 + WHEN `OrderID` = 2 AND `ProductID` = 20 THEN 200 + ELSE `Qty` + END, + `Note` = CASE + WHEN `OrderID` = 1 AND `ProductID` = 10 THEN Cast('a' as char(1)) + WHEN `OrderID` = 2 AND `ProductID` = 20 THEN Cast('b' as char(1)) + ELSE `Note` + END +WHERE (`OrderID` = 1 AND `ProductID` = 10) + OR (`OrderID` = 2 AND `ProductID` = 20) +[更新対象列なし] +- SQLServer +(生成なし) +- Oracle +(生成なし) +- PstGrS +(生成なし) +- MySQL +(生成なし) +[主キーなし] +- SQLServer +(生成なし) +- Oracle +(生成なし) +- PstGrS +(生成なし) +- MySQL +(生成なし) +---------------------------------------------------------------------------------------------------- +SQLUtility.GetInsertSQLParts +- SQLServer +([OrderID], [ProductID], [Qty], [Note]) +(1, 10, 100, Convert(nvarchar(1), 'a')) +(2, 20, 200, Convert(nvarchar(1), 'b')) +- Oracle +("OrderID", "ProductID", "Qty", "Note") +(1, 10, 100, CAST('a' AS varchar2(1))) +(2, 20, 200, CAST('b' AS varchar2(1))) +- PstGrS +("OrderID", "ProductID", "Qty", "Note") +(1, 10, 100, Cast('a' as text)) +(2, 20, 200, Cast('b' as text)) +- MySQL +(`OrderID`, `ProductID`, `Qty`, `Note`) +(1, 10, 100, Cast('a' as char(1))) +(2, 20, 200, Cast('b' as char(1))) +---------------------------------------------------------------------------------------------------- +[SQL] +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 +---------------------------------------------------------------------------------------------------- +更新系(専用の表を作って落とす) +---------------------------------------------------------------------------------------------------- +[SQL] +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +---------------------------------------------------------------------------------------------------- +動的パラメタライズドクエリ +---------------------------------------------------------------------------------------------------- +[SQL] +- WHERE / IF の組み合わせ + 両方指定 : 1 件 + 両方指定(不一致) : 0 件 + OrderIDのみ : 1 件 + Qtyのみ : 1 件 + 指定なし : 4 件 +- IF / ELSE(テキスト内パラメタ) + 値を設定 : 1 件 + nullを設定 : 1 件 + 未設定 : 4 件 +- IF / ELSE(タグ内パラメタ) + true : 1 件 + false : 1 件 + null : 1 件 + 未設定 : 4 件 +- LIST(IN 句) + 2 値 : 2 件 + 3 値 : 3 件 +- パラメタの作用範囲 + テキスト内(全タグ) : 0 件 + タグ内(最初の1つ) : 1 件 +- DELCMA / INSCOL + 両方の列 : 1 件 + Qtyのみ : 1 件 + Noteのみ : 1 件 + 投入後の件数 : 7 +- 組み立てのみ(ExecGenerateSQL) + CASE(a1) : SELECT 1 AS X + CASE(b2) : SELECT 2 AS X + DEFAULT : SELECT 9 AS X + 比較演算子 : SELECT [OrderID] FROM [TestOrders] WHERE [Qty] < 900 AND [Qty] > 100 + JOIN+SUB あり : SELECT o.[OrderID] FROM [TestOrders] o INNER JOIN [OtherTable] t ON o.[OrderID] = t.[OrderID] WHERE o.[Qty] = 999 AND o.[OrderID] IN (SELECT [OrderID] FROM [OtherTable]) + JOIN のみ : SELECT o.[OrderID] FROM [TestOrders] o INNER JOIN [OtherTable] t ON o.[OrderID] = t.[OrderID] WHERE o.[Qty] = 999 + JOIN+SUB なし : SELECT o.[OrderID] FROM [TestOrders] o + IsDPQ(タグあり): True + IsDPQ(タグなし): False +---------------------------------------------------------------------------------------------------- diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/ResultLocal48.txt b/root/programs/CS/Frameworks/Tests/TestDataAccess/ResultLocal48.txt new file mode 100644 index 000000000..db81be4ec --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/ResultLocal48.txt @@ -0,0 +1,277 @@ +---------------------------------------------------------------------------------------------------- +実行モード : LOCAL +対象データプロバイダ : SQL, ODP, MCN +---------------------------------------------------------------------------------------------------- +SQLUtility.GetUpdateSQLParts +[単一主キー] +- SQLServer +UPDATE Orders SET [Qty] = 100, [Note] = Convert(nvarchar(1), 'a') WHERE [OrderID] = 1 +UPDATE Orders SET [Qty] = 200, [Note] = Convert(nvarchar(1), 'b') WHERE [OrderID] = 2 +- Oracle +UPDATE Orders SET "Qty" = 100, "Note" = CAST('a' AS varchar2(1)) WHERE "OrderID" = 1 +UPDATE Orders SET "Qty" = 200, "Note" = CAST('b' AS varchar2(1)) WHERE "OrderID" = 2 +- PstGrS +UPDATE Orders SET "Qty" = CASE + WHEN "OrderID" = 1 THEN 100 + WHEN "OrderID" = 2 THEN 200 + ELSE "Qty" + END, + "Note" = CASE + WHEN "OrderID" = 1 THEN Cast('a' as text) + WHEN "OrderID" = 2 THEN Cast('b' as text) + ELSE "Note" + END +WHERE ("OrderID" = 1) + OR ("OrderID" = 2) +- MySQL +UPDATE Orders SET `Qty` = CASE + WHEN `OrderID` = 1 THEN 100 + WHEN `OrderID` = 2 THEN 200 + ELSE `Qty` + END, + `Note` = CASE + WHEN `OrderID` = 1 THEN Cast('a' as char(1)) + WHEN `OrderID` = 2 THEN Cast('b' as char(1)) + ELSE `Note` + END +WHERE (`OrderID` = 1) + OR (`OrderID` = 2) +[複合主キー] +- SQLServer +UPDATE Orders SET [Qty] = 100, [Note] = Convert(nvarchar(1), 'a') WHERE [OrderID] = 1 AND [ProductID] = 10 +UPDATE Orders SET [Qty] = 200, [Note] = Convert(nvarchar(1), 'b') WHERE [OrderID] = 2 AND [ProductID] = 20 +- Oracle +UPDATE Orders SET "Qty" = 100, "Note" = CAST('a' AS varchar2(1)) WHERE "OrderID" = 1 AND "ProductID" = 10 +UPDATE Orders SET "Qty" = 200, "Note" = CAST('b' AS varchar2(1)) WHERE "OrderID" = 2 AND "ProductID" = 20 +- PstGrS +UPDATE Orders SET "Qty" = CASE + WHEN "OrderID" = 1 AND "ProductID" = 10 THEN 100 + WHEN "OrderID" = 2 AND "ProductID" = 20 THEN 200 + ELSE "Qty" + END, + "Note" = CASE + WHEN "OrderID" = 1 AND "ProductID" = 10 THEN Cast('a' as text) + WHEN "OrderID" = 2 AND "ProductID" = 20 THEN Cast('b' as text) + ELSE "Note" + END +WHERE ("OrderID" = 1 AND "ProductID" = 10) + OR ("OrderID" = 2 AND "ProductID" = 20) +- MySQL +UPDATE Orders SET `Qty` = CASE + WHEN `OrderID` = 1 AND `ProductID` = 10 THEN 100 + WHEN `OrderID` = 2 AND `ProductID` = 20 THEN 200 + ELSE `Qty` + END, + `Note` = CASE + WHEN `OrderID` = 1 AND `ProductID` = 10 THEN Cast('a' as char(1)) + WHEN `OrderID` = 2 AND `ProductID` = 20 THEN Cast('b' as char(1)) + ELSE `Note` + END +WHERE (`OrderID` = 1 AND `ProductID` = 10) + OR (`OrderID` = 2 AND `ProductID` = 20) +[更新対象列なし] +- SQLServer +(生成なし) +- Oracle +(生成なし) +- PstGrS +(生成なし) +- MySQL +(生成なし) +[主キーなし] +- SQLServer +(生成なし) +- Oracle +(生成なし) +- PstGrS +(生成なし) +- MySQL +(生成なし) +---------------------------------------------------------------------------------------------------- +SQLUtility.GetInsertSQLParts +- SQLServer +([OrderID], [ProductID], [Qty], [Note]) +(1, 10, 100, Convert(nvarchar(1), 'a')) +(2, 20, 200, Convert(nvarchar(1), 'b')) +- Oracle +("OrderID", "ProductID", "Qty", "Note") +(1, 10, 100, CAST('a' AS varchar2(1))) +(2, 20, 200, CAST('b' AS varchar2(1))) +- PstGrS +("OrderID", "ProductID", "Qty", "Note") +(1, 10, 100, Cast('a' as text)) +(2, 20, 200, Cast('b' as text)) +- MySQL +(`OrderID`, `ProductID`, `Qty`, `Note`) +(1, 10, 100, Cast('a' as char(1))) +(2, 20, 200, Cast('b' as char(1))) +---------------------------------------------------------------------------------------------------- +[SQL] +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 +---------------------------------------------------------------------------------------------------- +[ODP] +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 +---------------------------------------------------------------------------------------------------- +[MCN] +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 +---------------------------------------------------------------------------------------------------- +更新系(専用の表を作って落とす) +---------------------------------------------------------------------------------------------------- +[SQL] +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +---------------------------------------------------------------------------------------------------- +[ODP] +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +---------------------------------------------------------------------------------------------------- +[MCN] +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +---------------------------------------------------------------------------------------------------- +動的パラメタライズドクエリ +---------------------------------------------------------------------------------------------------- +[SQL] +- WHERE / IF の組み合わせ + 両方指定 : 1 件 + 両方指定(不一致) : 0 件 + OrderIDのみ : 1 件 + Qtyのみ : 1 件 + 指定なし : 4 件 +- IF / ELSE(テキスト内パラメタ) + 値を設定 : 1 件 + nullを設定 : 1 件 + 未設定 : 4 件 +- IF / ELSE(タグ内パラメタ) + true : 1 件 + false : 1 件 + null : 1 件 + 未設定 : 4 件 +- LIST(IN 句) + 2 値 : 2 件 + 3 値 : 3 件 +- パラメタの作用範囲 + テキスト内(全タグ) : 0 件 + タグ内(最初の1つ) : 1 件 +- DELCMA / INSCOL + 両方の列 : 1 件 + Qtyのみ : 1 件 + Noteのみ : 1 件 + 投入後の件数 : 7 +- 組み立てのみ(ExecGenerateSQL) + CASE(a1) : SELECT 1 AS X + CASE(b2) : SELECT 2 AS X + DEFAULT : SELECT 9 AS X + 比較演算子 : SELECT [OrderID] FROM [TestOrders] WHERE [Qty] < 900 AND [Qty] > 100 + JOIN+SUB あり : SELECT o.[OrderID] FROM [TestOrders] o INNER JOIN [OtherTable] t ON o.[OrderID] = t.[OrderID] WHERE o.[Qty] = 999 AND o.[OrderID] IN (SELECT [OrderID] FROM [OtherTable]) + JOIN のみ : SELECT o.[OrderID] FROM [TestOrders] o INNER JOIN [OtherTable] t ON o.[OrderID] = t.[OrderID] WHERE o.[Qty] = 999 + JOIN+SUB なし : SELECT o.[OrderID] FROM [TestOrders] o + IsDPQ(タグあり): True + IsDPQ(タグなし): False +---------------------------------------------------------------------------------------------------- +[ODP] +- WHERE / IF の組み合わせ + 両方指定 : 1 件 + 両方指定(不一致) : 0 件 + OrderIDのみ : 1 件 + Qtyのみ : 1 件 + 指定なし : 4 件 +- IF / ELSE(テキスト内パラメタ) + 値を設定 : 1 件 + nullを設定 : 1 件 + 未設定 : 4 件 +- IF / ELSE(タグ内パラメタ) + true : 1 件 + false : 1 件 + null : 1 件 + 未設定 : 4 件 +- LIST(IN 句) + 2 値 : 2 件 + 3 値 : 3 件 +- パラメタの作用範囲 + テキスト内(全タグ) : 0 件 + タグ内(最初の1つ) : 1 件 +- DELCMA / INSCOL + 両方の列 : 1 件 + Qtyのみ : 1 件 + Noteのみ : 1 件 + 投入後の件数 : 7 +- 組み立てのみ(ExecGenerateSQL) + ExecGenerateSQL : このデータ プロバイダでは未実装 + IsDPQ(タグあり): True + IsDPQ(タグなし): False +---------------------------------------------------------------------------------------------------- +[MCN] +- WHERE / IF の組み合わせ + 両方指定 : 1 件 + 両方指定(不一致) : 0 件 + OrderIDのみ : 1 件 + Qtyのみ : 1 件 + 指定なし : 4 件 +- IF / ELSE(テキスト内パラメタ) + 値を設定 : 1 件 + nullを設定 : 1 件 + 未設定 : 4 件 +- IF / ELSE(タグ内パラメタ) + true : 1 件 + false : 1 件 + null : 1 件 + 未設定 : 4 件 +- LIST(IN 句) + 2 値 : 2 件 + 3 値 : 3 件 +- パラメタの作用範囲 + テキスト内(全タグ) : 0 件 + タグ内(最初の1つ) : 1 件 +- DELCMA / INSCOL + 両方の列 : 1 件 + Qtyのみ : 1 件 + Noteのみ : 1 件 + 投入後の件数 : 7 +- 組み立てのみ(ExecGenerateSQL) + ExecGenerateSQL : このデータ プロバイダでは未実装 + IsDPQ(タグあり): True + IsDPQ(タグなし): False +---------------------------------------------------------------------------------------------------- diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/ResultLocalCore100.txt b/root/programs/CS/Frameworks/Tests/TestDataAccess/ResultLocalCore100.txt new file mode 100644 index 000000000..2c11cbe31 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/ResultLocalCore100.txt @@ -0,0 +1,330 @@ +---------------------------------------------------------------------------------------------------- +実行モード : LOCAL +対象データプロバイダ : SQL, ODP, MCN, NPS +---------------------------------------------------------------------------------------------------- +SQLUtility.GetUpdateSQLParts +[単一主キー] +- SQLServer +UPDATE Orders SET [Qty] = 100, [Note] = Convert(nvarchar(1), 'a') WHERE [OrderID] = 1 +UPDATE Orders SET [Qty] = 200, [Note] = Convert(nvarchar(1), 'b') WHERE [OrderID] = 2 +- Oracle +UPDATE Orders SET "Qty" = 100, "Note" = CAST('a' AS varchar2(1)) WHERE "OrderID" = 1 +UPDATE Orders SET "Qty" = 200, "Note" = CAST('b' AS varchar2(1)) WHERE "OrderID" = 2 +- PstGrS +UPDATE Orders SET "Qty" = CASE + WHEN "OrderID" = 1 THEN 100 + WHEN "OrderID" = 2 THEN 200 + ELSE "Qty" + END, + "Note" = CASE + WHEN "OrderID" = 1 THEN Cast('a' as text) + WHEN "OrderID" = 2 THEN Cast('b' as text) + ELSE "Note" + END +WHERE ("OrderID" = 1) + OR ("OrderID" = 2) +- MySQL +UPDATE Orders SET `Qty` = CASE + WHEN `OrderID` = 1 THEN 100 + WHEN `OrderID` = 2 THEN 200 + ELSE `Qty` + END, + `Note` = CASE + WHEN `OrderID` = 1 THEN Cast('a' as char(1)) + WHEN `OrderID` = 2 THEN Cast('b' as char(1)) + ELSE `Note` + END +WHERE (`OrderID` = 1) + OR (`OrderID` = 2) +[複合主キー] +- SQLServer +UPDATE Orders SET [Qty] = 100, [Note] = Convert(nvarchar(1), 'a') WHERE [OrderID] = 1 AND [ProductID] = 10 +UPDATE Orders SET [Qty] = 200, [Note] = Convert(nvarchar(1), 'b') WHERE [OrderID] = 2 AND [ProductID] = 20 +- Oracle +UPDATE Orders SET "Qty" = 100, "Note" = CAST('a' AS varchar2(1)) WHERE "OrderID" = 1 AND "ProductID" = 10 +UPDATE Orders SET "Qty" = 200, "Note" = CAST('b' AS varchar2(1)) WHERE "OrderID" = 2 AND "ProductID" = 20 +- PstGrS +UPDATE Orders SET "Qty" = CASE + WHEN "OrderID" = 1 AND "ProductID" = 10 THEN 100 + WHEN "OrderID" = 2 AND "ProductID" = 20 THEN 200 + ELSE "Qty" + END, + "Note" = CASE + WHEN "OrderID" = 1 AND "ProductID" = 10 THEN Cast('a' as text) + WHEN "OrderID" = 2 AND "ProductID" = 20 THEN Cast('b' as text) + ELSE "Note" + END +WHERE ("OrderID" = 1 AND "ProductID" = 10) + OR ("OrderID" = 2 AND "ProductID" = 20) +- MySQL +UPDATE Orders SET `Qty` = CASE + WHEN `OrderID` = 1 AND `ProductID` = 10 THEN 100 + WHEN `OrderID` = 2 AND `ProductID` = 20 THEN 200 + ELSE `Qty` + END, + `Note` = CASE + WHEN `OrderID` = 1 AND `ProductID` = 10 THEN Cast('a' as char(1)) + WHEN `OrderID` = 2 AND `ProductID` = 20 THEN Cast('b' as char(1)) + ELSE `Note` + END +WHERE (`OrderID` = 1 AND `ProductID` = 10) + OR (`OrderID` = 2 AND `ProductID` = 20) +[更新対象列なし] +- SQLServer +(生成なし) +- Oracle +(生成なし) +- PstGrS +(生成なし) +- MySQL +(生成なし) +[主キーなし] +- SQLServer +(生成なし) +- Oracle +(生成なし) +- PstGrS +(生成なし) +- MySQL +(生成なし) +---------------------------------------------------------------------------------------------------- +SQLUtility.GetInsertSQLParts +- SQLServer +([OrderID], [ProductID], [Qty], [Note]) +(1, 10, 100, Convert(nvarchar(1), 'a')) +(2, 20, 200, Convert(nvarchar(1), 'b')) +- Oracle +("OrderID", "ProductID", "Qty", "Note") +(1, 10, 100, CAST('a' AS varchar2(1))) +(2, 20, 200, CAST('b' AS varchar2(1))) +- PstGrS +("OrderID", "ProductID", "Qty", "Note") +(1, 10, 100, Cast('a' as text)) +(2, 20, 200, Cast('b' as text)) +- MySQL +(`OrderID`, `ProductID`, `Qty`, `Note`) +(1, 10, 100, Cast('a' as char(1))) +(2, 20, 200, Cast('b' as char(1))) +---------------------------------------------------------------------------------------------------- +[SQL] +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 +---------------------------------------------------------------------------------------------------- +[ODP] +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 +---------------------------------------------------------------------------------------------------- +[MCN] +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 +---------------------------------------------------------------------------------------------------- +[NPS] +- ExecSelectScalar : 3 +- ExecSelectFill_DT : 3 +- ExecSelectFill_DS : 3 +- ExecSelect_DR : 3 +- SetSqlByFile + Scalar : 3 +---------------------------------------------------------------------------------------------------- +更新系(専用の表を作って落とす) +---------------------------------------------------------------------------------------------------- +[SQL] +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +---------------------------------------------------------------------------------------------------- +[ODP] +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +---------------------------------------------------------------------------------------------------- +[MCN] +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +---------------------------------------------------------------------------------------------------- +[NPS] +- INSERT(GetInsertSQLParts) : 3 件 + 投入後 : 1, 10, 999, x + 投入後 : 2, 20, 888, y + 投入後 : 3, 30, 777, z +- UPDATE(GetUpdateSQLParts) : 2 件 + 更新後 : 1, 10, 100, a + 更新後 : 2, 20, 200, b + 更新後 : 3, 30, 777, z +- ロールバック後の件数 : 3 +- コミット後の件数 : 2 +- DELETE : 2 件 +- 削除後の件数 : 0 +---------------------------------------------------------------------------------------------------- +動的パラメタライズドクエリ +---------------------------------------------------------------------------------------------------- +[SQL] +- WHERE / IF の組み合わせ + 両方指定 : 1 件 + 両方指定(不一致) : 0 件 + OrderIDのみ : 1 件 + Qtyのみ : 1 件 + 指定なし : 4 件 +- IF / ELSE(テキスト内パラメタ) + 値を設定 : 1 件 + nullを設定 : 1 件 + 未設定 : 4 件 +- IF / ELSE(タグ内パラメタ) + true : 1 件 + false : 1 件 + null : 1 件 + 未設定 : 4 件 +- LIST(IN 句) + 2 値 : 2 件 + 3 値 : 3 件 +- パラメタの作用範囲 + テキスト内(全タグ) : 0 件 + タグ内(最初の1つ) : 1 件 +- DELCMA / INSCOL + 両方の列 : 1 件 + Qtyのみ : 1 件 + Noteのみ : 1 件 + 投入後の件数 : 7 +- 組み立てのみ(ExecGenerateSQL) + CASE(a1) : SELECT 1 AS X + CASE(b2) : SELECT 2 AS X + DEFAULT : SELECT 9 AS X + 比較演算子 : SELECT [OrderID] FROM [TestOrders] WHERE [Qty] < 900 AND [Qty] > 100 + JOIN+SUB あり : SELECT o.[OrderID] FROM [TestOrders] o INNER JOIN [OtherTable] t ON o.[OrderID] = t.[OrderID] WHERE o.[Qty] = 999 AND o.[OrderID] IN (SELECT [OrderID] FROM [OtherTable]) + JOIN のみ : SELECT o.[OrderID] FROM [TestOrders] o INNER JOIN [OtherTable] t ON o.[OrderID] = t.[OrderID] WHERE o.[Qty] = 999 + JOIN+SUB なし : SELECT o.[OrderID] FROM [TestOrders] o + IsDPQ(タグあり): True + IsDPQ(タグなし): False +---------------------------------------------------------------------------------------------------- +[ODP] +- WHERE / IF の組み合わせ + 両方指定 : 1 件 + 両方指定(不一致) : 0 件 + OrderIDのみ : 1 件 + Qtyのみ : 1 件 + 指定なし : 4 件 +- IF / ELSE(テキスト内パラメタ) + 値を設定 : 1 件 + nullを設定 : 1 件 + 未設定 : 4 件 +- IF / ELSE(タグ内パラメタ) + true : 1 件 + false : 1 件 + null : 1 件 + 未設定 : 4 件 +- LIST(IN 句) + 2 値 : 2 件 + 3 値 : 3 件 +- パラメタの作用範囲 + テキスト内(全タグ) : 0 件 + タグ内(最初の1つ) : 1 件 +- DELCMA / INSCOL + 両方の列 : 1 件 + Qtyのみ : 1 件 + Noteのみ : 1 件 + 投入後の件数 : 7 +- 組み立てのみ(ExecGenerateSQL) + ExecGenerateSQL : このデータ プロバイダでは未実装 + IsDPQ(タグあり): True + IsDPQ(タグなし): False +---------------------------------------------------------------------------------------------------- +[MCN] +- WHERE / IF の組み合わせ + 両方指定 : 1 件 + 両方指定(不一致) : 0 件 + OrderIDのみ : 1 件 + Qtyのみ : 1 件 + 指定なし : 4 件 +- IF / ELSE(テキスト内パラメタ) + 値を設定 : 1 件 + nullを設定 : 1 件 + 未設定 : 4 件 +- IF / ELSE(タグ内パラメタ) + true : 1 件 + false : 1 件 + null : 1 件 + 未設定 : 4 件 +- LIST(IN 句) + 2 値 : 2 件 + 3 値 : 3 件 +- パラメタの作用範囲 + テキスト内(全タグ) : 0 件 + タグ内(最初の1つ) : 1 件 +- DELCMA / INSCOL + 両方の列 : 1 件 + Qtyのみ : 1 件 + Noteのみ : 1 件 + 投入後の件数 : 7 +- 組み立てのみ(ExecGenerateSQL) + ExecGenerateSQL : このデータ プロバイダでは未実装 + IsDPQ(タグあり): True + IsDPQ(タグなし): False +---------------------------------------------------------------------------------------------------- +[NPS] +- WHERE / IF の組み合わせ + 両方指定 : 1 件 + 両方指定(不一致) : 0 件 + OrderIDのみ : 1 件 + Qtyのみ : 1 件 + 指定なし : 4 件 +- IF / ELSE(テキスト内パラメタ) + 値を設定 : 1 件 + nullを設定 : 1 件 + 未設定 : 4 件 +- IF / ELSE(タグ内パラメタ) + true : 1 件 + false : 1 件 + null : 1 件 + 未設定 : 4 件 +- LIST(IN 句) + 2 値 : 2 件 + 3 値 : 3 件 +- パラメタの作用範囲 + テキスト内(全タグ) : 0 件 + タグ内(最初の1つ) : 1 件 +- DELCMA / INSCOL + 両方の列 : 1 件 + Qtyのみ : 1 件 + Noteのみ : 1 件 + 投入後の件数 : 7 +- 組み立てのみ(ExecGenerateSQL) + ExecGenerateSQL : このデータ プロバイダでは未実装 + IsDPQ(タグあり): True + IsDPQ(タグなし): False +---------------------------------------------------------------------------------------------------- diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/SampleLogConf.xml b/root/programs/CS/Frameworks/Tests/TestDataAccess/SampleLogConf.xml new file mode 100644 index 000000000..9871550bd --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/SampleLogConf.xml @@ -0,0 +1,178 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- log4net構成設定のセクション --> + +<log4net debug="true"><!-- ← debug="true"の場合、デバッグ用のコンソール出力が有効になる。 --> + + <!-- アペンダを選択することによって、ログの出力先を変更できる。 --> + + <!-- + アペンダの例 + + FileAppender :ファイルに出力。 + RollingFileAppender :ファイルに出力。ローリング機能付き。 + EventLogAppender :イベントビューアに出力(ローカルのPCのみ) + ConsoleAppender :コンソールに出力 + ※ FileAppender、RollingFileAppenderは、ネットワーク上のフォルダ共有やネットワークドライブにへの出力も可能 + --> + + <!-- + PatternLayoutで指定できるパターン + パターン 説明 + %logger ログ出力が行われたlogger名 + %appdomain アプリケーションドメイン名 + ●%date 日時を出力。「%date{yyyy/MM/dd HH:mm:ss,fff}」といった詳細指定も可能。 + ●%level ログのレベル(Fatal/Errorなど) + ●%t ログを生成したスレッド + ●%message メッセージ + ●%newline 改行文字 + %literal{-} リテラル(%をそのまま出力する場合など) + %file ファイル名 + %class クラス名 + %method メソッド名 + %line 行番号 + %location ログ出力した際の関数名とファイルのフルパス + ※ %file ~ %locationは処理負荷が高くなるため必要な時以外は使用しない。 + http://d.hatena.ne.jp/shima111/20060703 + --> + + <!-- ローリング・ログファイル出力用アペンダ --> + <appender name="ACCESS1" type="log4net.Appender.RollingFileAppender"> + <param name="File" value="./Log/ACCESS" /> + <!-- ローリングの設定 --> + <param name="StaticLogFileName" value="false" /> + <param name="RollingStyle" value="date " /> + <param name="DatePattern" value='"."yyyy-MM-dd".log"' /> + <!-- 書き込み時の設定(追加 or 上書き、出力エンコーディング) --> + <param name="AppendToFile" value="true" /> + <encoding value="utf-8" /> + <!-- メッセージのフォーマット --> + <layout type="log4net.Layout.PatternLayout"> + <param name="ConversionPattern" value="[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline" /> + </layout> + <!-- フィルタ(範囲)の設定 --> + <filter type="log4net.Filter.LevelRangeFilter"> + <levelMin value="DEBUG" /> + <levelMax value="FATAL" /> + </filter> + </appender> + <!-- コンソール出力用アペンダ --> + <appender name="ACCESS2" type="log4net.Appender.ConsoleAppender"> + <!-- メッセージのフォーマット --> + <layout type="log4net.Layout.PatternLayout"> + <param name="ConversionPattern" value="[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline" /> + </layout> + <!-- フィルタ(範囲)の設定 --> + <filter type="log4net.Filter.LevelRangeFilter"> + <levelMin value="DEBUG" /> + <levelMax value="FATAL" /> + </filter> + </appender> + + <!-- ローリング・ログファイル出力用アペンダ --> + <appender name="SQLTRACE1" type="log4net.Appender.RollingFileAppender"> + <param name="File" value="./Log/SQLTRACE" /> + <!-- ローリングの設定 --> + <param name="StaticLogFileName" value="false" /> + <param name="RollingStyle" value="date " /> + <param name="DatePattern" value='"."yyyy-MM-dd".log"' /> + <!-- 書き込み時の設定(追加 or 上書き、出力エンコーディング) --> + <param name="AppendToFile" value="true" /> + <encoding value="utf-8" /> + <!-- メッセージのフォーマット --> + <layout type="log4net.Layout.PatternLayout"> + <param name="ConversionPattern" value="[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline" /> + </layout> + <!-- フィルタ(範囲)の設定 --> + <filter type="log4net.Filter.LevelRangeFilter"> + <levelMin value="DEBUG" /> + <levelMax value="FATAL" /> + </filter> + </appender> + <!-- コンソール出力用アペンダ --> + <appender name="SQLTRACE2" type="log4net.Appender.ConsoleAppender"> + <!-- メッセージのフォーマット --> + <layout type="log4net.Layout.PatternLayout"> + <param name="ConversionPattern" value="[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline" /> + </layout> + <!-- フィルタ(範囲)の設定 --> + <filter type="log4net.Filter.LevelRangeFilter"> + <levelMin value="DEBUG" /> + <levelMax value="FATAL" /> + </filter> + </appender> + + <!-- ローリング・ログファイル出力用アペンダ --> + <appender name="OPERATION1" type="log4net.Appender.RollingFileAppender"> + <param name="File" value="./Log/OPERATION" /> + <!-- ローリングの設定 --> + <param name="StaticLogFileName" value="false" /> + <param name="RollingStyle" value="date " /> + <param name="DatePattern" value='"."yyyy-MM-dd".log"' /> + <!-- 書き込み時の設定(追加 or 上書き、出力エンコーディング) --> + <param name="AppendToFile" value="true" /> + <encoding value="utf-8" /> + <!-- メッセージのフォーマット --> + <layout type="log4net.Layout.PatternLayout"> + <param name="ConversionPattern" value="[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline" /> + </layout> + <!-- フィルタ(範囲)の設定 --> + <filter type="log4net.Filter.LevelRangeFilter"> + <levelMin value="DEBUG" /> + <levelMax value="FATAL" /> + </filter> + </appender> + <!-- コンソール出力用アペンダ --> + <appender name="OPERATION2" type="log4net.Appender.ConsoleAppender"> + <!-- メッセージのフォーマット --> + <layout type="log4net.Layout.PatternLayout"> + <param name="ConversionPattern" value="[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline" /> + </layout> + <!-- フィルタ(範囲)の設定 --> + <filter type="log4net.Filter.LevelRangeFilter"> + <levelMin value="DEBUG" /> + <levelMax value="FATAL" /> + </filter> + </appender> + + <!-- + ロガーを作成する。 + ロガーにはロガー名、アペンダ、出力レベルを設定する。 + 特定のレベルのログだけを出力したい場合には、 + フィルタ(範囲)機能を使用する。 + --> + <!-- + ↑出力レベル・高 + Fatal システム停止するような致命的な障害 + Error システム停止はしないが、問題となる障害 + Warn 障害ではない注意警告 + Info 操作ログなどの情報 + Debug 開発用のデバッグメッセージ + All すべてのレベル + ↓出力レベル・低 + --> + <!-- + Rootロガーを作成する(アペンダ×n、出力レベルを設定する)。 + 全てのログがRootロガーに出力される。 + --> + <root> + </root> + <!-- + 個別のロガーを作成する(ロガー名、アペンダ×n、出力レベルを設定する)。 + プログラムから個別のロガー名を指定したログは、個別のロガーで処理される。 + --> + <logger name="ACCESS"> + <level value="All" /> + <!--appender-ref ref="ACCESS1" /--> + <appender-ref ref="ACCESS2" /> + </logger> + <logger name="SQLTRACE"> + <level value="All" /> + <!--appender-ref ref="SQLTRACE1" /--> + <appender-ref ref="SQLTRACE2" /> + </logger> + <logger name="OPERATION"> + <level value="All" /> + <!--appender-ref ref="OPERATION1" /--> + <appender-ref ref="OPERATION2" /> + </logger> +</log4net> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessCore100.sln b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessCore100.sln new file mode 100644 index 000000000..98172b8a6 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessCore100.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11205.157 d18.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestDataAccessCore", "core100\TestDataAccessCore.csproj", "{7285AED0-058A-4C30-A3E5-83BF430AEF47}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7285AED0-058A-4C30-A3E5-83BF430AEF47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7285AED0-058A-4C30-A3E5-83BF430AEF47}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7285AED0-058A-4C30-A3E5-83BF430AEF47}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7285AED0-058A-4C30-A3E5-83BF430AEF47}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8BA454DE-0D7E-4FBC-9034-33600A3F13DB} + EndGlobalSection +EndGlobal diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessDpq.cs b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessDpq.cs new file mode 100644 index 000000000..9b48ae06a --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessDpq.cs @@ -0,0 +1,745 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestDataAccessDpq +//* クラス日本語名 :動的パラメタライズドクエリのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#520) +//* 2026/08/06 玄人 幸道 IF/ELSE・LIST・DELCMA・作用範囲・SQL生成を追加 +//********************************************************************************** + +using System; +using System.Collections; +using System.Data; +using System.IO; +using System.Text; + +using Touryo.Infrastructure.Public.Db; +using Touryo.Infrastructure.Public.Diagnostics; + +namespace TestDataAccess +{ + /// <summary>動的パラメタライズドクエリのテスト</summary> + /// <remarks> + /// 動的 SQL(.xml)は、**設定したパラメタによって SQL の形が変わる**(#520)。 + /// + /// <確認する観点> + /// 1. <WHERE> / <IF> の組み合わせ … 条件の増減と、先頭 AND の除去 + /// 2. <IF> / <ELSE> の 3 状態 … **「未設定」と「null を設定」は別物** + /// 3. <LIST> … IN 句への自動展開 + /// 4. パラメタの作用範囲 … テキスト内は全タグ、タグ内は最初の 1 タグ + /// 5. <DELCMA> / <INSCOL> … 要素が消えたときのカンマ処理 + /// 6. 組み立て結果そのもの … ExecGenerateSQL(実行しない) + /// + /// <1〜5 を件数で見る理由> + /// DBMS ごとに型や表示が変わるため、値を出すと差分になる。件数なら 4 DBMS で同じ。 + /// + /// <6 を ExecGenerateSQL で見る理由> + /// <SELECT>/<CASE> の分岐や比較演算子のエスケープは、 + /// **実行しなくても組み立て結果を見れば分かる**。表の中身に依存せず、 + /// 期待値も安定する。IsDPQ(動的として扱われたか)も同時に見る。 + /// + /// <XML を実行時に書き出す理由> + /// パラメタの先頭記号が DBMS で異なり(Oracle は「:」、他は「@」)、 + /// 囲い文字も異なるため、共有の SQL 置き場に置くと DBMS 分の重複になる。 + /// + /// <記法の参考> + /// root/files/resource/Test/dpq/query/ に DPQuery_Tool 用の資産がある。 + /// あちらの <PARAM> タグはツールが値を与えるためのもので、 + /// 実行時は SetParameter / SetUserParameter で与える。 + /// </remarks> + public class TestDataAccessDpq + { + #region public + + /// <summary>Root</summary> + /// <param name="daps">対象のデータ プロバイダ</param> + public static void Root(string[] daps) + { + foreach (string dap in daps) + { + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestDataAccessDpq.TestOneProvider(dap); + } + } + + #endregion + + #region private + + /// <summary>データ プロバイダ 1 つ分のテスト</summary> + /// <param name="dap">データ プロバイダの識別子</param> + private static void TestOneProvider(string dap) + { + MyDebug.OutputDebugAndConsole("[" + dap + "]"); + + BaseDam dam = DataProvider.CreateDam(dap); + + if (dam == null) + { + MyDebug.OutputDebugAndConsole("- 未対応のデータ プロバイダのため、実行しない。"); + return; + } + + try + { + dam.ConnectionOpen(DataProvider.GetConnectionString(dap)); + + try + { + TestTable.Drop(dam, dap); + TestTable.Create(dam, dap); + + // 4 行目は Note が NULL。<ELSE>(IS NULL 側)の確認に使う。 + TestTable.InsertRow(dam, dap, 1, 10, 999, "x"); + TestTable.InsertRow(dam, dap, 2, 20, 888, "y"); + TestTable.InsertRow(dam, dap, 3, 30, 777, "z"); + TestTable.InsertRow(dam, dap, 4, 40, 666, null); + + TestDataAccessDpq.TestWhereIf(dam, dap); + TestDataAccessDpq.TestIfElse(dam, dap); + TestDataAccessDpq.TestList(dam, dap); + TestDataAccessDpq.TestParamScope(dam, dap); + TestDataAccessDpq.TestDelcmaInscol(dam, dap); + TestDataAccessDpq.TestGenerateOnly(dam, dap); + } + finally + { + TestTable.Drop(dam, dap); + dam.ConnectionClose(); + } + } + catch (Exception ex) + { + MyDebug.OutputDebugAndConsole("- 例外 : " + ex.GetType().FullName); + } + } + + #region 1. WHERE / IF の組み合わせ + + /// <summary><WHERE> / <IF> の組み合わせ</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// IF が 2 つなので、設定/未設定の組み合わせは 2 の 2 乗 = 4 通り。 + /// 全数を通したうえで、AND であることを判別する 1 件を足している。 + /// </remarks> + private static void TestWhereIf(BaseDam dam, string dap) + { + MyDebug.OutputDebugAndConsole("- WHERE / IF の組み合わせ"); + + string sign = TestDataAccessDpq.Sign(dap); + string xml = + " SELECT " + TestDataAccessDpq.Col(dap, "OrderID") + " FROM " + TestTable.Quoted(dap) + "\n" + + " <WHERE>\n" + + " WHERE\n" + + " <IF>AND " + TestDataAccessDpq.Col(dap, "OrderID") + " = " + sign + "P1</IF>\n" + + " <IF>AND " + TestDataAccessDpq.Col(dap, "Qty") + " = " + sign + "P2</IF>\n" + + " </WHERE>\n"; + + string path = TestDataAccessDpq.WriteXml(dap, "whereif", xml); + + try + { + // 両方。ただし同じ行を指すため、AND / OR / 片方無視 のいずれでも 1 件になる。 + TestDataAccessDpq.RunCount(dam, path, " 両方指定", "P1", 1, "P2", 999); + + // 指す行をずらす。**AND であることを判別する。** + // AND なら 0 件 / OR なら 2 件 / 片方を無視していれば 1 件 + TestDataAccessDpq.RunCount(dam, path, " 両方指定(不一致)", "P1", 1, "P2", 888); + + // 末尾の IF が落ちる。 + TestDataAccessDpq.RunCount(dam, path, " OrderIDのみ", "P1", 1, "P2", null); + + // **先頭の IF が落ちる。** 残る IF は先頭に AND を持つため、 + // 除去されないと WHERE AND ... で構文エラーになる。 + TestDataAccessDpq.RunCount(dam, path, " Qtyのみ", "P1", null, "P2", 888); + + // WHERE ごと消えて全件(4 件)になる。 + TestDataAccessDpq.RunCount(dam, path, " 指定なし", "P1", null, "P2", null); + } + finally + { + TestDataAccessDpq.DeleteXml(path); + } + } + + #endregion + + #region 2. IF / ELSE の 3 状態 + + /// <summary><IF> / <ELSE> の 3 状態</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// **「未設定」と「null を設定」は別物。** + /// 条件から外したいときに null を渡すと、逆に IS NULL が残って外れない。 + /// この取り違えは実行時エラーにならず、**件数が静かに変わる**ので気付きにくい。 + /// + /// **テキスト内パラメタとタグ内パラメタで、状態の数が違う。** + /// + /// テキスト内(@P3) 値を設定 … IF / null … ELSE / 未設定 … 削除 + /// タグ内(name="F1") true … IF / **false または null** … ELSE / 未設定 … 削除 + /// + /// タグ内には false という状態が増える。両方とも通す。 + /// </remarks> + private static void TestIfElse(BaseDam dam, string dap) + { + string sign = TestDataAccessDpq.Sign(dap); + string col = TestDataAccessDpq.Col(dap, "Note"); + string head = + " SELECT " + TestDataAccessDpq.Col(dap, "OrderID") + " FROM " + TestTable.Quoted(dap) + "\n" + + " <WHERE>\n" + + " WHERE\n"; + + // テキスト内パラメタ : 値 / null / 未設定 + string xmlText = head + + " <IF>AND " + col + " = " + sign + "P3<ELSE>AND " + col + " IS NULL</ELSE></IF>\n" + + " </WHERE>\n"; + + // タグ内パラメタ : true / false / null / 未設定 + // ※ 条件式にパラメタを置かない(タグ内パラメタが有効・無効を決めるため)。 + string xmlTag = head + + " <IF name=\"F1\">AND " + col + " = 'x'<ELSE>AND " + col + " IS NULL</ELSE></IF>\n" + + " </WHERE>\n"; + + string pathText = TestDataAccessDpq.WriteXml(dap, "ifelsetext", xmlText); + string pathTag = TestDataAccessDpq.WriteXml(dap, "ifelsetag", xmlTag); + + try + { + MyDebug.OutputDebugAndConsole("- IF / ELSE(テキスト内パラメタ)"); + + // 値を設定 → IF 側(Note = 'x') + TestDataAccessDpq.RunCountOne(dam, pathText, " 値を設定", "P3", "x"); + + // null を設定 → **ELSE 側(Note IS NULL)** + TestDataAccessDpq.RunCountOne(dam, pathText, " nullを設定", "P3", null); + + // 未設定 → 条件ごと消えて全件 + TestDataAccessDpq.RunCountNone(dam, pathText, " 未設定"); + + MyDebug.OutputDebugAndConsole("- IF / ELSE(タグ内パラメタ)"); + + // **タグ内は false という状態が増える。** false も null も ELSE 側。 + TestDataAccessDpq.RunCountOne(dam, pathTag, " true", "F1", true); + TestDataAccessDpq.RunCountOne(dam, pathTag, " false", "F1", false); + TestDataAccessDpq.RunCountOne(dam, pathTag, " null", "F1", null); + TestDataAccessDpq.RunCountNone(dam, pathTag, " 未設定"); + } + finally + { + TestDataAccessDpq.DeleteXml(pathText); + TestDataAccessDpq.DeleteXml(pathTag); + } + } + + #endregion + + #region 3. LIST(IN 句) + + /// <summary><LIST>(IN 句への展開)</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// 1 つのパラメタ名に複数値を与えると、@名_1, @名_2 … へ自動展開される。 + /// 与えた数がそのまま件数に出るため、展開されているかを件数で判別できる。 + /// </remarks> + private static void TestList(BaseDam dam, string dap) + { + MyDebug.OutputDebugAndConsole("- LIST(IN 句)"); + + string sign = TestDataAccessDpq.Sign(dap); + string xml = + " SELECT " + TestDataAccessDpq.Col(dap, "OrderID") + " FROM " + TestTable.Quoted(dap) + "\n" + + " <WHERE>\n" + + " WHERE\n" + + " <LIST>AND " + TestDataAccessDpq.Col(dap, "OrderID") + " IN (" + sign + "PLIST)</LIST>\n" + + " </WHERE>\n"; + + string path = TestDataAccessDpq.WriteXml(dap, "list", xml); + + try + { + ArrayList two = new ArrayList(); + two.Add(1); + two.Add(3); + TestDataAccessDpq.RunCountOne(dam, path, " 2 値", "PLIST", two); + + ArrayList three = new ArrayList(); + three.Add(1); + three.Add(2); + three.Add(4); + TestDataAccessDpq.RunCountOne(dam, path, " 3 値", "PLIST", three); + } + finally + { + TestDataAccessDpq.DeleteXml(path); + } + } + + #endregion + + #region 4. パラメタの作用範囲 + + /// <summary>テキスト内パラメタとタグ内パラメタの作用範囲</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// **同名を書いたとき、作用する範囲が違う。** + /// テキスト内(@名前) … **同名を書いた全タグ**に作用する + /// タグ内(name 属性) … **最初の 1 タグ**にだけ作用する + /// + /// 判別できるように、2 つの IF が両立しない条件になっている。 + /// 両方に作用すれば 0 件、最初の 1 つだけなら 1 件。 + /// </remarks> + private static void TestParamScope(BaseDam dam, string dap) + { + MyDebug.OutputDebugAndConsole("- パラメタの作用範囲"); + + string sign = TestDataAccessDpq.Sign(dap); + string colOrder = TestDataAccessDpq.Col(dap, "OrderID"); + + // テキスト内 : 同じ @P1 を 2 つの IF に書く。 + // 両方に作用するので、OrderID = 1 かつ OrderID = 2 となり 0 件。 + string xmlText = + " SELECT " + colOrder + " FROM " + TestTable.Quoted(dap) + "\n" + + " <WHERE>\n" + + " WHERE\n" + + " <IF>AND " + colOrder + " = " + sign + "P1</IF>\n" + + " <IF>AND " + colOrder + " = " + sign + "P1 + 1</IF>\n" + + " </WHERE>\n"; + + // タグ内 : 同じ name="F1" を 2 つの IF に書く。 + // 最初の 1 つにしか作用しないので、OrderID = 1 だけが残り 1 件。 + string xmlTag = + " SELECT " + colOrder + " FROM " + TestTable.Quoted(dap) + "\n" + + " <WHERE>\n" + + " WHERE\n" + + " <IF name=\"F1\">AND " + colOrder + " = 1</IF>\n" + + " <IF name=\"F1\">AND " + colOrder + " = 2</IF>\n" + + " </WHERE>\n"; + + string pathText = TestDataAccessDpq.WriteXml(dap, "scopetext", xmlText); + string pathTag = TestDataAccessDpq.WriteXml(dap, "scopetag", xmlTag); + + try + { + TestDataAccessDpq.RunCountOne(dam, pathText, " テキスト内(全タグ)", "P1", 1); + TestDataAccessDpq.RunCountOne(dam, pathTag, " タグ内(最初の1つ)", "F1", true); + } + finally + { + TestDataAccessDpq.DeleteXml(pathText); + TestDataAccessDpq.DeleteXml(pathTag); + } + } + + #endregion + + #region 5. DELCMA / INSCOL + + /// <summary><DELCMA> / <INSCOL>(カンマの処理)</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// 列とその値を対で増減させる。**各要素の末尾にカンマを付けて書き**、 + /// <DELCMA> が前後の余分なカンマを削る。 + /// どの要素が残っても構文が壊れないことを、実際に INSERT して確かめる。 + /// </remarks> + private static void TestDelcmaInscol(BaseDam dam, string dap) + { + MyDebug.OutputDebugAndConsole("- DELCMA / INSCOL"); + + string sign = TestDataAccessDpq.Sign(dap); + string xml = + " INSERT INTO " + TestTable.Quoted(dap) + "\n" + + " (\n" + + " " + TestDataAccessDpq.Col(dap, "OrderID") + ",\n" + + " " + TestDataAccessDpq.Col(dap, "ProductID") + ",\n" + + " <DELCMA>\n" + + " <INSCOL name=\"Qty\">" + TestDataAccessDpq.Col(dap, "Qty") + ",</INSCOL>\n" + + " <INSCOL name=\"Note\">" + TestDataAccessDpq.Col(dap, "Note") + ",</INSCOL>\n" + + " </DELCMA>\n" + + " )\n" + + " VALUES\n" + + " (\n" + + " " + sign + "OrderID,\n" + + " " + sign + "ProductID,\n" + + " <DELCMA>\n" + + " <IF>" + sign + "Qty,</IF>\n" + + " <IF>" + sign + "Note,</IF>\n" + + " </DELCMA>\n" + + " )\n"; + + string path = TestDataAccessDpq.WriteXml(dap, "delcma", xml); + + try + { + // 両方の列を与える。 + TestDataAccessDpq.RunInsert(dam, path, " 両方の列", 5, 50, 555, "v"); + + // 末尾の列を落とす → 列リストと値の両方からカンマごと消える。 + TestDataAccessDpq.RunInsert(dam, path, " Qtyのみ", 6, 60, 666, null); + + // 先頭の列を落とす → 残った要素の先頭カンマが消える。 + TestDataAccessDpq.RunInsert(dam, path, " Noteのみ", 7, 70, -1, "w"); + + MyDebug.OutputDebugAndConsole(" 投入後の件数 : " + TestTable.Count(dam, dap)); + } + finally + { + TestDataAccessDpq.DeleteXml(path); + } + } + + #endregion + + #region 6. 組み立て結果だけを見る(ExecGenerateSQL) + + /// <summary>実行せずに組み立て結果だけを見る</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// ExecGenerateSQL は SQL を組み立てて返すだけで、実行しない。 + /// 分岐の結果やエスケープの扱いは、**表の中身に依存せず組み立て結果で分かる**。 + /// あわせて IsDPQ(動的として扱われたか)を見る。 + /// </remarks> + private static void TestGenerateOnly(BaseDam dam, string dap) + { + MyDebug.OutputDebugAndConsole("- 組み立てのみ(ExecGenerateSQL)"); + + SQLUtility util = new SQLUtility(DataProvider.GetDbmsType(dap)); + string sign = TestDataAccessDpq.Sign(dap); + string colQty = TestDataAccessDpq.Col(dap, "Qty"); + + // ---- SELECT / CASE / DEFAULT : 値による分岐 ---- + string xmlSelect = + " <SELECT name=\"SEL\">\n" + + " <CASE value=\"a1\">SELECT 1 AS X</CASE>\n" + + " <CASE value=\"b2\">SELECT 2 AS X</CASE>\n" + + " <DEFAULT>SELECT 9 AS X</DEFAULT>\n" + + " </SELECT>\n"; + + string pathSelect = TestDataAccessDpq.WriteXml(dap, "select", xmlSelect); + + // ---- 比較演算子 : < は < と CDATA の 2 通りで書ける ---- + // ※ どちらの IF にも**テキスト内パラメタを置くこと。** + //   パラメタも name 属性も無い IF は ArgumentException になる + //   (BaseDam が「どちらで有効・無効を決めるか」を判断できないため)。 + //   CDATA の中のパラメタも認識される。 + string xmlLt = + " SELECT " + TestDataAccessDpq.Col(dap, "OrderID") + " FROM " + TestTable.Quoted(dap) + "\n" + + " <WHERE>\n" + + " WHERE\n" + + " <IF>AND " + colQty + " < " + sign + "P1</IF>\n" + + " <IF><![CDATA[AND " + colQty + " > " + sign + "P2]]></IF>\n" + + " </WHERE>\n"; + + string pathLt = TestDataAccessDpq.WriteXml(dap, "lt", xmlLt); + + // ---- JOIN / SUB : 結合・副問い合わせを丸ごと出し入れする ---- + // **実行しないので、存在しない表を書いてよい。** + // 表を 1 つしか用意していなくても、組み立て結果は確認できる。 + // + // ※ 無効にしたいときは**設定しない**(未設定=ブロック削除)。 + //   false や null は <ELSE> が無いとエラーになる。 + string other = DataProvider.Quote(dap, "OtherTable"); + string xmlJoin = + " SELECT o." + TestDataAccessDpq.Col(dap, "OrderID") + + " FROM " + TestTable.Quoted(dap) + " o\n" + + " <JOIN name=\"J1\">\n" + + " INNER JOIN " + other + " t ON o." + TestDataAccessDpq.Col(dap, "OrderID") + + " = t." + TestDataAccessDpq.Col(dap, "OrderID") + "\n" + + " </JOIN>\n" + + " <WHERE>\n" + + " WHERE\n" + + " <IF>AND o." + colQty + " = " + sign + "P1</IF>\n" + + " <SUB name=\"S1\">AND o." + TestDataAccessDpq.Col(dap, "OrderID") + + " IN (SELECT " + TestDataAccessDpq.Col(dap, "OrderID") + " FROM " + other + ")</SUB>\n" + + " </WHERE>\n"; + + string pathJoin = TestDataAccessDpq.WriteXml(dap, "join", xmlJoin); + + try + { + TestDataAccessDpq.GenerateOne(dam, util, pathSelect, " CASE(a1)", "SEL", "a1"); + TestDataAccessDpq.GenerateOne(dam, util, pathSelect, " CASE(b2)", "SEL", "b2"); + TestDataAccessDpq.GenerateOne(dam, util, pathSelect, " DEFAULT", "SEL", "zz"); + + // < の側と CDATA の側を、両方とも有効にして組み立てる。 + dam.SetSqlByFile(pathLt); + dam.SetParameter("P1", 900); + dam.SetParameter("P2", 100); + TestDataAccessDpq.OutputSql(dam, util, " 比較演算子"); + + // JOIN と SUB を両方入れる。 + dam.SetSqlByFile(pathJoin); + dam.SetParameter("J1", true); + dam.SetParameter("S1", true); + dam.SetParameter("P1", 999); + TestDataAccessDpq.OutputSql(dam, util, " JOIN+SUB あり"); + + // JOIN だけ入れる(SUB は設定しない=ブロックごと削除)。 + dam.SetSqlByFile(pathJoin); + dam.SetParameter("J1", true); + dam.SetParameter("P1", 999); + TestDataAccessDpq.OutputSql(dam, util, " JOIN のみ"); + + // どちらも設定しない → 両方消える。IF も落ちて WHERE ごと消える。 + dam.SetSqlByFile(pathJoin); + TestDataAccessDpq.OutputSql(dam, util, " JOIN+SUB なし"); + } + catch (NotImplementedException) + { + // **ExecGenerateSQL を実装しているのは DamSqlSvr だけ。** + // 他のデータ プロバイダは NotImplementedException を投げる。 + // 組み立ての結果は DBMS によらないため、SQL Server で見れば足りる。 + MyDebug.OutputDebugAndConsole(" ExecGenerateSQL : このデータ プロバイダでは未実装"); + } + finally + { + TestDataAccessDpq.DeleteXml(pathSelect); + TestDataAccessDpq.DeleteXml(pathJoin); + } + + // ---- IsDPQ : 動的として扱われたか ---- + // 拡張子で切り替わる(.xml は動的、.sql は静的)。 + // ※ **整形式でない XML はフォールバックせず例外**になる。 + //   「書式が不正なら静的にフォールバック」はタグの綴り等の話で、 + //   XML として壊れている場合は対象外。ここでは .sql と対比する。 + string pathNotDpq = TestDataAccessDpq.WriteFile( + Path.Combine(Path.GetTempPath(), "TestDataAccess_notdpq_" + dap + ".sql"), + "SELECT 1 AS X\n"); + + try + { + dam.SetSqlByFile(pathLt); + MyDebug.OutputDebugAndConsole(" IsDPQ(タグあり): " + dam.IsDPQ); + + dam.SetSqlByFile(pathNotDpq); + MyDebug.OutputDebugAndConsole(" IsDPQ(タグなし): " + dam.IsDPQ); + } + finally + { + // pathLt はここまで使うため、上の finally では消していない。 + TestDataAccessDpq.DeleteXml(pathLt); + TestDataAccessDpq.DeleteXml(pathNotDpq); + } + } + + /// <summary>組み立てた SQL を 1 行にして出力する</summary> + /// <param name="dam">BaseDam</param> + /// <param name="util">SQLUtility</param> + /// <param name="path">動的 SQL のパス</param> + /// <param name="caseName">ケース名</param> + /// <param name="paramName">パラメタ名</param> + /// <param name="paramValue">パラメタの値</param> + private static void GenerateOne( + BaseDam dam, SQLUtility util, string path, string caseName, + string paramName, object paramValue) + { + dam.SetSqlByFile(path); + dam.SetParameter(paramName, paramValue); + + TestDataAccessDpq.OutputSql(dam, util, caseName); + } + + /// <summary>組み立てた SQL を 1 行にして出力する</summary> + /// <param name="dam">BaseDam</param> + /// <param name="util">SQLUtility</param> + /// <param name="caseName">ケース名</param> + private static void OutputSql(BaseDam dam, SQLUtility util, string caseName) + { + // 改行・連続空白を畳んで、環境によらず同じ 1 行にする。 + string sql = dam.ExecGenerateSQL(util); + sql = System.Text.RegularExpressions.Regex.Replace(sql, @"\s+", " ").Trim(); + + MyDebug.OutputDebugAndConsole(caseName + " : " + sql); + } + + #endregion + + #region 実行のヘルパ + + /// <summary>2 パラメタを与えて件数を出す</summary> + /// <param name="dam">BaseDam</param> + /// <param name="path">動的 SQL のパス</param> + /// <param name="caseName">ケース名</param> + /// <param name="name1">パラメタ名 1</param> + /// <param name="value1">値 1(null なら設定しない)</param> + /// <param name="name2">パラメタ名 2</param> + /// <param name="value2">値 2(null なら設定しない)</param> + private static void RunCount( + BaseDam dam, string path, string caseName, + string name1, object value1, string name2, object value2) + { + dam.SetSqlByFile(path); + + if (value1 != null) { dam.SetParameter(name1, value1); } + if (value2 != null) { dam.SetParameter(name2, value2); } + + TestDataAccessDpq.Output(dam, caseName); + } + + /// <summary>1 パラメタを与えて件数を出す</summary> + /// <param name="dam">BaseDam</param> + /// <param name="path">動的 SQL のパス</param> + /// <param name="caseName">ケース名</param> + /// <param name="name">パラメタ名</param> + /// <param name="value">値(null も「null を設定」として渡す)</param> + /// <remarks> + /// **null は「設定しない」ではなく「null を設定」。** + /// 設定しないケースは RunCountNone を使う。 + /// </remarks> + private static void RunCountOne( + BaseDam dam, string path, string caseName, string name, object value) + { + dam.SetSqlByFile(path); + dam.SetParameter(name, value); + + TestDataAccessDpq.Output(dam, caseName); + } + + /// <summary>パラメタを与えずに件数を出す</summary> + /// <param name="dam">BaseDam</param> + /// <param name="path">動的 SQL のパス</param> + /// <param name="caseName">ケース名</param> + private static void RunCountNone(BaseDam dam, string path, string caseName) + { + dam.SetSqlByFile(path); + + TestDataAccessDpq.Output(dam, caseName); + } + + /// <summary>件数を出力する</summary> + /// <param name="dam">BaseDam</param> + /// <param name="caseName">ケース名</param> + private static void Output(BaseDam dam, string caseName) + { + DataTable dt = new DataTable(); + dam.ExecSelectFill_DT(dt); + + MyDebug.OutputDebugAndConsole(caseName + " : " + dt.Rows.Count + " 件"); + } + + /// <summary>INSERT を実行する</summary> + /// <param name="dam">BaseDam</param> + /// <param name="path">動的 SQL のパス</param> + /// <param name="caseName">ケース名</param> + /// <param name="orderId">OrderID</param> + /// <param name="productId">ProductID</param> + /// <param name="qty">Qty(-1 なら設定しない)</param> + /// <param name="note">Note(null なら設定しない)</param> + private static void RunInsert( + BaseDam dam, string path, string caseName, + int orderId, int productId, int qty, string note) + { + dam.SetSqlByFile(path); + + dam.SetParameter("OrderID", orderId); + dam.SetParameter("ProductID", productId); + + if (qty != -1) { dam.SetParameter("Qty", qty); } + if (note != null) { dam.SetParameter("Note", note); } + + MyDebug.OutputDebugAndConsole( + caseName + " : " + dam.ExecInsUpDel_NonQuery() + " 件"); + } + + #endregion + + #region XML のヘルパ + + /// <summary>パラメタの先頭記号</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <returns>先頭記号</returns> + /// <remarks>Oracle だけ「:」で、他は「@」。</remarks> + private static string Sign(string dap) + { + return (dap == "ODP") ? ":" : "@"; + } + + /// <summary>囲った列名</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <param name="name">列名</param> + /// <returns>囲った列名</returns> + private static string Col(string dap, string name) + { + return DataProvider.Quote(dap, name); + } + + /// <summary>動的 SQL(.xml)を書き出す</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <param name="name">ファイル名の一部</param> + /// <param name="inner">ROOT の中身</param> + /// <returns>書き出したパス</returns> + private static string WriteXml(string dap, string name, string inner) + { + StringBuilder sb = new StringBuilder(); + + sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); + sb.Append("<ROOT>\n"); + sb.Append(inner); + sb.Append("</ROOT>\n"); + + return TestDataAccessDpq.WriteRaw(dap, name, sb.ToString()); + } + + /// <summary>ファイルをそのまま書き出す</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <param name="name">ファイル名の一部</param> + /// <param name="text">中身</param> + /// <returns>書き出したパス</returns> + private static string WriteRaw(string dap, string name, string text) + { + return TestDataAccessDpq.WriteFile( + Path.Combine(Path.GetTempPath(), "TestDataAccess_" + name + "_" + dap + ".xml"), + text); + } + + /// <summary>指定したパスへ書き出す</summary> + /// <param name="path">パス</param> + /// <param name="text">中身</param> + /// <returns>書き出したパス</returns> + private static string WriteFile(string path, string text) + { + File.WriteAllText(path, text, new UTF8Encoding(false)); + + return path; + } + + /// <summary>書き出した XML を消す</summary> + /// <param name="path">パス</param> + private static void DeleteXml(string path) + { + if (path != "" && File.Exists(path)) + { + File.Delete(path); + } + } + + #endregion + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessFx48.sln b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessFx48.sln new file mode 100644 index 000000000..a20d9c4d1 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessFx48.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11205.157 d18.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestDataAccessFx", "net48\TestDataAccessFx.csproj", "{100C9173-E92B-410D-9C93-9C0EBF2019DB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {100C9173-E92B-410D-9C93-9C0EBF2019DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {100C9173-E92B-410D-9C93-9C0EBF2019DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {100C9173-E92B-410D-9C93-9C0EBF2019DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {100C9173-E92B-410D-9C93-9C0EBF2019DB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {47BAF598-A579-44AD-8873-D234AA989A7D} + EndGlobalSection +EndGlobal diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessPattern.cs b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessPattern.cs new file mode 100644 index 000000000..5eaad7fd8 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessPattern.cs @@ -0,0 +1,174 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestDataAccessPattern +//* クラス日本語名 :データ アクセスのパターンのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/05 玄人 幸道 新規作成(#520) +//********************************************************************************** + +using System; +using System.Data; +using System.IO; + +using Touryo.Infrastructure.Public.Db; +using Touryo.Infrastructure.Public.Diagnostics; +using Touryo.Infrastructure.Public.Util; + +namespace TestDataAccess +{ + /// <summary>データ アクセスのパターンのテスト</summary> + /// <remarks> + /// Dam の実行系メソッドを、同じ問い合わせに対して一通り呼ぶ(#520)。 + /// + /// <Dam を直接使う理由> + /// B層・D層を経由すると、引数クラス・戻り値クラス・LayerB / LayerD の一式が要る。 + /// ここで見たいのは「データ プロバイダごとの実行系の挙動」なので、Dam を直接使う。 + /// B層・D層を通した確認は TestBatch(SimpleBatch)が担う。 + /// + /// <結果の決定性> + /// Shippers は 3 件(初期状態)。件数だけを出力するため、DBMS が違っても同じ結果になる。 + /// 例外は型名だけを出力する。メッセージは OS の表示言語で変わり、 + /// CI(英語)と開発環境(日本語)で差分になるため。 + /// </remarks> + public class TestDataAccessPattern + { + #region public + + /// <summary>Root</summary> + /// <param name="daps">対象のデータ プロバイダ</param> + public static void Root(string[] daps) + { + foreach (string dap in daps) + { + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestDataAccessPattern.TestOneProvider(dap); + } + } + + #endregion + + #region private + + /// <summary>データ プロバイダ 1 つ分のテスト</summary> + /// <param name="dap">データ プロバイダの識別子</param> + private static void TestOneProvider(string dap) + { + MyDebug.OutputDebugAndConsole("[" + dap + "]"); + + BaseDam dam = DataProvider.CreateDam(dap); + + if (dam == null) + { + // このターゲット フレームワークでは使えないデータ プロバイダ。 + MyDebug.OutputDebugAndConsole("- 未対応のデータ プロバイダのため、実行しない。"); + return; + } + + try + { + dam.ConnectionOpen(DataProvider.GetConnectionString(dap)); + + try + { + TestDataAccessPattern.TestExecPatterns(dam); + TestDataAccessPattern.TestStaticSql(dam, dap); + } + finally + { + dam.ConnectionClose(); + } + } + catch (Exception ex) + { + // 接続できない場合もここに来る(LOCAL モードでコンテナが起動していない等)。 + // メッセージは環境で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole("- 例外 : " + ex.GetType().FullName); + } + } + + /// <summary>実行系メソッドを一通り呼ぶ</summary> + /// <param name="dam">BaseDam</param> + private static void TestExecPatterns(BaseDam dam) + { + // 件数を返す(スカラ) + dam.SetSqlByCommand("SELECT COUNT(*) FROM Shippers"); + MyDebug.OutputDebugAndConsole("- ExecSelectScalar : " + Convert.ToInt32(dam.ExecSelectScalar())); + + // データテーブルに受ける + DataTable dt = new DataTable(); + dam.SetSqlByCommand("SELECT * FROM Shippers"); + dam.ExecSelectFill_DT(dt); + MyDebug.OutputDebugAndConsole("- ExecSelectFill_DT : " + dt.Rows.Count); + + // データセットに受ける + DataSet ds = new DataSet(); + dam.SetSqlByCommand("SELECT * FROM Shippers"); + dam.ExecSelectFill_DS(ds); + MyDebug.OutputDebugAndConsole("- ExecSelectFill_DS : " + ds.Tables[0].Rows.Count); + + // データリーダで受ける + dam.SetSqlByCommand("SELECT * FROM Shippers"); + int count = 0; + IDataReader idr = dam.ExecSelect_DR(); + try + { + while (idr.Read()) + { + count++; + } + } + finally + { + idr.Close(); + } + MyDebug.OutputDebugAndConsole("- ExecSelect_DR : " + count); + } + + /// <summary>静的SQL(ファイル)を読んで実行する</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// SQL は DBMS ごとのフォルダに分かれている。 + /// BaseDam.SetSqlByFile はパスを連結しないため(連結するのは MyBaseDao.SetSqlByFile2)、 + /// ここで組み立てる。 + /// </remarks> + private static void TestStaticSql(BaseDam dam, string dap) + { + string path = Path.Combine( + GetConfigParameter.GetConfigValue("SqlTextFilePath"), + DataProvider.GetSqlFolder(dap), + "ShipperCount.sql"); + + if (!File.Exists(path)) + { + MyDebug.OutputDebugAndConsole("- SetSqlByFile : SQLファイルが無い。"); + return; + } + + dam.SetSqlByFile(path); + MyDebug.OutputDebugAndConsole("- SetSqlByFile + Scalar : " + Convert.ToInt32(dam.ExecSelectScalar())); + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessUpdate.cs b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessUpdate.cs new file mode 100644 index 000000000..7dfac08db --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestDataAccessUpdate.cs @@ -0,0 +1,290 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestDataAccessUpdate +//* クラス日本語名 :更新系のテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#520) +//********************************************************************************** + +using System; +using System.Data; + +using Touryo.Infrastructure.Public.Db; +using Touryo.Infrastructure.Public.Diagnostics; + +namespace TestDataAccess +{ + /// <summary>更新系のテスト</summary> + /// <remarks> + /// INSERT・UPDATE・DELETE とトランザクションを、対象 DBMS ごとに確認する(#520)。 + /// あわせて **SQLUtility が生成した SQL を実際に実行**し、結果まで検証する。 + /// + /// <専用の表を作る理由> + /// Northwind の表を更新すると、他のテスト(SimpleBatch・3_SmokeTest.ps1)の前提が壊れる。 + /// このテストは自分で表を作り、最後に落とす。**既存のデータには一切触れない。** + /// + /// <SQLUtility を実 DB で確認する理由> + /// #515 は「生成された SQL が構文として妥当でも、**誤った行に誤った値が入る**」 + /// という不具合だった。生成結果の目視だけでは、この種の誤りは見つけにくい。 + /// ここでは更新対象外の行を 1 件混ぜ、**無傷であること**まで確認する。 + /// </remarks> + public class TestDataAccessUpdate + { + #region public + + /// <summary>Root</summary> + /// <param name="daps">対象のデータ プロバイダ</param> + public static void Root(string[] daps) + { + foreach (string dap in daps) + { + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + TestDataAccessUpdate.TestOneProvider(dap); + } + } + + #endregion + + #region private + + /// <summary>データ プロバイダ 1 つ分のテスト</summary> + /// <param name="dap">データ プロバイダの識別子</param> + private static void TestOneProvider(string dap) + { + MyDebug.OutputDebugAndConsole("[" + dap + "]"); + + BaseDam dam = DataProvider.CreateDam(dap); + + if (dam == null) + { + MyDebug.OutputDebugAndConsole("- 未対応のデータ プロバイダのため、実行しない。"); + return; + } + + try + { + dam.ConnectionOpen(DataProvider.GetConnectionString(dap)); + + try + { + // DDL は Oracle では暗黙にコミットされるため、トランザクションの外で行う。 + TestTable.Drop(dam, dap); + TestTable.Create(dam, dap); + + TestDataAccessUpdate.TestInsert(dam, dap); + TestDataAccessUpdate.TestUpdateBySQLUtility(dam, dap); + TestDataAccessUpdate.TestTransaction(dam, dap); + TestDataAccessUpdate.TestDelete(dam, dap); + } + finally + { + // 失敗しても表を残さない。 + TestTable.Drop(dam, dap); + dam.ConnectionClose(); + } + } + catch (Exception ex) + { + // メッセージは OS の表示言語で変わるため、型名だけを出す。 + MyDebug.OutputDebugAndConsole("- 例外 : " + ex.GetType().FullName); + } + } + + #region 各テスト + + /// <summary>INSERT(SQLUtility が生成したパーツを実行する)</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + private static void TestInsert(BaseDam dam, string dap) + { + // 3 件目は更新対象に含めない。UPDATE で無傷であることを確認するため。 + DataTable dt = TestDataAccessUpdate.CreateSourceTable(true); + + SQLUtility util = new SQLUtility(DataProvider.GetDbmsType(dap)); + string[] parts = util.GetInsertSQLParts(dt); + + // parts[0] が列リスト、parts[1] 以降が値の並び。 + int total = 0; + for (int i = 1; i < parts.Length; i++) + { + dam.SetSqlByCommand( + "INSERT INTO " + TestTable.Quoted(dap) + + " " + parts[0] + " VALUES " + parts[i]); + total += dam.ExecInsUpDel_NonQuery(); + } + + MyDebug.OutputDebugAndConsole("- INSERT(GetInsertSQLParts) : " + total + " 件"); + TestDataAccessUpdate.OutputRows(dam, dap, " 投入後"); + } + + /// <summary>UPDATE(SQLUtility が生成したパーツを実行する)</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// #515 の再発を実 DB で検知する。 + /// 更新するのは (1,10) と (2,20) の 2 件だけで、(3,30) は対象外。 + /// 複合主キーの扱いを誤ると、対象外の行が巻き込まれるか、値が入れ替わる。 + /// </remarks> + private static void TestUpdateBySQLUtility(BaseDam dam, string dap) + { + DataTable dt = TestDataAccessUpdate.CreateSourceTable(false); + + SQLUtility util = new SQLUtility(DataProvider.GetDbmsType(dap)); + string[] parts = util.GetUpdateSQLParts(dt, new string[] { "OrderID", "ProductID" }); + + int total = 0; + foreach (string part in parts) + { + dam.SetSqlByCommand("UPDATE " + TestTable.Quoted(dap) + " " + part); + total += dam.ExecInsUpDel_NonQuery(); + } + + MyDebug.OutputDebugAndConsole("- UPDATE(GetUpdateSQLParts) : " + total + " 件"); + TestDataAccessUpdate.OutputRows(dam, dap, " 更新後"); + } + + /// <summary>トランザクション(ロールバックとコミット)</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + private static void TestTransaction(BaseDam dam, string dap) + { + string table = TestTable.Quoted(dap); + + // ロールバック : 全件消してから戻す。件数が元に戻ること。 + dam.BeginTransaction(DbEnum.IsolationLevelEnum.ReadCommitted); + dam.SetSqlByCommand("DELETE FROM " + table); + dam.ExecInsUpDel_NonQuery(); + dam.RollbackTransaction(); + MyDebug.OutputDebugAndConsole("- ロールバック後の件数 : " + TestTable.Count(dam, dap)); + + // コミット : 1 件消して確定する。件数が減ったままであること。 + dam.BeginTransaction(DbEnum.IsolationLevelEnum.ReadCommitted); + dam.SetSqlByCommand( + "DELETE FROM " + table + + " WHERE " + DataProvider.Quote(dap, "OrderID") + " = 3"); + dam.ExecInsUpDel_NonQuery(); + dam.CommitTransaction(); + MyDebug.OutputDebugAndConsole("- コミット後の件数 : " + TestTable.Count(dam, dap)); + } + + /// <summary>DELETE</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + private static void TestDelete(BaseDam dam, string dap) + { + dam.SetSqlByCommand("DELETE FROM " + TestTable.Quoted(dap)); + MyDebug.OutputDebugAndConsole("- DELETE : " + dam.ExecInsUpDel_NonQuery() + " 件"); + MyDebug.OutputDebugAndConsole("- 削除後の件数 : " + TestTable.Count(dam, dap)); + } + + #endregion + + #region ヘルパ + + /// <summary>全行を出力する</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <param name="caption">見出し</param> + /// <remarks> + /// DBMS によって数値の型が異なる(Oracle の NUMBER は decimal になる)ため、 + /// 明示的に変換してから出力する。並び順も固定する。 + /// </remarks> + private static void OutputRows(BaseDam dam, string dap, string caption) + { + DataTable dt = new DataTable(); + + dam.SetSqlByCommand( + "SELECT " + DataProvider.Quote(dap, "OrderID") + + ", " + DataProvider.Quote(dap, "ProductID") + + ", " + DataProvider.Quote(dap, "Qty") + + ", " + DataProvider.Quote(dap, "Note") + + " FROM " + TestTable.Quoted(dap) + + " ORDER BY " + DataProvider.Quote(dap, "OrderID")); + + dam.ExecSelectFill_DT(dt); + + foreach (DataRow dr in dt.Rows) + { + MyDebug.OutputDebugAndConsole( + caption + " : " + + Convert.ToInt32(dr["OrderID"]) + ", " + + Convert.ToInt32(dr["ProductID"]) + ", " + + Convert.ToInt32(dr["Qty"]) + ", " + + Convert.ToString(dr["Note"])); + } + } + + /// <summary>テスト データの DataTable を生成する</summary> + /// <param name="isForInsert">投入用(3 件)か、更新用(2 件)か</param> + /// <returns>DataTable</returns> + /// <remarks> + /// 投入用の 3 件目 (3,30) は更新対象に含めない。 + /// 更新後も 777,'z' のままであることで、WHERE 句が正しいと分かる。 + /// </remarks> + private static DataTable CreateSourceTable(bool isForInsert) + { + DataTable dt = new DataTable(); + + dt.Columns.Add("OrderID", typeof(object)); + dt.Columns.Add("ProductID", typeof(object)); + dt.Columns.Add("Qty", typeof(object)); + dt.Columns.Add("Note", typeof(object)); + + if (isForInsert) + { + TestDataAccessUpdate.AddRow(dt, 1, 10, 999, "x"); + TestDataAccessUpdate.AddRow(dt, 2, 20, 888, "y"); + TestDataAccessUpdate.AddRow(dt, 3, 30, 777, "z"); + } + else + { + TestDataAccessUpdate.AddRow(dt, 1, 10, 100, "a"); + TestDataAccessUpdate.AddRow(dt, 2, 20, 200, "b"); + } + + return dt; + } + + /// <summary>DataTable に 1 行足す</summary> + /// <param name="dt">DataTable</param> + /// <param name="orderId">OrderID</param> + /// <param name="productId">ProductID</param> + /// <param name="qty">Qty</param> + /// <param name="note">Note</param> + private static void AddRow(DataTable dt, int orderId, int productId, int qty, string note) + { + DataRow dr = dt.NewRow(); + + dr["OrderID"] = orderId; + dr["ProductID"] = productId; + dr["Qty"] = qty; + dr["Note"] = note; + + dt.Rows.Add(dr); + } + + #endregion + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/TestSQLUtility.cs b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestSQLUtility.cs new file mode 100644 index 000000000..705df931b --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestSQLUtility.cs @@ -0,0 +1,199 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestSQLUtility +//* クラス日本語名 :SQLUtilityのテスト +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/02 玄人 幸道 新規作成(#515) +//* 2026/08/05 玄人 幸道 TestCodeから移設(#520) +//********************************************************************************** +using System; +using System.Data; + +using Touryo.Infrastructure.Public.Db; +using Touryo.Infrastructure.Public.Diagnostics; + +namespace TestDataAccess +{ + /// <summary>SQLUtilityのテスト</summary> + /// <remarks> + /// 生成されるSQLは、目視しないと誤りに気付けない。 + /// 特にPostgreSQL・MySQL向けの一括UPDATE(CASE ... WHEN ... THEN)は、 + /// 複合主キーで誤った行に誤った値を書き込む不具合があった(#515)。 + /// このため、生成結果を結果ファイルに残して比較できるようにする。 + /// </remarks> + public class TestSQLUtility + { + #region public + + /// <summary>Root</summary> + public static void Root() + { + TestSQLUtility.TestGetUpdateSQLParts(); + + MyDebug.OutputDebugAndConsole("----------------------------------------------------------------------------------------------------"); + + TestSQLUtility.TestGetInsertSQLParts(); + } + + #endregion + + #region private + + /// <summary>Update系SQLのパーツ生成のテスト</summary> + private static void TestGetUpdateSQLParts() + { + MyDebug.OutputDebugAndConsole("SQLUtility.GetUpdateSQLParts"); + + // 単一主キー + // ・PostgreSQL・MySQLは1文にまとめ、それ以外は1行1文になる。 + DataTable dtSingle = TestSQLUtility.CreateOrderTable(false); + TestSQLUtility.OutputUpdateSQLParts("単一主キー", dtSingle, new string[] { "OrderID" }); + + // 複合主キー + // ・WHENとWHEREが主キーの「組み合わせ」になっていること。 + // ・列ごとに独立していると、WHEREが直積になって対象外の行に一致し、 + // CASEも先に一致した枝が勝つため、誤った行に誤った値が入る(#515)。 + DataTable dtComposite = TestSQLUtility.CreateOrderTable(true); + TestSQLUtility.OutputUpdateSQLParts("複合主キー", dtComposite, new string[] { "OrderID", "ProductID" }); + + // 更新対象列が無い場合(全列が主キー) + // ・SET句が空のSQLは構文エラーになるため、生成しないこと。 + DataTable dtAllPk = new DataTable(); + dtAllPk.Columns.Add("OrderID", typeof(object)); + DataRow drAllPk = dtAllPk.NewRow(); + drAllPk["OrderID"] = 1; + dtAllPk.Rows.Add(drAllPk); + TestSQLUtility.OutputUpdateSQLParts("更新対象列なし", dtAllPk, new string[] { "OrderID" }); + + // 主キーが無い場合 + // ・WHERE句が無いと全行更新になるため、生成しないこと。 + TestSQLUtility.OutputUpdateSQLParts("主キーなし", dtSingle, new string[] { }); + } + + /// <summary>Insert系SQLのパーツ生成のテスト</summary> + private static void TestGetInsertSQLParts() + { + MyDebug.OutputDebugAndConsole("SQLUtility.GetInsertSQLParts"); + + DataTable dt = TestSQLUtility.CreateOrderTable(true); + + foreach (DbEnum.DBMSType dbms in TestSQLUtility.GetTargetDbms()) + { + MyDebug.OutputDebugAndConsole("- " + dbms.ToString()); + + string[] parts = (new SQLUtility(dbms)).GetInsertSQLParts(dt); + foreach (string part in parts) + { + MyDebug.OutputDebugAndConsole(part); + } + } + } + + /// <summary>Update系SQLのパーツを生成して出力する</summary> + /// <param name="caseName">ケース名</param> + /// <param name="dt">入力DataTable</param> + /// <param name="primaryKeys">主キー情報</param> + private static void OutputUpdateSQLParts(string caseName, DataTable dt, string[] primaryKeys) + { + MyDebug.OutputDebugAndConsole("[" + caseName + "]"); + + foreach (DbEnum.DBMSType dbms in TestSQLUtility.GetTargetDbms()) + { + MyDebug.OutputDebugAndConsole("- " + dbms.ToString()); + + string[] parts = (new SQLUtility(dbms)).GetUpdateSQLParts(dt, primaryKeys); + + if (parts.Length == 0) + { + // 生成しないケース(更新対象列なし・主キーなし) + MyDebug.OutputDebugAndConsole("(生成なし)"); + } + else + { + foreach (string part in parts) + { + // 呼び出し側が "UPDATE <テーブル名>" を前置して1文にする。 + MyDebug.OutputDebugAndConsole("UPDATE Orders " + part); + } + } + } + } + + /// <summary>テスト対象のDBMS</summary> + /// <returns>DBMSの種類の配列</returns> + /// <remarks> + /// HiRDBは囲い文字などの実装が他と同じため、代表としてSQLServerを見る。 + /// PostgreSQL・MySQLはCASE式を使う別実装のため、両方を対象にする。 + /// </remarks> + private static DbEnum.DBMSType[] GetTargetDbms() + { + return new DbEnum.DBMSType[] + { + DbEnum.DBMSType.SQLServer, + DbEnum.DBMSType.Oracle, + DbEnum.DBMSType.PstGrS, + DbEnum.DBMSType.MySQL + }; + } + + /// <summary>テスト用のDataTableを生成する</summary> + /// <param name="isComposite">主キーを複合にするか</param> + /// <returns>DataTable</returns> + private static DataTable CreateOrderTable(bool isComposite) + { + DataTable dt = new DataTable(); + + dt.Columns.Add("OrderID", typeof(object)); + if (isComposite) + { + dt.Columns.Add("ProductID", typeof(object)); + } + dt.Columns.Add("Qty", typeof(object)); + dt.Columns.Add("Note", typeof(object)); + + DataRow dr1 = dt.NewRow(); + dr1["OrderID"] = 1; + if (isComposite) + { + dr1["ProductID"] = 10; + } + dr1["Qty"] = 100; + dr1["Note"] = "a"; + dt.Rows.Add(dr1); + + DataRow dr2 = dt.NewRow(); + dr2["OrderID"] = 2; + if (isComposite) + { + dr2["ProductID"] = 20; + } + dr2["Qty"] = 200; + dr2["Note"] = "b"; + dt.Rows.Add(dr2); + + return dt; + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/TestTable.cs b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestTable.cs new file mode 100644 index 000000000..bc3873361 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/TestTable.cs @@ -0,0 +1,162 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :TestTable +//* クラス日本語名 :テスト用の表 +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/06 玄人 幸道 新規作成(#520) +//********************************************************************************** + +using System; + +using Touryo.Infrastructure.Public.Db; + +namespace TestDataAccess +{ + /// <summary>テスト用の表</summary> + /// <remarks> + /// 更新系と動的パラメタライズドクエリのテストで共有する。 + /// + /// **既存の表(Northwind 等)は使わない。** 更新すると SimpleBatch や + /// 3_SmokeTest.ps1 の前提が壊れるため、テストのたびに作って落とす。 + /// </remarks> + public class TestTable + { + /// <summary>表名</summary> + /// <remarks>既存の表と衝突しない名前にすること。</remarks> + public const string Name = "TestOrders"; + + /// <summary>囲った表名</summary> + /// <param name="dap">データ プロバイダの識別子</param> + /// <returns>囲った表名</returns> + public static string Quoted(string dap) + { + return DataProvider.Quote(dap, TestTable.Name); + } + + /// <summary>表を作る</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// **囲い文字は SQLUtility が生成するものと必ず一致させる。** + /// Oracle は囲わないと大文字、PostgreSQL は囲わないと小文字に畳まれるため、 + /// 囲わずに作ると、生成された SQL の "Qty" などが「存在しない列」になる。 + /// </remarks> + public static void Create(BaseDam dam, string dap) + { + string intType; + string strType; + + switch (dap) + { + case "ODP": + intType = "NUMBER(10)"; + strType = "VARCHAR2(10)"; + break; + + case "MCN": + intType = "INT"; + strType = "VARCHAR(10)"; + break; + + case "NPS": + intType = "integer"; + strType = "varchar(10)"; + break; + + default: + intType = "int"; + strType = "nvarchar(10)"; + break; + } + + dam.SetSqlByCommand( + "CREATE TABLE " + TestTable.Quoted(dap) + " (" + + DataProvider.Quote(dap, "OrderID") + " " + intType + " NOT NULL, " + + DataProvider.Quote(dap, "ProductID") + " " + intType + " NOT NULL, " + + DataProvider.Quote(dap, "Qty") + " " + intType + ", " + + DataProvider.Quote(dap, "Note") + " " + strType + ", " + + "PRIMARY KEY (" + DataProvider.Quote(dap, "OrderID") + + ", " + DataProvider.Quote(dap, "ProductID") + "))"); + + dam.ExecInsUpDel_NonQuery(); + } + + /// <summary>表を落とす</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <remarks> + /// 存在しない場合の例外は無視する。 + /// DROP TABLE IF EXISTS は Oracle では 23ai 以降でしか使えないため、 + /// 分岐せずに「投げて握る」形にしている。 + /// </remarks> + public static void Drop(BaseDam dam, string dap) + { + try + { + dam.SetSqlByCommand("DROP TABLE " + TestTable.Quoted(dap)); + dam.ExecInsUpDel_NonQuery(); + } + catch + { + // 表が無いだけ。 + } + } + + /// <summary>1 行追加する</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <param name="orderId">OrderID</param> + /// <param name="productId">ProductID</param> + /// <param name="qty">Qty</param> + /// <param name="note">Note(null を渡すと NULL を入れる)</param> + /// <remarks> + /// Note に NULL を入れられるようにしてあるのは、動的 SQL の <ELSE> + /// (IS NULL 側)を確認するため。 + /// </remarks> + public static void InsertRow( + BaseDam dam, string dap, int orderId, int productId, int qty, string note) + { + string noteValue = (note == null) ? "NULL" : "'" + note + "'"; + + dam.SetSqlByCommand( + "INSERT INTO " + TestTable.Quoted(dap) + + " (" + DataProvider.Quote(dap, "OrderID") + + ", " + DataProvider.Quote(dap, "ProductID") + + ", " + DataProvider.Quote(dap, "Qty") + + ", " + DataProvider.Quote(dap, "Note") + ")" + + " VALUES (" + orderId + ", " + productId + ", " + qty + ", " + noteValue + ")"); + + dam.ExecInsUpDel_NonQuery(); + } + + /// <summary>件数を取得する</summary> + /// <param name="dam">BaseDam</param> + /// <param name="dap">データ プロバイダの識別子</param> + /// <returns>件数</returns> + public static int Count(BaseDam dam, string dap) + { + dam.SetSqlByCommand("SELECT COUNT(*) FROM " + TestTable.Quoted(dap)); + return Convert.ToInt32(dam.ExecSelectScalar()); + } + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/appsettings.json b/root/programs/CS/Frameworks/Tests/TestDataAccess/appsettings.json new file mode 100644 index 000000000..d601c4cd9 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/appsettings.json @@ -0,0 +1,29 @@ +{ + // connectionStrings section + "ConnectionStrings": { + // SQL Server(CI でも使う。ここだけは必ず接続できること) + "ConnectionString_SQL": "Data Source=localhost;Initial Catalog=Northwind;User ID=sa;Password=seigi@123;Encrypt=false;", + // ODBC + "ConnectionString_ODBC": "Dsn=odbc_test1", + // Oracle(ODP.NET) + "ConnectionString_ODP": "User Id=SCOTT;Password=tiger;Data Source=localhost/XE;", + // MySQL(Connector/NET) + "ConnectionString_MCN": "Server=localhost;Database=test;User Id=root;Password=seigi@123", + // PostgreSQL(Npgsql)… .NET (Core) 専用 + "ConnectionString_NPS": "HOST=localhost;DATABASE=postgres;USER ID=postgres;PASSWORD=seigi@123;" + }, + // appSettings section + "appSettings": { + // リソース ファイルの場合 + "FxXMLMSGDefinition": "C:/root/files/resource/Xml/MSGDefinition.xml", + "FxXMLSPDefinition": "C:/root/files/resource/Xml/SPDefinition.xml", + // メッセージの言語を固定する + // GetMessage は、指定が無ければ CurrentUICulture から MSGDefinition_xx.xml を選ぶ。 + // 期待結果は日本語で記録されているため、実行環境の表示言語に依存しないよう固定する。 + "FxBusinessMessageCulture": "ja-JP", + // 静的SQL・動的SQLの格納フォルダ + "SqlTextFilePath": "C:/root/files/resource/Sql", + // Log4Netのコンフィグファイルへのパス + "FxLog4NetConfFile": "SampleLogConf.xml" + } +} diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/core100/TestDataAccessCore.csproj b/root/programs/CS/Frameworks/Tests/TestDataAccess/core100/TestDataAccessCore.csproj new file mode 100644 index 000000000..88f8cb686 --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/core100/TestDataAccessCore.csproj @@ -0,0 +1,77 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <NoWarn>$(NoWarn);NU1605</NoWarn> + <TargetFramework>net10.0</TargetFramework> + <AssemblyName>TestDataAccessCore</AssemblyName> + <RootNamespace>TestDataAccess</RootNamespace> + </PropertyGroup> + + <PropertyGroup> + <DefineConstants>TRACE;NETCOREAPP</DefineConstants> + </PropertyGroup> + + <ItemGroup> + <Compile Include="..\DataProvider.cs" Link="DataProvider.cs" /> + <Compile Include="..\Program.cs" Link="Program.cs" /> + <Compile Include="..\TestDataAccessDpq.cs" Link="TestDataAccessDpq.cs" /> + <Compile Include="..\TestDataAccessPattern.cs" Link="TestDataAccessPattern.cs" /> + <Compile Include="..\TestDataAccessUpdate.cs" Link="TestDataAccessUpdate.cs" /> + <Compile Include="..\TestSQLUtility.cs" Link="TestSQLUtility.cs" /> + <Compile Include="..\TestTable.cs" Link="TestTable.cs" /> + </ItemGroup> + + <ItemGroup> + <Content Include="..\SampleLogConf.xml" Link="SampleLogConf.xml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + </ItemGroup> + + <ItemGroup> + <None Include="..\appsettings.json" Link="appsettings.json"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + </ItemGroup> + + <ItemGroup> + <PackageReference Include="log4net" Version="3.3.0" /> + <PackageReference Include="Microsoft.Data.SqlClient" Version="6.0.2" /> + <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.6" /> + <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="9.0.6" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.6" /> + <PackageReference Include="MySql.Data" Version="9.3.0" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> + <PackageReference Include="Npgsql" Version="9.0.3" /> + <!--Oracle は .NET (Core) 版のパッケージ名が異なる(DamManagedOdp_netcore100.csproj に合わせる)。 + net48 は Oracle.ManagedDataAccess。無いと ODP の接続時に FileNotFoundException になる。--> + <PackageReference Include="Oracle.ManagedDataAccess.Core" Version="23.8.0" /> + <PackageReference Include="System.Security.Permissions" Version="9.0.6" /> + </ItemGroup> + + <ItemGroup> + <Reference Include="OpenTouryo.Framework"> + <HintPath>..\..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.Framework.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.Public"> + <HintPath>..\..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.Public.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.DamManagedOdp"> + <HintPath>..\..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.DamManagedOdp.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.DamMySQL"> + <HintPath>..\..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.DamMySQL.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.DamPstGrS"> + <HintPath>..\..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.DamPstGrS.dll</HintPath> + </Reference> + </ItemGroup> + + <ItemGroup> + <None Update="appsettings.json"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + <CopyToPublishDirectory>Always</CopyToPublishDirectory> + </None> + </ItemGroup> + +</Project> diff --git a/root/programs/CS/Frameworks/Tests/TestDataAccess/net48/TestDataAccessFx.csproj b/root/programs/CS/Frameworks/Tests/TestDataAccess/net48/TestDataAccessFx.csproj new file mode 100644 index 000000000..3df03fc2a --- /dev/null +++ b/root/programs/CS/Frameworks/Tests/TestDataAccess/net48/TestDataAccessFx.csproj @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{100C9173-E92B-410D-9C93-9C0EBF2019DB}</ProjectGuid> + <OutputType>Exe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>TestDataAccess</RootNamespace> + <AssemblyName>TestDataAccessFx</AssemblyName> + <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> + <TargetFrameworkProfile /> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE;NET48</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE;NET48</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="OpenTouryo.Framework"> + <HintPath>..\..\..\Infrastructure\Build_net48\OpenTouryo.Framework.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.Public"> + <HintPath>..\..\..\Infrastructure\Build_net48\OpenTouryo.Public.dll</HintPath> + </Reference> + <!--PostgreSQL(DamPstGrS)は .NET (Core) 専用のため、net48 では参照しない--> + <Reference Include="OpenTouryo.DamManagedOdp"> + <HintPath>..\..\..\Infrastructure\Build_net48\OpenTouryo.DamManagedOdp.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.DamMySQL"> + <HintPath>..\..\..\Infrastructure\Build_net48\OpenTouryo.DamMySQL.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Configuration" /> + <Reference Include="System.Data" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="System.Xml" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="Microsoft.CSharp" /> + </ItemGroup> + <ItemGroup> + <None Include="..\App.config"> + <Link>App.config</Link> + </None> + </ItemGroup> + <ItemGroup> + <Compile Include="..\AssemblyInfo.cs"> + <Link>Properties\AssemblyInfo.cs</Link> + </Compile> + <Compile Include="..\DataProvider.cs"> + <Link>DataProvider.cs</Link> + </Compile> + <Compile Include="..\Program.cs"> + <Link>Program.cs</Link> + </Compile> + <Compile Include="..\TestDataAccessDpq.cs"> + <Link>TestDataAccessDpq.cs</Link> + </Compile> + <Compile Include="..\TestDataAccessPattern.cs"> + <Link>TestDataAccessPattern.cs</Link> + </Compile> + <Compile Include="..\TestDataAccessUpdate.cs"> + <Link>TestDataAccessUpdate.cs</Link> + </Compile> + <Compile Include="..\TestSQLUtility.cs"> + <Link>TestSQLUtility.cs</Link> + </Compile> + <Compile Include="..\TestTable.cs"> + <Link>TestTable.cs</Link> + </Compile> + </ItemGroup> + <ItemGroup> + <Content Include="..\SampleLogConf.xml"> + <Link>SampleLogConf.xml</Link> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + </ItemGroup> + <ItemGroup> + <PackageReference Include="log4net"> + <Version>3.3.0</Version> + </PackageReference> + <PackageReference Include="Microsoft.Data.SqlClient"> + <Version>6.0.2</Version> + </PackageReference> + <PackageReference Include="MySql.Data"> + <Version>9.3.0</Version> + </PackageReference> + <PackageReference Include="Newtonsoft.Json"> + <Version>13.0.3</Version> + </PackageReference> + <PackageReference Include="Oracle.ManagedDataAccess"> + <Version>23.8.0</Version> + </PackageReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project> diff --git a/root/programs/CS/Frameworks/Tests/TestLog/TestLog1.csproj b/root/programs/CS/Frameworks/Tests/TestLog/TestLog1.csproj index a72b73be8..a7722aebc 100644 --- a/root/programs/CS/Frameworks/Tests/TestLog/TestLog1.csproj +++ b/root/programs/CS/Frameworks/Tests/TestLog/TestLog1.csproj @@ -91,7 +91,7 @@ </ItemGroup> <ItemGroup> <PackageReference Include="log4net"> - <Version>3.1.0</Version> + <Version>3.3.0</Version> </PackageReference> <PackageReference Include="NLog"> <Version>5.5.0</Version> diff --git a/root/programs/CS/Frameworks/Tests/TestLog/TestLog2.csproj b/root/programs/CS/Frameworks/Tests/TestLog/TestLog2.csproj index b7b903009..3f4ae430a 100644 --- a/root/programs/CS/Frameworks/Tests/TestLog/TestLog2.csproj +++ b/root/programs/CS/Frameworks/Tests/TestLog/TestLog2.csproj @@ -91,7 +91,7 @@ </ItemGroup> <ItemGroup> <PackageReference Include="log4net"> - <Version>3.1.0</Version> + <Version>3.3.0</Version> </PackageReference> </ItemGroup> <ItemGroup> diff --git a/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore1.csproj b/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore1.csproj index 093e0b6c8..a78b72703 100644 --- a/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore1.csproj +++ b/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore1.csproj @@ -2,7 +2,7 @@ <PropertyGroup> <OutputType>WinExe</OutputType> - <TargetFramework>net8.0-windows7.0</TargetFramework> + <TargetFramework>net10.0-windows7.0</TargetFramework> <UseWindowsForms>true</UseWindowsForms> <ApplicationIcon /> <StartupObject /> @@ -42,7 +42,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="log4net" Version="3.1.0" /> + <PackageReference Include="log4net" Version="3.3.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="9.0.6" /> @@ -61,7 +61,7 @@ <ItemGroup> <Reference Include="OpenTouryo.Public"> - <HintPath>..\..\Infrastructure\Build_netcore80\net8.0\OpenTouryo.Public.dll</HintPath> + <HintPath>..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.Public.dll</HintPath> </Reference> </ItemGroup> diff --git a/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore2.csproj b/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore2.csproj index c74f69554..159cda630 100644 --- a/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore2.csproj +++ b/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore2.csproj @@ -2,7 +2,7 @@ <PropertyGroup> <OutputType>WinExe</OutputType> - <TargetFramework>net8.0-windows7.0</TargetFramework> + <TargetFramework>net10.0-windows7.0</TargetFramework> <UseWindowsForms>true</UseWindowsForms> <ApplicationIcon /> <StartupObject /> @@ -42,7 +42,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="log4net" Version="3.1.0" /> + <PackageReference Include="log4net" Version="3.3.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="9.0.6" /> <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="9.0.6" /> @@ -57,7 +57,7 @@ <ItemGroup> <Reference Include="OpenTouryo.Public"> - <HintPath>..\..\Infrastructure\Build_netcore80\net8.0\OpenTouryo.Public.dll</HintPath> + <HintPath>..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.Public.dll</HintPath> </Reference> </ItemGroup> diff --git a/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore3.csproj b/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore3.csproj index c9c8b43ec..d787cab12 100644 --- a/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore3.csproj +++ b/root/programs/CS/Frameworks/Tests/TestLog/TestLogCore3.csproj @@ -2,7 +2,7 @@ <PropertyGroup> <OutputType>WinExe</OutputType> - <TargetFramework>net8.0-windows7.0</TargetFramework> + <TargetFramework>net10.0-windows7.0</TargetFramework> <UseWindowsForms>true</UseWindowsForms> <ApplicationIcon /> <StartupObject /> @@ -57,7 +57,7 @@ <ItemGroup> <Reference Include="OpenTouryo.Public"> - <HintPath>..\..\Infrastructure\Build_netcore80\net8.0\OpenTouryo.Public.dll</HintPath> + <HintPath>..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.Public.dll</HintPath> </Reference> </ItemGroup> diff --git a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoDefinitionOptions.cs b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoDefinitionOptions.cs new file mode 100644 index 000000000..55f30c422 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoDefinitionOptions.cs @@ -0,0 +1,85 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :DaoDefinitionOptions +//* クラス日本語名 :D層定義情報ファイル生成処理のオプション +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/07/31 玄人 幸道 新規作成(GUIのCUI化) +//********************************************************************************** + +namespace DaoGen_Tool +{ + /// <summary> + /// D層定義情報ファイル生成処理のオプション + /// </summary> + /// <remarks> + /// 生成処理(Form1.DaoDefinitionGen)を GUI からも CUI からも呼び出せるようにするための引数。 + /// UI コントロールへの参照を持たず、フィールドは全て組み込み型とする。 + /// ・GUI 起動時は Form1 のイベント ハンドラが UI コントロールから値を読んで処理を呼び出す。 + /// ・CUI 起動時は Program がコマンドライン引数から生成する。 + /// </remarks> + public class DaoDefinitionOptions + { + #region 接続情報 + + /// <summary>データ プロバイダ(SQL / OLE / ODB / ODP / DB2 / HIR / MCN / NPS)</summary> + public string Dap = "SQL"; + + /// <summary>接続文字列</summary> + public string ConnectionString = ""; + + #endregion + + #region 出力 + + /// <summary>出力先ファイル(*.csv)へのパス</summary> + /// <remarks> + /// 同じ場所に "*_DBTypeInfo.csv" "*_DotNetTypeInfo.csv" も出力される。 + /// </remarks> + public string OutputFilePath = ""; + + /// <summary>D層定義情報ファイルの出力エンコーディング(コード ページ)</summary> + public int CodePage = 65001; + + #endregion + + #region 生成対象 + + /// <summary>生成対象とするテーブル・ビュー名の配列</summary> + /// <remarks>要素が無い場合は、DBMS 上の全テーブル・ビューを対象とする。</remarks> + public string[] Tables = new string[0]; + + /// <summary>生成対象から除外するテーブル・ビュー名の配列</summary> + public string[] ExcludeTables = new string[0]; + + /// <summary>主キー情報(キー:テーブル名、値:主キー列名の配列)</summary> + /// <remarks> + /// GUI の「主キー情報の設定」ダイアログに相当する。 + /// 主キー情報を DBMS から取得できないデータ プロバイダ + /// (ODBC・OLEDB・MySQL・PostgreSQL)で使用する。 + /// </remarks> + public System.Collections.Generic.Dictionary<string, string[]> PrimaryKeys + = new System.Collections.Generic.Dictionary<string, string[]>(); + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoGenOptions.cs b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoGenOptions.cs new file mode 100644 index 000000000..18e4f71ee --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoGenOptions.cs @@ -0,0 +1,134 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :DaoGenOptions +//* クラス日本語名 :Dao・DTO・SQL 生成処理のオプション +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/07/31 玄人 幸道 新規作成(GUIのCUI化) +//********************************************************************************** + +namespace DaoGen_Tool +{ + /// <summary> + /// Dao・DTO・SQL 生成処理のオプション + /// </summary> + /// <remarks> + /// 生成処理(Form2.DaoAndSqlGen)を GUI からも CUI からも呼び出せるようにするための引数。 + /// UI コントロールへの参照を持たず、フィールドは全て組み込み型とする。 + /// ・GUI 起動時は Form2 のイベント ハンドラが UI コントロールから値を読んで生成する。 + /// ・CUI 起動時は Program がコマンドライン引数から生成する。 + /// </remarks> + public class DaoGenOptions + { + #region 入出力パス + + /// <summary>D層定義情報ファイル(*.csv)へのパス</summary> + /// <remarks> + /// 同じ場所の "*_DotNetTypeInfo.csv" "*_DBTypeInfo.csv" も必要に応じて読み込まれる。 + /// </remarks> + public string DaoDefinitionFilePath = ""; + + /// <summary>テンプレート ファイルのルート フォルダ</summary> + public string TemplateRootPath = ""; + + /// <summary>出力先フォルダ</summary> + public string OutputPath = ""; + + #endregion + + #region データ プロバイダ・言語 + + /// <summary>データ プロバイダ(SQL / OLE / ODB / ODP / DB2 / MCN / NPS)</summary> + public string Dap = "SQL"; + + /// <summary>true:Visual C# / false:Visual Basic</summary> + public bool IsCSharp = true; + + #endregion + + #region 生成対象 + + /// <summary>エンティティ(DTO)を生成する</summary> + public bool CreateEntity = false; + + /// <summary>型付きデータセットを生成する</summary> + public bool CreateTypedDataSet = false; + + /// <summary>テーブル メンテナンス画面を生成する</summary> + public bool CreateTableMaintenance = false; + + /// <summary>DTO のみ生成する(Dao を生成しない)</summary> + public bool OnlyDTO = false; + + /// <summary>テーブル メンテナンス画面のみ生成する(Dao を生成しない)</summary> + public bool OnlyTableMaintenance = false; + + #endregion + + #region 生成オプション + + /// <summary>D層定義情報ファイルの1行目をヘッダとして読み飛ばす</summary> + public bool DaoDefinitionHeader = true; + + /// <summary>エスケープ文字(ODP 使用時に1文字必須)</summary> + public string EscapeChar = ""; + + /// <summary>タイム スタンプ列名(空文字なら未使用)</summary> + public string TimeStampColName = ""; + + /// <summary>タイム スタンプの更新方法</summary> + public string TimeStampUpdMethod = ""; + + /// <summary>作成者(姓)</summary> + public string FamilyName = ""; + + /// <summary>作成者(名)</summary> + public string PersonalName = ""; + + #endregion + + #region エンコーディング + + /// <summary>SQL ファイル(XML)のエンコーディング名</summary> + public string XmlEncoding = "utf-8"; + + /// <summary>クラス ファイルのエンコーディング(コード ページ)</summary> + public int ClassFileCodePage = 65001; + + /// <summary>D層定義情報ファイルの読み込みエンコーディング(コード ページ)</summary> + public int DaoDefinitionCodePage = 65001; + + /// <summary>クラス ファイルの出力エンコーディング(コード ページ)</summary> + public int ClassFileOutputCodePage = 65001; + + /// <summary>SQL ファイルの出力エンコーディング(コード ページ)</summary> + public int SqlFileCodePage = 65001; + + /// <summary>SQL テンプレートの読み込みエンコーディング(コード ページ)</summary> + public int SqlTemplateCodePage = 65001; + + /// <summary>LIKE 文(Oracle 用の LIKE 句の記述)</summary> + public string LikeStatement = "LIKE"; + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoGen_Tool.csproj b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoGen_Tool.csproj index a113774f5..d0fbbf84f 100644 --- a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoGen_Tool.csproj +++ b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/DaoGen_Tool.csproj @@ -108,6 +108,8 @@ <Compile Include="Form2.Designer.cs"> <DependentUpon>Form2.cs</DependentUpon> </Compile> + <Compile Include="DaoDefinitionOptions.cs" /> + <Compile Include="DaoGenOptions.cs" /> <Compile Include="Program.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <EmbeddedResource Include="Form1.ja-JP.resx"> diff --git a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Form1.cs b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Form1.cs index a52a8c48f..fbc7bdd30 100644 --- a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Form1.cs +++ b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Form1.cs @@ -50,6 +50,12 @@ //* 2014/08/19 西野 大介 カラム取得時のスキーマ考慮が無かったため追加(奥井さんからの提供) //* 2017/09/06 西野 大介 Oracle.ManagedDataAccess.Clientで主キーが取れなくなった対応 //* 2018/10/29 西野 大介 NETCOREAPP対応で、サポートされないDBを「#if」した。 +//* 2026/07/31 玄人 幸道 GUIのCUI化(イベント ハンドラのロジックを関数化) +//* 2026/08/01 玄人 幸道 SQL Serverの主キー取得を、非公開のストアド プロシージャ +//* (sp_helpconstraint/sp_MShelpindex)からカタログ ビューに変更 +//* 2026/08/01 玄人 幸道 サポートされないデータ プロバイダの選択・指定を抑止 +//* 2026/08/01 玄人 幸道 PostgreSQLの.NET型情報を取得するように変更 +//* (NpgsqlがDataTypesをサポートするようになったため) //********************************************************************************** // -------------------- @@ -76,6 +82,7 @@ using System.Text; using System.Data; using System.Collections; +using System.Collections.Generic; using System.Diagnostics; using System.Resources; using System.Drawing; @@ -128,6 +135,50 @@ public partial class Form1 : Form /// <summary>スキーマの情報(カスタム)</summary> private Hashtable HtSchemaCustom; + #region 取得したスキーマ情報(デバッグ表示用) + + // ↓↓↓【追加】↓↓↓ + // イベント ハンドラから外に出した関数の取得結果を、 + // イベント ハンドラ側でデバッグ表示するために保持する。 + + /// <summary>スキーマの情報(テーブル)</summary> + private DataTable DtSchmaTables; + + /// <summary>スキーマの情報(ビュー)</summary> + private DataTable DtSchmaViews; + + /// <summary>スキーマの情報(カラム)</summary> + private DataTable DtSchmaColumns; + + /// <summary>スキーマの情報(主キー)</summary> + private DataTable DtSchmaPrimaryKeys; + + /// <summary>スキーマの情報(インデックス カラム)</summary> + private DataTable DtSchmaIndexColumns; + + // ↑↑↑【追加】↑↑↑ + + #endregion + + #endregion + + #region CUI(ヘッドレス実行)用 + + // ↓↓↓【追加】↓↓↓ + + /// <summary>接続文字列</summary> + /// <remarks> + /// GUI 起動時はイベント ハンドラが txtConnString から、 + /// CUI 起動時は DaoDefinitionGen がコマンドライン引数から設定する。 + /// </remarks> + private string ConnString = ""; + + /// <summary>CUI(非対話)で起動しているか</summary> + /// <remarks>true の場合、MessageBox の代わりに標準出力へメッセージを出す。</remarks> + public bool IsCui = false; + + // ↑↑↑【追加】↑↑↑ + #endregion #region Help Information @@ -183,12 +234,21 @@ private void Form1_Load(object sender, EventArgs e) this.btnDaoDefinitionGen.Enabled = false; + // ↓↓↓【変更】↓↓↓ + // このビルドでサポートされないデータ プロバイダは、選択できないようにする。 + // ※ DB2・HiRDBは、両ビルドともコードがコメントアウトされているためサポートされない。 #if NETCOREAPP + // OLEDBは、NETCOREAPPではサポートされない。 this.rbnOLE.Enabled = false; this.rbnDB2.Enabled = false; this.rbnHiRDB.Enabled = false; #else + // PostgreSQLは、NETCOREAPPでのみサポートされる。 + this.rbnPstgrs.Enabled = false; + this.rbnDB2.Enabled = false; + this.rbnHiRDB.Enabled = false; #endif + // ↑↑↑【変更】↑↑↑ } #endregion @@ -211,59 +271,106 @@ private void Close_ToolStripMenuItem_Click(object sender, EventArgs e) #region 共通関数 + #region メッセージ表示 + + // ↓↓↓【追加】↓↓↓ + + /// <summary>メッセージを表示する(GUI:MessageBox/CUI:標準出力)</summary> + /// <param name="message">メッセージ</param> + private void ShowMessage(string message) + { + if (this.IsCui) + { + Console.WriteLine(message); + } + else + { + MessageBox.Show(message); + } + } + + /// <summary>メッセージを表示する(GUI:MessageBox/CUI:標準出力)</summary> + /// <param name="message">メッセージ</param> + /// <param name="caption">キャプション</param> + private void ShowMessage(string message, string caption) + { + if (this.IsCui) + { + Console.WriteLine(caption + " " + message); + } + else + { + MessageBox.Show(message, caption); + } + } + + // ↑↑↑【追加】↑↑↑ + + #endregion + #region コネクション オープン クローズ /// <summary> /// コネクション オープン /// </summary> + /// <remarks> + /// CUI からも呼び出せるよう、UIコントロール(rbnXxx、txtConnString)ではなく、 + /// this.Dap、this.ConnString を参照する。 + /// </remarks> private void ConnectionOpen() { - if (this.rbnSQL.Checked) + if (this.Dap == "SQL") { - this.SqlCn = new SqlConnection(this.txtConnString.Text); + this.SqlCn = new SqlConnection(this.ConnString); this.SqlCn.Open(); } - else if (this.rbnODB.Checked) + else if (this.Dap == "ODB") { - this.OdbCn = new OdbcConnection(this.txtConnString.Text); + this.OdbCn = new OdbcConnection(this.ConnString); this.OdbCn.Open(); } - else if (this.rbnODP.Checked) + else if (this.Dap == "ODP") { - this.OdpCn = new OracleConnection(this.txtConnString.Text); + this.OdpCn = new OracleConnection(this.ConnString); this.OdpCn.Open(); } - else if (this.rbnMySQL.Checked) + else if (this.Dap == "MCN") { - this.MySqlCn = new MySqlConnection(this.txtConnString.Text); + this.MySqlCn = new MySqlConnection(this.ConnString); this.MySqlCn.Open(); } #if NETCOREAPP - else if (this.rbnPstgrs.Checked) + else if (this.Dap == "NPS") { - this.NpgsqlCn = new NpgsqlConnection(this.txtConnString.Text); + this.NpgsqlCn = new NpgsqlConnection(this.ConnString); this.NpgsqlCn.Open(); } #else - else if (this.rbnOLE.Checked) + else if (this.Dap == "OLE") { - this.OleCn = new OleDbConnection(this.txtConnString.Text); + this.OleCn = new OleDbConnection(this.ConnString); this.OleCn.Open(); } - /*else if (this.rbnDB2.Checked) + /*else if (this.Dap == "DB2") { - this.DB2Cn = new DB2Connection(this.txtConnString.Text); + this.DB2Cn = new DB2Connection(this.ConnString); this.DB2Cn.Open(); } - else if (this.rbnHiRDB.Checked) + else if (this.Dap == "HIR") { - this.HiRDBCn = new HiRDBConnection(this.txtConnString.Text); + this.HiRDBCn = new HiRDBConnection(this.ConnString); this.HiRDBCn.Open(); }*/ #endif else { - // データプロバイダ指定無し(ありえない) + // ↓↓↓【変更】↓↓↓ + // データプロバイダ指定無し、または、このビルドでサポートされないデータ プロバイダ。 + // 以前は何もしなかったため、コネクションがnullのまま後続処理へ進み、 + // NullReferenceExceptionになっていた。呼び出し元のcatchで処理できるよう、例外を送出する。 + throw new NotSupportedException(string.Format( + "データ プロバイダ[{0}]は、このビルドではサポートされていません。", this.Dap)); + // ↑↑↑【変更】↑↑↑ } } @@ -573,6 +680,9 @@ private void btnGetSchemaInfo_Click(object sender, EventArgs e) // カーソルを待機状態にする System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; + // UIコントロールから情報を取得する。 + this.ConnString = this.txtConnString.Text; + // コネクション オープン this.ConnectionOpen(); @@ -1024,15 +1134,74 @@ private void btnGetSchemaInfo_Click(object sender, EventArgs e) /// <summary>スキーマ情報を読み込み、テーブル・ビューをリストする。</summary> private void btnListTable_Click(object sender, EventArgs e) + { + // カーソルを待機状態にする + System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; + + try + { + // UIコントロールから情報を取得し、リスト処理を呼び出す。 + this.ConnString = this.txtConnString.Text; + + if (!this.ListTable()) + { + // 失敗した場合、UIコントロールへの反映は行わない。 + return; + } + + #region デバッグ + if (this.cbxDebug.Checked) + { + // テーブル情報 + if (this.DtSchmaTables != null) + { + //this.tabPage1.Text = "テーブル情報"; + this.tabPage1.Text = this.RM_GetString("TabPage1TableInfo"); + this.dataGridView1.DataSource = this.DtSchmaTables; + } + // ヴュー情報 + if (this.DtSchmaViews != null) + { + //this.tabPage2.Text = "ヴュー情報"; + this.tabPage2.Text = this.RM_GetString("TabPage2VieuxInfo"); + this.dataGridView2.DataSource = this.DtSchmaViews; + } + } + #endregion + + // リスト ボックスを更新する。 + this.LbxUpdateItems(); + + // ボタン状態の変更 + this.gbxDataProviders.Enabled = false; + this.rbnMySQL.Enabled = false; + this.txtConnString.Enabled = false; + + this.btnDelTable.Enabled = true; + this.btnLoadColumn.Enabled = true; + + this.btnSetPrimaryKey.Enabled = false; + + this.cmbEncoding.Enabled = false; + this.btnDaoDefinitionGen.Enabled = false; + } + finally + { + // カーソルを元に戻す + System.Windows.Forms.Cursor.Current = Cursors.Default; + } + } + + /// <summary>スキーマ情報を読み込み、テーブル・ビューをリストする(GUI/CUI 共通)。</summary> + /// <returns>成功した場合 true</returns> + /// <remarks>UIコントロールを参照しないため、フォームを表示せずに呼び出せる。</remarks> + private bool ListTable() { try { // コネクション オープン this.ConnectionOpen(); - // カーソルを待機状態にする - System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; - // スキーマの情報(テーブル) DataTable dtSchmaTables = null; // スキーマの情報(ビュー) @@ -1040,13 +1209,13 @@ private void btnListTable_Click(object sender, EventArgs e) #region スキーマ情報を読み込み // テーブル・ビューをリストする。 - if (this.rbnSQL.Checked) + if (this.Dap == "SQL") { #region SQL Server // 注釈 - //MessageBox.Show("同一DB上で同一名の複数のテーブルを持たないこと(SQL Server用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); - MessageBox.Show(string.Format(this.RM_GetString("CautionPrerequisite"), "SQL Server"), this.RM_GetString("CautionPrerequisiteCaption")); + //this.ShowMessage("同一DB上で同一名の複数のテーブルを持たないこと(SQL Server用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); + this.ShowMessage(string.Format(this.RM_GetString("CautionPrerequisite"), "SQL Server"), this.RM_GetString("CautionPrerequisiteCaption")); #region テーブル・ビューの情報を取得 @@ -1080,13 +1249,13 @@ private void btnListTable_Click(object sender, EventArgs e) #endregion } - else if (this.rbnODB.Checked) + else if (this.Dap == "ODB") { #region ODBC // 注釈 - //MessageBox.Show("同一DB上で同一名の複数のテーブルを持たないこと(ODBC用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); - MessageBox.Show(string.Format(this.RM_GetString("CautionPrerequisite"), "ODBC"), this.RM_GetString("CautionPrerequisiteCaption")); + //this.ShowMessage("同一DB上で同一名の複数のテーブルを持たないこと(ODBC用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); + this.ShowMessage(string.Format(this.RM_GetString("CautionPrerequisite"), "ODBC"), this.RM_GetString("CautionPrerequisiteCaption")); #region テーブル・ビューの情報を取得 @@ -1120,14 +1289,14 @@ private void btnListTable_Click(object sender, EventArgs e) #endregion } - else if (this.rbnODP.Checked) + else if (this.Dap == "ODP") { #region Oracle #region ユーザー名を取得する。 // Substringする。 - string temp = this.txtConnString.Text; + string temp = this.ConnString; int start = temp.IndexOf("User Id=") + "User Id=".Length; int end = temp.IndexOf(";", start); temp = temp.Substring(start, end - start); @@ -1138,8 +1307,8 @@ private void btnListTable_Click(object sender, EventArgs e) #endregion // 注釈 - //MessageBox.Show("[" + userId + "]スキーマ(ユーザ)の所有するテーブルのみを対象とします(Oracle用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); - MessageBox.Show(string.Format(this.RM_GetString("CautionPrerequisiteOracle"), userId), this.RM_GetString("CautionPrerequisiteCaption")); + //this.ShowMessage("[" + userId + "]スキーマ(ユーザ)の所有するテーブルのみを対象とします(Oracle用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); + this.ShowMessage(string.Format(this.RM_GetString("CautionPrerequisiteOracle"), userId), this.RM_GetString("CautionPrerequisiteCaption")); #region テーブル・ビューの情報を取得 @@ -1183,13 +1352,13 @@ private void btnListTable_Click(object sender, EventArgs e) #endregion } - else if (this.rbnMySQL.Checked) + else if (this.Dap == "MCN") { #region MySQL // 注釈 - // MessageBox.Show("同一DB上で同一名の複数のテーブルを持たないこと(MySQL用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); - MessageBox.Show(string.Format(this.RM_GetString("CautionPrerequisite"), "MySQL"), this.RM_GetString("CautionPrerequisiteCaption")); + // this.ShowMessage("同一DB上で同一名の複数のテーブルを持たないこと(MySQL用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); + this.ShowMessage(string.Format(this.RM_GetString("CautionPrerequisite"), "MySQL"), this.RM_GetString("CautionPrerequisiteCaption")); #region テーブル・ビューの情報を取得 @@ -1218,13 +1387,13 @@ private void btnListTable_Click(object sender, EventArgs e) #endregion } #if NETCOREAPP - else if (this.rbnPstgrs.Checked) + else if (this.Dap == "NPS") { #region PostgreSQL // 注釈 - //MessageBox.Show("同一DB上で同一名の複数のテーブルを持たないこと(PostgreSQL用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); - MessageBox.Show(string.Format(this.RM_GetString("CautionPrerequisite"), "PostgreSQL"), this.RM_GetString("CautionPrerequisiteCaption")); + //this.ShowMessage("同一DB上で同一名の複数のテーブルを持たないこと(PostgreSQL用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); + this.ShowMessage(string.Format(this.RM_GetString("CautionPrerequisite"), "PostgreSQL"), this.RM_GetString("CautionPrerequisiteCaption")); #region テーブル・ビューの情報を取得 @@ -1255,13 +1424,13 @@ private void btnListTable_Click(object sender, EventArgs e) #endregion } #else - else if (this.rbnOLE.Checked) + else if (this.Dap == "OLE") { #region OLEDB // 注釈 - //MessageBox.Show("同一DB上で同一名の複数のテーブルを持たないこと(OLEDB用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); - MessageBox.Show(string.Format(this.RM_GetString("CautionPrerequisite"), "OLEDB"), this.RM_GetString("CautionPrerequisiteCaption")); + //this.ShowMessage("同一DB上で同一名の複数のテーブルを持たないこと(OLEDB用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); + this.ShowMessage(string.Format(this.RM_GetString("CautionPrerequisite"), "OLEDB"), this.RM_GetString("CautionPrerequisiteCaption")); #region テーブル・ビューの情報を取得 @@ -1295,13 +1464,13 @@ private void btnListTable_Click(object sender, EventArgs e) #endregion } - else if (this.rbnDB2.Checked) + else if (this.Dap == "DB2") { #region DB2 // 注釈 - //MessageBox.Show("同一DB上で同一名の複数のテーブルを持たないこと(DB2用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); - MessageBox.Show(string.Format(this.RM_GetString("CautionPrerequisite"), "DB2"), this.RM_GetString("CautionPrerequisiteCaption")); + //this.ShowMessage("同一DB上で同一名の複数のテーブルを持たないこと(DB2用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); + this.ShowMessage(string.Format(this.RM_GetString("CautionPrerequisite"), "DB2"), this.RM_GetString("CautionPrerequisiteCaption")); #region テーブル・ビューの情報を取得 /* @@ -1352,13 +1521,13 @@ private void btnListTable_Click(object sender, EventArgs e) #endregion } - else if (this.rbnHiRDB.Checked) + else if (this.Dap == "HIR") { #region HiRDB // 注釈 - //MessageBox.Show("同一DB上で同一名の複数のテーブルを持たないこと(HiRDB用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); - MessageBox.Show(string.Format(this.RM_GetString("CautionPrerequisite"), "ODBC"), this.RM_GetString("CautionPrerequisiteCaption")); + //this.ShowMessage("同一DB上で同一名の複数のテーブルを持たないこと(HiRDB用のD層自動生成ツールの仕様です)", "-注意(前提条件)-"); + this.ShowMessage(string.Format(this.RM_GetString("CautionPrerequisite"), "ODBC"), this.RM_GetString("CautionPrerequisiteCaption")); #region テーブル・ビューの情報を取得 /* @@ -1416,53 +1585,21 @@ private void btnListTable_Click(object sender, EventArgs e) } #endregion - #region デバッグ - if (this.cbxDebug.Checked) - { - // テーブル情報 - if (dtSchmaTables != null) - { - //this.tabPage1.Text = "テーブル情報"; - this.tabPage1.Text = this.RM_GetString("TabPage1TableInfo"); - this.dataGridView1.DataSource = dtSchmaTables; - } - // ヴュー情報 - if (dtSchmaViews != null) - { - //this.tabPage2.Text = "ヴュー情報"; - this.tabPage2.Text = this.RM_GetString("TabPage2VieuxInfo"); - this.dataGridView2.DataSource = dtSchmaViews; - } - } - #endregion - - // リスト ボックスを更新する。 - this.LbxUpdateItems(); - - // ボタン状態の変更 - this.gbxDataProviders.Enabled = false; - this.rbnMySQL.Enabled = false; - this.txtConnString.Enabled = false; - - this.btnDelTable.Enabled = true; - this.btnLoadColumn.Enabled = true; + // 取得したスキーマ情報を保持する(デバッグ表示用)。 + this.DtSchmaTables = dtSchmaTables; + this.DtSchmaViews = dtSchmaViews; - this.btnSetPrimaryKey.Enabled = false; - - this.cmbEncoding.Enabled = false; - this.btnDaoDefinitionGen.Enabled = false; + return true; } catch (Exception ex) { - MessageBox.Show(this.RM_GetString("RuntimeError") + ex.Message); + this.ShowMessage(this.RM_GetString("RuntimeError") + ex.Message); + return false; } finally { // コネクション クローズ this.ConnectionClose(); - - // カーソルを元に戻す - System.Windows.Forms.Cursor.Current = Cursors.Default; } } @@ -1478,6 +1615,67 @@ private void btnDelTable_Click(object sender, EventArgs e) /// <summary>スキーマ情報を読み込み、列情報をロードする。</summary> private void btnLoadColumn_Click(object sender, EventArgs e) + { + // カーソルを待機状態にする + System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; + + try + { + // UIコントロールから情報を取得し、ロード処理を呼び出す。 + this.ConnString = this.txtConnString.Text; + + if (!this.LoadColumn()) + { + // 失敗した場合、UIコントロールへの反映は行わない。 + return; + } + + #region デバッグ + if (this.cbxDebug.Checked) + { + // カラム情報 + if (this.DtSchmaColumns != null) + { + // this.tabPage1.Text = "カラム情報"; + this.tabPage1.Text = this.RM_GetString("TabPage1ColumnInfo"); + this.dataGridView1.DataSource = this.DtSchmaColumns; + } + // 主キー情報 + if (this.DtSchmaPrimaryKeys != null) + { + //this.tabPage2.Text = "主キー情報"; + this.tabPage2.Text = this.RM_GetString("TabPage2PrimarykeyInfo"); + this.dataGridView2.DataSource = this.DtSchmaPrimaryKeys; + } + // インデックス カラム情報 + if (this.DtSchmaIndexColumns != null) + { + //this.tabPage3.Text = "インデックス カラム情報"; + this.tabPage3.Text = this.RM_GetString("TabPage3IndexColInfo"); + this.dataGridView3.DataSource = this.DtSchmaIndexColumns; + } + } + #endregion + + // ボタン状態の変更 + this.btnLoadColumn.Enabled = false; + + this.btnSetPrimaryKey.Enabled = true; + + this.cmbEncoding.Enabled = true; + this.btnDaoDefinitionGen.Enabled = true; + } + finally + { + // カーソルを元に戻す + System.Windows.Forms.Cursor.Current = Cursors.Default; + } + } + + /// <summary>スキーマ情報を読み込み、列情報をロードする(GUI/CUI 共通)。</summary> + /// <returns>成功した場合 true</returns> + /// <remarks>UIコントロールを参照しないため、フォームを表示せずに呼び出せる。</remarks> + private bool LoadColumn() { try { @@ -1492,49 +1690,50 @@ private void btnLoadColumn_Click(object sender, EventArgs e) // コネクション オープン this.ConnectionOpen(); - // カーソルを待機状態にする - System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; - #region 型情報を取得 - if (this.rbnSQL.Checked) + if (this.Dap == "SQL") { // DataTypes CmnMethods.DataTypes = this.SqlCn.GetSchema(System.Data.Common.DbMetaDataCollectionNames.DataTypes); } - else if (this.rbnODB.Checked) + else if (this.Dap == "ODB") { // DataTypes CmnMethods.DataTypes = this.OdbCn.GetSchema(System.Data.Common.DbMetaDataCollectionNames.DataTypes); } - else if (this.rbnODP.Checked) + else if (this.Dap == "ODP") { // DataTypes CmnMethods.DataTypes = this.OdpCn.GetSchema(System.Data.Common.DbMetaDataCollectionNames.DataTypes); } - else if (this.rbnMySQL.Checked) + else if (this.Dap == "MCN") { // DataTypes CmnMethods.DataTypes = this.MySqlCn.GetSchema(System.Data.Common.DbMetaDataCollectionNames.DataTypes); } - else if (this.rbnPstgrs.Checked) +#if NETCOREAPP + // ↓↓↓【変更】↓↓↓ + // 以前のNpgsqlはDataTypesをサポートしていなかったため、型情報を取得していなかったが、 + // 現在はサポートされているため、他のデータ プロバイダと同様に取得する。 + else if (this.Dap == "NPS") { - //// DataTypes(NpgsqlではDataTypesがサポートされていない) - //CmnMethods.DataTypes = this.NpgsqlCn.GetSchema(System.Data.Common.DbMetaDataCollectionNames.DataTypes); + // DataTypes + CmnMethods.DataTypes = this.NpgsqlCn.GetSchema(System.Data.Common.DbMetaDataCollectionNames.DataTypes); } -#if NETCOREAPP + // ↑↑↑【変更】↑↑↑ #else - else if (this.rbnOLE.Checked) + else if (this.Dap == "OLE") { // DataTypes CmnMethods.DataTypes = this.OleCn.GetSchema(System.Data.Common.DbMetaDataCollectionNames.DataTypes); } - /*else if (this.rbnDB2.Checked) + /*else if (this.Dap == "DB2") { // DataTypes CmnMethods.DataTypes = this.DB2Cn.GetSchema(System.Data.Common.DbMetaDataCollectionNames.DataTypes); } - else if (this.rbnHiRDB.Checked) + else if (this.Dap == "HIR") { // DataTypes CmnMethods.DataTypes = this.HiRDBCn.GetSchema(System.Data.Common.DbMetaDataCollectionNames.DataTypes); @@ -1555,7 +1754,7 @@ private void btnLoadColumn_Click(object sender, EventArgs e) DataTable dtSchmaIndexColumns = null; #region 列情報をロード - if (this.rbnSQL.Checked) + if (this.Dap == "SQL") { #region SQL Server @@ -1595,115 +1794,69 @@ private void btnLoadColumn_Click(object sender, EventArgs e) #region 主キーの情報を取得 - // テーブルを取得 - foreach (CTable table in this.HtSchemaCustom.Values) + // ↓↓↓【変更】↓↓↓ + // 以前は、sp_helpconstraint で主キー インデックス名を取得し、 + // sp_MShelpindex で主キー列名(indCol1~indCol16)を取得していたが、下記の理由でカタログ ビューに変更した。 + // ・sp_MShelpindex は非公開のストアド プロシージャであり、内部で一時テーブル(tempdbの照合順序)と + // sysindexes.name(DBの照合順序)を文字列比較するため、両者が異なる環境では照合順序の競合で失敗する。 + // ・主キーが16列までという制限があった。 + // ・テーブルごとに2回、DBへ問い合わせていた。 + // カタログ ビューの結合キーは全てID(整数)であるため、照合順序の影響を受けない。 + + // 主キー情報を取得 + SqlCommand cmdPrimaryKeys = new SqlCommand( + "SELECT t.name AS TABLE_NAME, c.name AS COLUMN_NAME, ic.key_ordinal AS KEY_ORDINAL" + + " FROM sys.indexes AS i" + + " INNER JOIN sys.index_columns AS ic" + + " ON i.object_id = ic.object_id AND i.index_id = ic.index_id" + + " INNER JOIN sys.columns AS c" + + " ON ic.object_id = c.object_id AND ic.column_id = c.column_id" + + " INNER JOIN sys.tables AS t ON i.object_id = t.object_id" + + " WHERE i.is_primary_key = 1" + + " ORDER BY t.name, ic.key_ordinal", this.SqlCn); + + dtSchmaPrimaryKeys = new DataTable(); + + SqlDataReader drd = cmdPrimaryKeys.ExecuteReader(); + dtSchmaPrimaryKeys.Load(drd); + drd.Close(); + + // 主キーの設定 + foreach (System.Data.DataRow row in dtSchmaPrimaryKeys.Rows) { - // 存在チェック - if (!((CTable)this.HtSchemaCustom[table.Name]).Effective) - { - continue; // 存在しない場合スキップする処理を追加 - } + // テーブルを取得 + CTable table = (CTable)this.HtSchemaCustom[(string)row["TABLE_NAME"]]; - // ワーク - SqlDataReader drd = null; - DataTable dtSchmaConstraint = new DataTable(); - DataTable dtSchmaIndex = new DataTable(); - - // 主キー名 - string pkName = ""; - // 主キーレコード - System.Data.DataRow pkRow = null; - - // sp_helpconstraintストアドプロシージャで、主キー インデックス名を取得 - SqlCommand cmd_sp_help = new SqlCommand("sp_helpconstraint", this.SqlCn); - cmd_sp_help.CommandType = CommandType.StoredProcedure; - cmd_sp_help.Parameters.Add(new SqlParameter("@objname", table.Name)); - - // sp_helpconstraintストアドプロシージャの結果セット(制約に関する結果セット) - drd = cmd_sp_help.ExecuteReader(); - drd.NextResult(); // 1つスキップする。 - dtSchmaConstraint.Load(drd); - drd.Close(); - - // 制約レコードを取得する。 - foreach (System.Data.DataRow row in dtSchmaConstraint.Rows) + // 有効なテーブルにのみ設定する。 + if (table == null) { - // 制約レコードが主キーか? - if (row["constraint_type"].ToString().IndexOf( - "PRIMARY KEY", StringComparison.CurrentCultureIgnoreCase) == -1) - { - // 主キーでない。 - } - else - { - // 主キーである。 - pkName = row["constraint_name"].ToString(); - break; - } + // 不明なテーブル } - - // 主キー インデックス名なしの場合 - if (pkName == "") { } else { - - // sp_MShelpindexストアドプロシージャで、主キー列名を取得 - SqlCommand sp_MShelpindex = new SqlCommand("sp_MShelpindex", this.SqlCn); - sp_MShelpindex.CommandType = CommandType.StoredProcedure; - sp_MShelpindex.Parameters.Add(new SqlParameter("@tablename", table.Name)); - - // sp_helpconstraintストアドプロシージャの結果セット(制約に関する結果セット) - drd = sp_MShelpindex.ExecuteReader(); - dtSchmaIndex.Load(drd); - drd.Close(); - - // 主キー レコードを取得する。 - foreach (System.Data.DataRow row in dtSchmaIndex.Rows) + // 有効なテーブル + if (table.Effective) { - // 主キー インデックスか? - if (row["name"].ToString() == pkName) - { - // 主キー インデックスである。 - pkRow = row; - break; - } - else - { - // 主キー インデックスでない。 - - } - } + // 主キー列 + CColumn column = (CColumn)table.HtColumns_Name[(string)row["COLUMN_NAME"]]; - // 主キー レコードなしの場合 - if (pkRow == null) { } - else - { - // 列のIsKeyフラグを立てる。 - for (int i = 1; i <= 16; i++) + // nullの時があるようなので、この場合は処理しない。 + if (column == null) { } + else { - // 主キー列 - CColumn column = (CColumn)table.HtColumns_Name[pkRow["indCol" + i.ToString()].ToString()]; - - // nullの時があるようなので、この場合は処理しない。 - if (column == null) - { - // 無い場合は抜ける。 - break; - } - else - { - column.IsKey = true; - } + // 列のIsKeyフラグを立てる。 + column.IsKey = true; } } } } + // ↑↑↑【変更】↑↑↑ #endregion #endregion } - else if (this.rbnODB.Checked) + else if (this.Dap == "ODB") { #region ODBC.NET @@ -1741,14 +1894,14 @@ private void btnLoadColumn_Click(object sender, EventArgs e) #endregion } - else if (this.rbnODP.Checked) + else if (this.Dap == "ODP") { #region Oracle // 接続文字列から"User Id"値を取得。 - start = this.txtConnString.Text.IndexOf("User Id=") + "User Id=".Length; - end = this.txtConnString.Text.IndexOf(";", start); - userId = this.txtConnString.Text.Substring(start, end - start).Trim(); + start = this.ConnString.IndexOf("User Id=") + "User Id=".Length; + end = this.ConnString.IndexOf(";", start); + userId = this.ConnString.Substring(start, end - start).Trim(); #region カラムの情報を取得 @@ -1859,7 +2012,7 @@ private void btnLoadColumn_Click(object sender, EventArgs e) #endregion } - else if (this.rbnMySQL.Checked) + else if (this.Dap == "MCN") { #region MySQL @@ -1899,7 +2052,7 @@ private void btnLoadColumn_Click(object sender, EventArgs e) #endregion } #if NETCOREAPP - else if (this.rbnPstgrs.Checked) + else if (this.Dap == "NPS") { #region PostgreSQL @@ -1922,10 +2075,14 @@ private void btnLoadColumn_Click(object sender, EventArgs e) // 有効なテーブル if (table.Effective) { + // ↓↓↓【変更】↓↓↓ + // 以前はNpgsqlがDataTypesをサポートしていなかったため + // ".NET型情報"を"System.Object"固定にしていたが、 + // 現在はサポートされているため、他のデータ プロバイダと同様に変換する。 CColumn column = new CColumn( - (string)row["COLUMN_NAME"], (string)row["DATA_TYPE"], "System.Object"); - //CmnMethods.ConvertToDotNetTypeInfo((string)row["DATA_TYPE"])); - //(NpgsqlではDataTypesがサポートされていないため) + (string)row["COLUMN_NAME"], (string)row["DATA_TYPE"], + CmnMethods.ConvertToDotNetTypeInfo((string)row["DATA_TYPE"])); + // ↑↑↑【変更】↑↑↑ // ポジションをキーにしてカラムを追加 table.HtColumns_Position[row["ORDINAL_POSITION"].ToString()] = column; @@ -1940,7 +2097,7 @@ private void btnLoadColumn_Click(object sender, EventArgs e) #endregion } #else - else if (this.rbnOLE.Checked) + else if (this.Dap == "OLE") { #region OLEDB.NET @@ -1979,7 +2136,7 @@ private void btnLoadColumn_Click(object sender, EventArgs e) #endregion } - /*else if (this.rbnDB2.Checked) + /*else if (this.Dap == "DB2") { #region DB2 @@ -2018,7 +2175,7 @@ private void btnLoadColumn_Click(object sender, EventArgs e) #endregion } - else if (this.rbnHiRDB.Checked) + else if (this.Dap == "HIR") { #region HiRDB @@ -2064,52 +2221,22 @@ private void btnLoadColumn_Click(object sender, EventArgs e) } #endregion - #region デバッグ - if (this.cbxDebug.Checked) - { - // カラム情報 - if (dtSchmaColumns != null) - { - // this.tabPage1.Text = "カラム情報"; - this.tabPage1.Text = this.RM_GetString("TabPage1ColumnInfo"); - this.dataGridView1.DataSource = dtSchmaColumns; - } - // 主キー情報 - if (dtSchmaPrimaryKeys != null) - { - //this.tabPage2.Text = "主キー情報"; - this.tabPage2.Text = this.RM_GetString("TabPage2PrimarykeyInfo"); - this.dataGridView2.DataSource = dtSchmaPrimaryKeys; - } - // インデックス カラム情報 - if (dtSchmaIndexColumns != null) - { - //this.tabPage3.Text = "インデックス カラム情報"; - this.tabPage3.Text = this.RM_GetString("TabPage3IndexColInfo"); - this.dataGridView3.DataSource = dtSchmaIndexColumns; - } - } - #endregion - - // ボタン状態の変更 - this.btnLoadColumn.Enabled = false; - - this.btnSetPrimaryKey.Enabled = true; + // 取得したスキーマ情報を保持する(デバッグ表示用)。 + this.DtSchmaColumns = dtSchmaColumns; + this.DtSchmaPrimaryKeys = dtSchmaPrimaryKeys; + this.DtSchmaIndexColumns = dtSchmaIndexColumns; - this.cmbEncoding.Enabled = true; - this.btnDaoDefinitionGen.Enabled = true; + return true; } catch (Exception ex) { - MessageBox.Show(this.RM_GetString("RuntimeError") + ex.Message); + this.ShowMessage(this.RM_GetString("RuntimeError") + ex.Message); + return false; } finally { // コネクション クローズ this.ConnectionClose(); - - // カーソルを元に戻す - System.Windows.Forms.Cursor.Current = Cursors.Default; } } @@ -2169,111 +2296,135 @@ private void btnDaoDefinitionGen_Click(object sender, EventArgs e) sfd.Title = this.RM_GetString("SaveFileDialogTitle"); DialogResult dRet = sfd.ShowDialog(); - // ストリームライター - StreamWriter sw = null; - StreamWriter sw_DBTypeInfo = null; - StreamWriter sw_DotNetTypeInfo = null; + // カーソルを待機状態にする + System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; try { - // カーソルを待機状態にする - System.Windows.Forms.Cursor.Current = Cursors.WaitCursor; - if (dRet == DialogResult.OK) { // OKで - if (sfd.FileName == "") + // UIコントロールから情報を取得し、生成処理を呼び出す。 + if (this.WriteDaoDefinition(sfd.FileName, (int)this.cmbEncoding.SelectedValue)) { - // ファイルが指定されていない。 + // メッセージ + //MessageBox.Show("D層定義情報の生成完了!"); + MessageBox.Show(this.RM_GetString("DlayerGeneratedMessage")); } - else - { - // ファイルが指定されている。 + } + else + { + // メッセージ + //MessageBox.Show("操作はキャンセルされました。"); + MessageBox.Show(this.RM_GetString("DLayerCancelledmessage")); + } + } + finally + { + // カーソルを元に戻す + System.Windows.Forms.Cursor.Current = Cursors.Default; + } + } + + /// <summary>D層定義情報ファイルを出力する(GUI/CUI 共通)。</summary> + /// <param name="filePath">出力先ファイル パス(*.csv)</param> + /// <param name="codePage">出力エンコーディングのコード ページ</param> + /// <returns>成功した場合 true</returns> + /// <remarks>UIコントロールを参照しないため、フォームを表示せずに呼び出せる。</remarks> + private bool WriteDaoDefinition(string filePath, int codePage) + { + // ストリームライター + StreamWriter sw = null; + StreamWriter sw_DBTypeInfo = null; + StreamWriter sw_DotNetTypeInfo = null; + + try + { + if (filePath == "") + { + // ファイルが指定されていない。 + } + else + { + // ファイルが指定されている。 - // ファイル出力 + // ファイル出力 - // エンコーディングの指定 - Encoding enc = Encoding.GetEncoding((int)this.cmbEncoding.SelectedValue); + // エンコーディングの指定 + Encoding enc = Encoding.GetEncoding(codePage); - // ファイル ストリームを生成する。 - int temp = sfd.FileName.Length - 4; - sw = new StreamWriter(sfd.FileName, false, enc); - sw_DBTypeInfo = new StreamWriter(sfd.FileName.Substring(0, temp) + "_DBTypeInfo" + sfd.FileName.Substring(temp), false, enc); - sw_DotNetTypeInfo = new StreamWriter(sfd.FileName.Substring(0, temp) + "_DotNetTypeInfo" + sfd.FileName.Substring(temp), false, enc); + // ファイル ストリームを生成する。 + int temp = filePath.Length - 4; + sw = new StreamWriter(filePath, false, enc); + sw_DBTypeInfo = new StreamWriter(filePath.Substring(0, temp) + "_DBTypeInfo" + filePath.Substring(temp), false, enc); + sw_DotNetTypeInfo = new StreamWriter(filePath.Substring(0, temp) + "_DotNetTypeInfo" + filePath.Substring(temp), false, enc); - // ファイル ヘッダーを出力 - //sw.WriteLine("テーブル名,カラム情報~"); - sw.WriteLine(this.RM_GetString("TableNameColInfo")); - //sw_DBTypeInfo.WriteLine("テーブル名,カラムDB型情報~"); - sw_DBTypeInfo.WriteLine(this.RM_GetString("TableNameColDbTypeInfo")); - //sw_DotNetTypeInfo.WriteLine("テーブル名,カラム.NET型情報~"); - sw_DotNetTypeInfo.WriteLine(this.RM_GetString("TableNameColdotNetTypeInfo")); + // ファイル ヘッダーを出力 + //sw.WriteLine("テーブル名,カラム情報~"); + sw.WriteLine(this.RM_GetString("TableNameColInfo")); + //sw_DBTypeInfo.WriteLine("テーブル名,カラムDB型情報~"); + sw_DBTypeInfo.WriteLine(this.RM_GetString("TableNameColDbTypeInfo")); + //sw_DotNetTypeInfo.WriteLine("テーブル名,カラム.NET型情報~"); + sw_DotNetTypeInfo.WriteLine(this.RM_GetString("TableNameColdotNetTypeInfo")); - // テーブルを処理 - foreach (CTable table in this.HtSchemaCustom.Values) + // テーブルを処理 + foreach (CTable table in this.HtSchemaCustom.Values) + { + // 有効なテーブルだけ出力 + if (table.Effective) { - // 有効なテーブルだけ出力 - if (table.Effective) + // カラム ポジションを昇順にソートする + ArrayList sort = CmnMethods.sortColumn(table.HtColumns_Position); + + // 1行目 + string pk = ""; + string pk_DBTypeInfo = ""; + string pk_DotNetTypeInfo = ""; + // 2行目 + string _else = ""; + string _else_DBTypeInfo = ""; + string _else_DotNetTypeInfo = ""; + + // ソート後のカラム ポジション配列を廻す + foreach (Int32 position in sort) { - // カラム ポジションを昇順にソートする - ArrayList sort = CmnMethods.sortColumn(table.HtColumns_Position); - - // 1行目 - string pk = ""; - string pk_DBTypeInfo = ""; - string pk_DotNetTypeInfo = ""; - // 2行目 - string _else = ""; - string _else_DBTypeInfo = ""; - string _else_DotNetTypeInfo = ""; - - // ソート後のカラム ポジション配列を廻す - foreach (Int32 position in sort) - { - // カラムを取得 - CColumn column = (CColumn)table.HtColumns_Position[position.ToString()]; + // カラムを取得 + CColumn column = (CColumn)table.HtColumns_Position[position.ToString()]; - if (column.IsKey) - { - // 主キー列 // 1行目 - pk += column.Name + ","; - pk_DBTypeInfo += column.DBTypeInfo + ","; - pk_DotNetTypeInfo += column.DotNetTypeInfo + ","; - } - else - { - // その他の列 // 2行目 - _else += column.Name + ","; - _else_DBTypeInfo += column.DBTypeInfo + ","; - _else_DotNetTypeInfo += column.DotNetTypeInfo + ","; - } + if (column.IsKey) + { + // 主キー列 // 1行目 + pk += column.Name + ","; + pk_DBTypeInfo += column.DBTypeInfo + ","; + pk_DotNetTypeInfo += column.DotNetTypeInfo + ","; + } + else + { + // その他の列 // 2行目 + _else += column.Name + ","; + _else_DBTypeInfo += column.DBTypeInfo + ","; + _else_DotNetTypeInfo += column.DotNetTypeInfo + ","; } - - // 1行目 - sw.WriteLine(table.Name + "," + pk); - sw_DBTypeInfo.WriteLine(table.Name + "," + pk_DBTypeInfo); - sw_DotNetTypeInfo.WriteLine(table.Name + "," + pk_DotNetTypeInfo); - // 2行目 - sw.WriteLine("," + _else); - sw_DBTypeInfo.WriteLine("," + _else_DBTypeInfo); - sw_DotNetTypeInfo.WriteLine("," + _else_DotNetTypeInfo); } + + // 1行目 + sw.WriteLine(table.Name + "," + pk); + sw_DBTypeInfo.WriteLine(table.Name + "," + pk_DBTypeInfo); + sw_DotNetTypeInfo.WriteLine(table.Name + "," + pk_DotNetTypeInfo); + // 2行目 + sw.WriteLine("," + _else); + sw_DBTypeInfo.WriteLine("," + _else_DBTypeInfo); + sw_DotNetTypeInfo.WriteLine("," + _else_DotNetTypeInfo); } } - // メッセージ - //MessageBox.Show("D層定義情報の生成完了!"); - MessageBox.Show(this.RM_GetString("DlayerGeneratedMessage")); - } - else - { - // メッセージ - //MessageBox.Show("操作はキャンセルされました。"); - MessageBox.Show(this.RM_GetString("DLayerCancelledmessage")); } + + return true; } catch (Exception ex) { - MessageBox.Show(this.RM_GetString("RuntimeError") + ex.Message); + this.ShowMessage(this.RM_GetString("RuntimeError") + ex.Message); + return false; } finally { @@ -2307,12 +2458,209 @@ private void btnDaoDefinitionGen_Click(object sender, EventArgs e) // nullでない場合、閉じる。 sw_DotNetTypeInfo.Close(); } + } + } - // カーソルを元に戻す - System.Windows.Forms.Cursor.Current = Cursors.Default; + #endregion + + #region CUI(ヘッドレス実行) + + // ↓↓↓【追加】↓↓↓ + + /// <summary>D層定義情報ファイルを生成する(CUI)。</summary> + /// <param name="opt">生成オプション(UIコントロールに依存しない)</param> + /// <returns>成功した場合 true</returns> + /// <remarks> + /// GUI で「テーブルを一覧」→「列情報のロード」→「主キー情報の設定」 + /// →「D層定義情報の生成」と操作するのと同じ処理を、非対話で順に実行する。 + /// </remarks> + public bool DaoDefinitionGen(DaoDefinitionOptions opt) + { + // 接続情報の設定(GUIではラジオ ボタンとテキスト ボックスから設定される) + this.Dap = opt.Dap; + this.ConnString = opt.ConnectionString; + + // テーブル・ビューをリストする。 + if (!this.ListTable()) + { + return false; + } + + // 生成対象のテーブル・ビューを絞り込む。 + if (!this.SelectTables(opt.Tables, opt.ExcludeTables)) + { + return false; + } + + // 列情報をロードする。 + if (!this.LoadColumn()) + { + return false; + } + + // 主キー情報を設定する。 + if (!this.SetPrimaryKeys(opt.PrimaryKeys)) + { + return false; + } + + // 生成対象を表示する。 + foreach (CTable table in this.HtSchemaCustom.Values) + { + if (table.Effective) + { + this.ShowMessage("対象:" + table.Name); + } + } + + // D層定義情報ファイルを出力する。 + return this.WriteDaoDefinition(opt.OutputFilePath, opt.CodePage); + } + + /// <summary>生成対象のテーブル・ビューを絞り込む。</summary> + /// <param name="tables">生成対象とするテーブル・ビュー名の配列(空の場合は全て)</param> + /// <param name="excludeTables">生成対象から除外するテーブル・ビュー名の配列</param> + /// <returns>成功した場合 true</returns> + /// <remarks>GUI の「テーブルを削除(LbxDeleteItems)」に相当する。</remarks> + private bool SelectTables(string[] tables, string[] excludeTables) + { + // 生成対象の指定がある場合、指定されたテーブル・ビューのみを有効にする。 + if (tables != null && tables.Length != 0) + { + // 一旦、全て無効にする。 + foreach (CTable table in this.HtSchemaCustom.Values) + { + table.Effective = false; + } + + foreach (string tableName in tables) + { + CTable table = this.FindTable(tableName); + + if (table == null) + { + this.ShowMessage(string.Format( + "エラー:テーブル・ビュー[{0}]が見つかりません。", tableName)); + return false; + } + else + { + table.Effective = true; + } + } + } + + // 除外の指定がある場合、指定されたテーブル・ビューを無効にする。 + if (excludeTables != null) + { + foreach (string tableName in excludeTables) + { + CTable table = this.FindTable(tableName); + + if (table == null) + { + this.ShowMessage(string.Format( + "エラー:テーブル・ビュー[{0}]が見つかりません。", tableName)); + return false; + } + else + { + table.Effective = false; + } + } + } + + return true; + } + + /// <summary>主キー情報を設定する。</summary> + /// <param name="primaryKeys">主キー情報(キー:テーブル名、値:主キー列名の配列)</param> + /// <returns>成功した場合 true</returns> + /// <remarks> + /// GUI の「主キー情報の設定(SetPrimaryKeyWindow)」に相当する。 + /// 指定されたテーブルの主キーは、DBMS から取得した情報ではなく、この指定で置き換える。 + /// </remarks> + private bool SetPrimaryKeys(Dictionary<string, string[]> primaryKeys) + { + if (primaryKeys == null) + { + return true; + } + + foreach (KeyValuePair<string, string[]> kvp in primaryKeys) + { + CTable table = this.FindTable(kvp.Key); + + if (table == null) + { + this.ShowMessage(string.Format( + "エラー:テーブル・ビュー[{0}]が見つかりません。", kvp.Key)); + return false; + } + + // 指定されたテーブルの主キーを一旦クリアする。 + foreach (CColumn column in table.HtColumns_Name.Values) + { + column.IsKey = false; + } + + // 主キー列のIsKeyフラグを立てる。 + foreach (string columnName in kvp.Value) + { + CColumn column = this.FindColumn(table, columnName); + + if (column == null) + { + this.ShowMessage(string.Format( + "エラー:テーブル・ビュー[{0}]にカラム[{1}]が見つかりません。", + table.Name, columnName)); + return false; + } + else + { + column.IsKey = true; + } + } } + + return true; } + /// <summary>テーブル・ビューを検索する(大文字・小文字を区別しない)。</summary> + /// <param name="tableName">テーブル・ビュー名</param> + /// <returns>テーブル・ビュー(見つからない場合はnull)</returns> + private CTable FindTable(string tableName) + { + foreach (CTable table in this.HtSchemaCustom.Values) + { + if (string.Compare(table.Name, tableName, true) == 0) + { + return table; + } + } + + return null; + } + + /// <summary>カラムを検索する(大文字・小文字を区別しない)。</summary> + /// <param name="table">テーブル・ビュー</param> + /// <param name="columnName">カラム名</param> + /// <returns>カラム(見つからない場合はnull)</returns> + private CColumn FindColumn(CTable table, string columnName) + { + foreach (CColumn column in table.HtColumns_Name.Values) + { + if (string.Compare(column.Name, columnName, true) == 0) + { + return column; + } + } + + return null; + } + + // ↑↑↑【追加】↑↑↑ + #endregion /// <summary>D層、Daoクラスファイル、SQLファイルを生成する。</summary> diff --git a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Form2.cs b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Form2.cs index 401d95daf..4be2cbaef 100644 --- a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Form2.cs +++ b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Form2.cs @@ -52,6 +52,7 @@ //* added constant to get the TimeStamp placeholder from the app.config file and //* did code modification to replace the required TimeStamp code in the template, if TimeStamp selected in the tool. //* 2015/06/18 Sai-san Added <Else></Else> tag in create string method and ReplaceSQL method to fix the bug 'DynInsParameter of dynamic insert'. +//* 2026/07/31 玄人 幸道 GUIのCUI化(イベント ハンドラのロジックを関数化) //********************************************************************************** using System; @@ -822,10 +823,10 @@ private void OpenSrDefInfo(out StreamReader ddi, out StreamReader dti, out Strea Encoding enc = null; // DDE:D層定義情報のEncoding - enc = Encoding.GetEncoding((int)this.cmbDDEncoding.SelectedValue); + enc = Encoding.GetEncoding(this.genDaoDefCodePage); // 読込ファイル ストリームを生成する。 - ddi = new StreamReader(this.txtSetDaoDefinition.Text, enc); + ddi = new StreamReader(this.genDaoDefinitionFilePath, enc); // ↓↓↓【追加】↓↓↓ // +エンティテイ生成+型付きデータセット生成 @@ -866,12 +867,12 @@ private StreamReader OpenSrTemplate(string templateFilePath, int encoding) private StreamWriter OpenSwClassFile(string fileName, string extension) { // ファイルパス情報の作成 - string tempPath = this.CreateFilePath(this.txtSetOutput.Text, fileName, extension); + string tempPath = this.CreateFilePath(this.genOutputPath, fileName, extension); // 書込ファイル ストリームを生成する。 // DFE:DaoClassファイルのEncoding - return new StreamWriter(tempPath, false, Encoding.GetEncoding((int)this.cmbDFEncoding.SelectedValue)); + return new StreamWriter(tempPath, false, Encoding.GetEncoding(this.genClassFileCodePage)); } /// <summary>SQLファイルを開く(書込)</summary> @@ -880,12 +881,12 @@ private StreamWriter OpenSwClassFile(string fileName, string extension) private StreamWriter OpenSwSQLFile(string fileName, string extension) { // ファイルパス情報の作成 - string tempPath = this.CreateFilePath(this.txtSetOutput.Text, fileName, extension); + string tempPath = this.CreateFilePath(this.genOutputPath, fileName, extension); // 書込ファイル ストリームを生成する。 // SFE:SQLファイルのEncoding - return new StreamWriter(tempPath, false, Encoding.GetEncoding((int)this.cmbSFEncoding.SelectedValue)); + return new StreamWriter(tempPath, false, Encoding.GetEncoding(this.genSqlFileCodePage)); } #endregion @@ -1032,6 +1033,17 @@ private void Form2_Load(object sender, EventArgs e) #endregion + // 設定ファイルからの読み込み + // (UIコントロールに依存しないため、CUIからも呼び出せるよう関数化している) + this.LoadSettingsFromConfig(); + } + + /// <summary> + /// 設定ファイルからテンプレート ファイル名・クラス名・メソッド名などを読み込む(GUI/CUI 共通)。 + /// </summary> + /// <remarks>UIコントロールを参照しないため、フォームを表示せずに呼び出せる。</remarks> + public void LoadSettingsFromConfig() + { #region ファイル名、クラス名、メソッド名(+空文字チェック) #region 読み @@ -1920,9 +1932,116 @@ private void btnSetOutput_Click(object sender, EventArgs e) // メイン ロジック #region 生成処理 + + /// <summary>生成処理が使用するD層定義情報ファイルのパス</summary> + /// <remarks>DaoAndSqlGen の冒頭で DaoGenOptions から設定する(ファイルI/Oヘルパーが参照)。</remarks> + private string genDaoDefinitionFilePath = ""; + + /// <summary>生成処理が使用する出力先フォルダ</summary> + private string genOutputPath = ""; + + /// <summary>D層定義情報ファイルの読み込みコード ページ</summary> + private int genDaoDefCodePage = 65001; + + /// <summary>クラス ファイルの出力コード ページ</summary> + private int genClassFileCodePage = 65001; + + /// <summary>SQL ファイルの出力コード ページ</summary> + private int genSqlFileCodePage = 65001; + + /// <summary>SQL テンプレートの読み込みコード ページ</summary> + private int genSqlTemplateCodePage = 65001; + + /// <summary>LIKE 文</summary> + private string genLikeStatement = "LIKE"; + + /// <summary>エスケープ文字</summary> + private string genEscapeChar = ""; + + /// <summary>CUI(非対話)で起動しているか</summary> + /// <remarks>true の場合、MessageBox の代わりに標準出力へメッセージを出す。</remarks> + public bool IsCui = false; + + /// <summary>メッセージを表示する(GUI:MessageBox/CUI:標準出力)</summary> + /// <param name="message">メッセージ</param> + private void ShowMessage(string message) + { + if (this.IsCui) + { + Console.WriteLine(message); + } + else + { + MessageBox.Show(message); + } + } + + /// <summary>UIコントロールから生成オプションを組み立てる</summary> + /// <returns>生成オプション</returns> + /// <remarks>UIコントロールへの参照は、このメソッドとイベント ハンドラにのみ置く。</remarks> + private DaoGenOptions CreateOptionsFromUI() + { + DaoGenOptions opt = new DaoGenOptions(); + + // 入出力パス + opt.DaoDefinitionFilePath = this.txtSetDaoDefinition.Text; + opt.TemplateRootPath = this.txtSetSourceTemplate.Text; + opt.OutputPath = this.txtSetOutput.Text; + + // データ プロバイダ・言語 + opt.Dap = this.strDAP; + opt.IsCSharp = this.rbnDTL_CS.Checked; + + // 生成対象 + opt.CreateEntity = this.cbxEntity.Checked; + opt.CreateTypedDataSet = this.cbxTypedDataSet.Checked; + opt.CreateTableMaintenance = this.cbxTableMaintenance.Checked; + opt.OnlyDTO = this.cbxOnlyDTO.Checked; + opt.OnlyTableMaintenance = this.cbxOnlyTableMaintenance.Checked; + + // 生成オプション + opt.DaoDefinitionHeader = this.cbxDaoDefinitionHeader.Checked; + opt.EscapeChar = this.txtEscapeChar.Text; + opt.TimeStampColName = this.txtTimeStampColName.Text; + opt.TimeStampUpdMethod = this.txtTimeStampUpdMethod.Text; + opt.FamilyName = this.txtFamilyName.Text; + opt.PersonalName = this.txtPersonalName.Text; + + // エンコーディング + opt.XmlEncoding = this.cmbSFEncoding.Text; + opt.ClassFileCodePage = (int)this.cmbDTEncoding.SelectedValue; + opt.DaoDefinitionCodePage = (int)this.cmbDDEncoding.SelectedValue; + opt.ClassFileOutputCodePage = (int)this.cmbDFEncoding.SelectedValue; + opt.SqlFileCodePage = (int)this.cmbSFEncoding.SelectedValue; + opt.SqlTemplateCodePage = (int)this.cmbSTEncoding.SelectedValue; + opt.LikeStatement = this.cmbLikeStatement.Text; + + return opt; + } + /// <summary>D層、Daoクラスファイル、SQLファイルを生成する。</summary> private void btnDaoAndSqlGen_Click(object sender, EventArgs e) { + // UIコントロールから情報を取得し、生成処理を呼び出す。 + this.DaoAndSqlGen(this.CreateOptionsFromUI()); + } + + /// <summary>D層、Daoクラスファイル、SQLファイルを生成する(GUI/CUI 共通)。</summary> + /// <param name="opt">生成オプション(UIコントロールに依存しない)</param> + /// <returns>成功した場合 true</returns> + public bool DaoAndSqlGen(DaoGenOptions opt) + { + // ファイルI/Oヘルパー(OpenSrDefInfo/OpenSwClassFile/OpenSwSQLFile)が + // 参照するフィールドを設定する。 + this.genDaoDefinitionFilePath = opt.DaoDefinitionFilePath; + this.genOutputPath = opt.OutputPath; + this.genDaoDefCodePage = opt.DaoDefinitionCodePage; + this.genClassFileCodePage = opt.ClassFileOutputCodePage; + this.genSqlFileCodePage = opt.SqlFileCodePage; + this.genSqlTemplateCodePage = opt.SqlTemplateCodePage; + this.genLikeStatement = opt.LikeStatement; + this.genEscapeChar = opt.EscapeChar; + // D層定義情報ファイル StreamReader srDaoDef = null; @@ -1931,10 +2050,10 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) StreamReader srTypeDef = null; // DTO生成フラグの初期化 - this.CreateDTO = (this.cbxEntity.Checked || this.cbxTypedDataSet.Checked); + this.CreateDTO = (opt.CreateEntity || opt.CreateTypedDataSet); // メンテナンス画面生成フラグの初期化 - this.CreateMaintenanceScreen = (this.cbxOnlyTableMaintenance.Checked || this.cbxTableMaintenance.Checked); + this.CreateMaintenanceScreen = (opt.OnlyTableMaintenance || opt.CreateTableMaintenance); // ↑↑↑【追加】↑↑↑ @@ -1943,7 +2062,7 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) StreamReader srDbTypeDef = null; // DB型定義情報ファイル読み込みフラグ設定 - this.ReadDbTypeInfo = (this.ReadDbTypeInfo || rbnODP.Checked); + this.ReadDbTypeInfo = (this.ReadDbTypeInfo || (opt.Dap == "ODP")); // ↑↑↑【追加】↑↑↑ try @@ -1953,7 +2072,7 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) #region 拡張子の設定 - if (this.rbnDTL_CS.Checked) + if (opt.IsCSharp) { // Visual C# this.ClassTemplateFileExtension = "cs"; @@ -1978,13 +2097,13 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) #region D層定義情報ファイル // 標準生成 - fileInfo = new FileInfo(this.txtSetDaoDefinition.Text); + fileInfo = new FileInfo(opt.DaoDefinitionFilePath); if (fileInfo.Exists) { } else { - //MessageBox.Show(string.Format("チェックエラーです:D層定義情報ファイル[{0}]が存在しません。", fileInfo.Name)); - MessageBox.Show(string.Format(this.RM_GetString("FilenotExistDlayerInfo"), fileInfo.Name)); - return; + //this.ShowMessage(string.Format("チェックエラーです:D層定義情報ファイル[{0}]が存在しません。", fileInfo.Name)); + this.ShowMessage(string.Format(this.RM_GetString("FilenotExistDlayerInfo"), fileInfo.Name)); + return false; } // ↓↓↓【追加】↓↓↓ @@ -1992,19 +2111,19 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) if (this.CreateDTO) { // *.CSVである前提の仕様だがOKか?(一応ファイル名を出力する) - int temp = this.txtSetDaoDefinition.Text.Length - 4; + int temp = opt.DaoDefinitionFilePath.Length - 4; this.DotNetTypeInfoFilePath = - this.txtSetDaoDefinition.Text.Substring(0, temp) - + "_DotNetTypeInfo" + this.txtSetDaoDefinition.Text.Substring(temp); + opt.DaoDefinitionFilePath.Substring(0, temp) + + "_DotNetTypeInfo" + opt.DaoDefinitionFilePath.Substring(temp); fileInfo = new FileInfo(this.DotNetTypeInfoFilePath); if (fileInfo.Exists) { } else { - //MessageBox.Show(string.Format("チェックエラーです:.NET型情報ファイル[{0}]が存在しません。", fileInfo.Name)); - MessageBox.Show(string.Format(this.RM_GetString("FilenotExistNETtypeInfo"), fileInfo.Name)); - return; + //this.ShowMessage(string.Format("チェックエラーです:.NET型情報ファイル[{0}]が存在しません。", fileInfo.Name)); + this.ShowMessage(string.Format(this.RM_GetString("FilenotExistNETtypeInfo"), fileInfo.Name)); + return false; } } // ↑↑↑【追加】↑↑↑ @@ -2014,18 +2133,18 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) if (this.ReadDbTypeInfo) { // *.CSVである前提の仕様だがOKか?(一応ファイル名を出力する) - int temp = this.txtSetDaoDefinition.Text.Length - 4; + int temp = opt.DaoDefinitionFilePath.Length - 4; - this.DbTypeInfoFilePath = this.txtSetDaoDefinition.Text.Substring(0, temp) - + "_DBTypeInfo" + this.txtSetDaoDefinition.Text.Substring(temp); + this.DbTypeInfoFilePath = opt.DaoDefinitionFilePath.Substring(0, temp) + + "_DBTypeInfo" + opt.DaoDefinitionFilePath.Substring(temp); fileInfo = new FileInfo(this.DbTypeInfoFilePath); if (fileInfo.Exists) { } else { - //MessageBox.Show(string.Format("チェックエラーです:DB型情報ファイル[{0}]が存在しません。", fileInfo.Name)); - MessageBox.Show(string.Format(this.RM_GetString("FilenotExistDBtypeInfo"), fileInfo.Name)); - return; + //this.ShowMessage(string.Format("チェックエラーです:DB型情報ファイル[{0}]が存在しません。", fileInfo.Name)); + this.ShowMessage(string.Format(this.RM_GetString("FilenotExistDBtypeInfo"), fileInfo.Name)); + return false; } } // ↑↑↑【追加】↑↑↑ @@ -2034,26 +2153,26 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) #region 入力ファイル - dirInfo = new DirectoryInfo(this.txtSetSourceTemplate.Text); + dirInfo = new DirectoryInfo(opt.TemplateRootPath); if (dirInfo.Exists) { } else { - //MessageBox.Show("入力ファイル(テンプレート ファイル)のルート フォルダが存在しません。"); - MessageBox.Show(this.RM_GetString("InputFileRootFolderNotExist")); - return; + //this.ShowMessage("入力ファイル(テンプレート ファイル)のルート フォルダが存在しません。"); + this.ShowMessage(this.RM_GetString("InputFileRootFolderNotExist")); + return false; } #region Dao、Entity、DataSetテンプレート ファイル // Daoテンプレート ファイル - if (!this.cbxOnlyDTO.Checked - && !this.cbxOnlyTableMaintenance.Checked) + if (!opt.OnlyDTO + && !opt.OnlyTableMaintenance) { this.DaoTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.DaoTemplateFileName, this.ClassTemplateFileExtension); } @@ -2064,14 +2183,14 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) // Entityテンプレート ファイル this.EntityTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.EntityTemplateFileName, this.ClassTemplateFileExtension); // DataSetテンプレート ファイル this.DataSetTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.DataSetTemplateFileName, ""); } @@ -2080,55 +2199,55 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) // TableAdapterテンプレート ファイル this.TableAdapterTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.TableAdapterTemplateFileName, this.ClassTemplateFileExtension); // ConditionalSearchテンプレート ファイル this.ConditionalSearchTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.ConditionalSearchTemplateFileName, ""); // SearchAndUpdateテンプレート ファイル this.SearchAndUpdateTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.SearchAndUpdateTemplateFileName, ""); // Detailテンプレート ファイル this.DetailTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.DetailTemplateFileName, ""); } // ↑↑↑【追加】↑↑↑ #endregion - if (!this.cbxOnlyDTO.Checked - && !this.cbxOnlyTableMaintenance.Checked) + if (!opt.OnlyDTO + && !opt.OnlyTableMaintenance) { #region SQLテンプレート ファイル(静的) this.InsertTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.InsertTemplateFileName, ""); this.SelectTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.SelectTemplateFileName, ""); this.UpdateTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.UpdateTemplateFileName, ""); this.DeleteTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.DeleteTemplateFileName, ""); #endregion @@ -2137,28 +2256,28 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) this.DynInsTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.DynInsTemplateFileName, ""); this.DynSelTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.DynSelTemplateFileName, ""); this.DynUpdTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.DynUpdTemplateFileName, ""); this.DynDelTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.DynDelTemplateFileName, ""); // ↓↓↓【追加】↓↓↓ this.DynSelCntTemplateFilePath = this.CheckTemplateFile( - this.txtSetSourceTemplate.Text, + opt.TemplateRootPath, this.DynSelCntTemplateFileName, ""); // ↑↑↑【追加】↑↑↑ @@ -2169,13 +2288,13 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) #region 出力ファイル - dirInfo = new DirectoryInfo(this.txtSetOutput.Text); + dirInfo = new DirectoryInfo(opt.OutputPath); if (dirInfo.Exists) { } else { - //MessageBox.Show("出力ファイル(Daoクラス ファイル、SQLファイル.etc)のルート フォルダが存在しません。"); - MessageBox.Show(this.RM_GetString("OutputFileRootFolderNotExist")); - return; + //this.ShowMessage("出力ファイル(Daoクラス ファイル、SQLファイル.etc)のルート フォルダが存在しません。"); + this.ShowMessage(this.RM_GetString("OutputFileRootFolderNotExist")); + return false; } #endregion @@ -2185,12 +2304,12 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) // ↓↓↓【追加】↓↓↓ //エスケープ文字のチェック - if (rbnODP.Checked == true && txtEscapeChar.Text.Length != 1) + if ((opt.Dap == "ODP") == true && opt.EscapeChar.Length != 1) { //Oracle ODP.NET かつ エスケープ文字が入力されていない(1文字でない)場合 - //MessageBox.Show("エスケープ文字が設定されていません。"); - MessageBox.Show(this.RM_GetString("EscCharacterNotSet")); - return; + //this.ShowMessage("エスケープ文字が設定されていません。"); + this.ShowMessage(this.RM_GetString("EscCharacterNotSet")); + return false; } // ↑↑↑【追加】↑↑↑ @@ -2200,10 +2319,10 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) #region タイムスタンプ列 // タイムスタンプ列名を取得 - this.TimeStampColName = this.txtTimeStampColName.Text.Trim(); + this.TimeStampColName = opt.TimeStampColName.Trim(); // タイムスタンプ更新方法を取得 - this.TimeStampUpdMethod = this.txtTimeStampUpdMethod.Text.Trim(); + this.TimeStampUpdMethod = opt.TimeStampUpdMethod.Trim(); // タイムスタンプの設定ステータスのチェック&設定 if (this.TimeStampColName == "" & this.TimeStampUpdMethod == "") @@ -2224,10 +2343,10 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) else { // 更新方法だけある。 - //MessageBox.Show("タイムスタンプ列名がありません。"); - MessageBox.Show(this.RM_GetString("NoTimestampColName")); + //this.ShowMessage("タイムスタンプ列名がありません。"); + this.ShowMessage(this.RM_GetString("NoTimestampColName")); - return; + return false; } #endregion @@ -2242,41 +2361,41 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) this.TimeStamp = DateTime.Now.Year + "/" + DateTime.Now.Month + "/" + DateTime.Now.Day; // ユーザ名 - this.UserName = this.txtFamilyName.Text + " " + this.txtPersonalName.Text; + this.UserName = opt.FamilyName + " " + opt.PersonalName; //// エンコーディング(XML用) - this.XMLEncoding = this.cmbSFEncoding.Text; + this.XMLEncoding = opt.XmlEncoding; // SQLの制御文字 - if (rbnSQL.Checked || rbnOLE.Checked || rbnODB.Checked) + if ((opt.Dap == "SQL") || (opt.Dap == "OLE") || (opt.Dap == "ODB")) { this.ParamSign = '@'; this.EnclosureCharS = '['; this.EnclosureCharE = ']'; } - else if (rbnODP.Checked) + else if ((opt.Dap == "ODP")) { this.ParamSign = ':'; this.EnclosureCharS = '"'; this.EnclosureCharE = '"'; } - else if (rbnDB2.Checked) + else if ((opt.Dap == "DB2")) { this.ParamSign = '@'; this.EnclosureCharS = '"'; this.EnclosureCharE = '"'; } - else if (rbnMySQL.Checked) + else if ((opt.Dap == "MCN")) { this.ParamSign = '@'; this.EnclosureCharS = '`'; this.EnclosureCharE = '`'; } - else if (rbnPstgrs.Checked) + else if ((opt.Dap == "NPS")) { // Npgsqlでは、「@」・「:」の双方をサポートするが、 // 本Fxでは、「:」を選択(動作がOracleに近いため)。 @@ -2318,7 +2437,7 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) #region D層定義情報ファイル ヘッダー制御 - if (this.cbxDaoDefinitionHeader.Checked) + if (opt.DaoDefinitionHeader) { // ヘッダーは、無視 if (!srDaoDef.EndOfStream) @@ -2770,7 +2889,7 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) this.DaoClassName = this.DaoClassNameHeader + this.TableName.Replace(' ', '_') + this.DaoClassNameFooter; // DTO、メンテナンス画面のみの場合はDao、SQLは生成しない。 - if (!(this.cbxOnlyDTO.Checked || this.cbxOnlyTableMaintenance.Checked)) + if (!(opt.OnlyDTO || opt.OnlyTableMaintenance)) { #region SQLファイルを生成 @@ -2952,18 +3071,18 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) // DTE:DaoClassテンプレートのEncoding this.GenerateClassFile( this.DaoTemplateFilePath, - (int)this.cmbDTEncoding.SelectedValue, this.FileName); + opt.ClassFileCodePage, this.FileName); #endregion } // ↓↓↓【追加】↓↓↓ if (this.CreateDTO - && !this.cbxOnlyTableMaintenance.Checked) + && !opt.OnlyTableMaintenance) { #region Entityファイルを生成 - if (this.cbxEntity.Checked) + if (opt.CreateEntity) { // カレント・ファイル出力用とReplace用途 // Entityクラス名 @@ -2977,14 +3096,14 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) // DTE:DaoClassテンプレートのEncoding this.GenerateClassFile( this.EntityTemplateFilePath, - (int)this.cmbDTEncoding.SelectedValue, this.FileName); + opt.ClassFileCodePage, this.FileName); } #endregion #region DataSetファイルを生成 - if (this.cbxTypedDataSet.Checked) + if (opt.CreateTypedDataSet) { // カレント・ファイル出力用とReplace用途 // DataSetクラス名 @@ -3002,14 +3121,14 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) // DTE:DaoClassテンプレートのEncoding this.GenerateClassFile( this.DataSetTemplateFilePath, - (int)this.cmbDTEncoding.SelectedValue, this.FileName); + opt.ClassFileCodePage, this.FileName); } #endregion } if (this.CreateMaintenanceScreen - && !this.cbxOnlyDTO.Checked) + && !opt.OnlyDTO) { // カレント・ファイル出力用とReplace用途 @@ -3017,7 +3136,7 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) this.FileName = this.TableName.Replace(' ', '_') + this.TableAdapterTemplateFileName; this.GenerateClassFile( this.TableAdapterTemplateFilePath, - (int)this.cmbDTEncoding.SelectedValue, this.FileName); + opt.ClassFileCodePage, this.FileName); #region ASPXファイル、Codebehindファイル @@ -3025,29 +3144,29 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) this.FileName = this.TableName + this.ConditionalSearchTemplateFileName; this.GenerateClassFile( this.ConditionalSearchTemplateFilePath, - (int)this.cmbDTEncoding.SelectedValue, this.FileName); + opt.ClassFileCodePage, this.FileName); this.GenerateClassFile( this.ConditionalSearchTemplateFilePath + "." + this.ClassTemplateFileExtension, - (int)this.cmbDTEncoding.SelectedValue, this.FileName + "." + this.ClassTemplateFileExtension); + opt.ClassFileCodePage, this.FileName + "." + this.ClassTemplateFileExtension); // ASPXファイル、Codebehindファイル(SearchAndUpdate)を生成 this.FileName = this.TableName + this.SearchAndUpdateTemplateFileName; this.GenerateClassFile( this.SearchAndUpdateTemplateFilePath, - (int)this.cmbDTEncoding.SelectedValue, this.FileName); + opt.ClassFileCodePage, this.FileName); this.GenerateClassFile( this.SearchAndUpdateTemplateFilePath + "." + this.ClassTemplateFileExtension, - (int)this.cmbDTEncoding.SelectedValue, this.FileName + "." + this.ClassTemplateFileExtension); + opt.ClassFileCodePage, this.FileName + "." + this.ClassTemplateFileExtension); // ASPXファイル、Codebehindファイル(Detail)を生成 this.FileName = this.TableName + this.DetailTemplateFileName; this.GenerateClassFile( this.DetailTemplateFilePath, - (int)this.cmbDTEncoding.SelectedValue, this.FileName); + opt.ClassFileCodePage, this.FileName); this.GenerateClassFile( this.DetailTemplateFilePath + "." + this.ClassTemplateFileExtension, - (int)this.cmbDTEncoding.SelectedValue, this.FileName + "." + this.ClassTemplateFileExtension); + opt.ClassFileCodePage, this.FileName + "." + this.ClassTemplateFileExtension); #endregion } @@ -3073,19 +3192,22 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) System.Windows.Forms.Cursor.Current = Cursors.Default; // メッセージ - //MessageBox.Show("自動生成完了!"); - MessageBox.Show(this.RM_GetString("FileGenComplete")); + //this.ShowMessage("自動生成完了!"); + this.ShowMessage(this.RM_GetString("FileGenComplete")); } catch (CheckException cex) { - //MessageBox.Show("チェックエラーです:" + cex.Message); - MessageBox.Show(this.RM_GetString("CheckExceptionError") + cex.Message); - + //this.ShowMessage("チェックエラーです:" + cex.Message); + this.ShowMessage(this.RM_GetString("CheckExceptionError") + cex.Message); + return false; } catch (Exception ex) { - //MessageBox.Show("ランタイムエラーです:" + ex.Message); - MessageBox.Show(this.RM_GetString("RuntimeError") + ex.Message); + //this.ShowMessage("ランタイムエラーです:" + ex.Message); + // CUI時は原因調査のためスタック トレースまで出力する。 + this.ShowMessage(this.RM_GetString("RuntimeError") + + (this.IsCui ? ex.ToString() : ex.Message)); + return false; } finally { @@ -3106,6 +3228,8 @@ private void btnDaoAndSqlGen_Click(object sender, EventArgs e) // カーソルを元に戻す System.Windows.Forms.Cursor.Current = Cursors.Default; } + + return true; } #endregion @@ -3138,7 +3262,7 @@ private void GenerateSQLFile(string sqlTemplate, string extension) // 入力テンプレート // STE:SQLテンプレートのEncoding - srSQLTpl = this.OpenSrTemplate(sqlTemplate, (int)cmbSTEncoding.SelectedValue); + srSQLTpl = this.OpenSrTemplate(sqlTemplate, this.genSqlTemplateCodePage); // 出力ファイル swSQLFile = this.OpenSwSQLFile(this.FileName, extension); @@ -3784,17 +3908,17 @@ private void CreateString(string col, string dbType, bool isPK) + " IS NULL</ELSE>" + "</IF>" + "," + "<IF>AND " - + this.EnclosureCharS + col + this.EnclosureCharE + " " + cmbLikeStatement.Text + " " + + this.EnclosureCharS + col + this.EnclosureCharE + " " + this.genLikeStatement + " " + this.ParamSign.ToString() + this.LikeParamHeader + col.Replace(' ', '_') + this.LikeParamFooter; if (chkEscapeToNChar.Checked == true) { //TO_NCHARする場合 - this.DynColsCondition_Like += " ESCAPE TO_NCHAR('" + txtEscapeChar.Text + "')"; + this.DynColsCondition_Like += " ESCAPE TO_NCHAR('" + this.genEscapeChar + "')"; } else { //TO_NCHARしない場合 - this.DynColsCondition_Like += " ESCAPE '" + txtEscapeChar.Text + "'"; + this.DynColsCondition_Like += " ESCAPE '" + this.genEscapeChar + "'"; } this.DynColsCondition_Like += "</IF>" + ","; @@ -3810,7 +3934,7 @@ private void CreateString(string col, string dbType, bool isPK) "<IF>AND " + this.EnclosureCharS + col + this.EnclosureCharE + " LIKE " + this.ParamSign.ToString() + this.LikeParamHeader + col.Replace(' ', '_') + this.LikeParamFooter - + " ESCAPE '" + txtEscapeChar.Text + "' " + "</IF>" + ","; + + " ESCAPE '" + this.genEscapeChar + "' " + "</IF>" + ","; } } else diff --git a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Program.cs b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Program.cs index 31ef75569..ee4c29448 100644 --- a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Program.cs +++ b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/Program.cs @@ -33,14 +33,18 @@ //* and replaced to this method wherever hard coded values. //* Also Added code to get the Culture information from app.config file. //* 2018/10/29 西野 大介 NETCOREAPP対応で、configの初期化 +//* 2026/07/31 玄人 幸道 CUI起動(/CUI)とヘルプ(/HELP)を追加 //********************************************************************************** using System; +using System.Collections.Generic; using System.Threading; using System.Resources; using System.Globalization; +using System.Runtime.InteropServices; using System.Windows.Forms; +using Touryo.Infrastructure.Public.Str; using Touryo.Infrastructure.Public.Util; namespace DaoGen_Tool @@ -48,6 +52,24 @@ namespace DaoGen_Tool /// <summary>アプリケーションのメイン エントリ ポイント</summary> static class Program { + /// <summary>CUI(非対話)で起動しているか</summary> + private static bool _isCui = false; + + #region コンソール制御 + + /// <summary>親プロセスのコンソールにアタッチする</summary> + /// <param name="dwProcessId">-1 で親プロセス</param> + /// <returns>成否</returns> + [DllImport("kernel32.dll")] + private static extern bool AttachConsole(int dwProcessId); + + /// <summary>コンソールをデタッチする</summary> + /// <returns>成否</returns> + [DllImport("kernel32.dll")] + private static extern bool FreeConsole(); + + #endregion + /// <summary> /// アプリケーションのメイン エントリ ポイントです。 /// </summary> @@ -73,13 +95,425 @@ static void Main() Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(strDefaultCulture); } - Application.Run(new Form1()); + // コマンドライン引数を取得する(キーは大文字化される)。 + List<string> valsLst; + Dictionary<string, string> argsDic; + StringVariableOperator.GetCommandArgs('/', out argsDic, out valsLst); + + // 起動の切り替え + if (argsDic.ContainsKey("/HELP")) + { + // ヘルプ + Program.AttachConsole(-1); + Program.WriteHelp(); + Program.FreeConsole(); + } + else if (argsDic.ContainsKey("/CUI")) + { + // CUI起動(非対話) + Program._isCui = true; + Program.AttachConsole(-1); + try + { + Environment.ExitCode = Program.RunAsCui(argsDic); + } + catch (Exception cuiEx) + { + Console.WriteLine("エラー:" + cuiEx.ToString()); + Environment.ExitCode = 2; + } + Program.FreeConsole(); + } + else + { + // GUI起動 + Application.Run(new Form1()); + } } catch (Exception ex) { - MessageBox.Show(RM_GetString("EntryPoint") + ex.Message); + if (Program._isCui) + { + // CUI起動時は MessageBox で停止させない。 + Console.WriteLine(RM_GetString("EntryPoint") + ex.ToString()); + Environment.ExitCode = 2; + } + else + { + MessageBox.Show(RM_GetString("EntryPoint") + ex.Message); + } + } + } + + #region CUI + + /// <summary>ヘルプを標準出力に表示する</summary> + private static void WriteHelp() + { + Console.WriteLine(""); + Console.WriteLine("DaoGen_Tool(D層自動生成ツール/墨壺)"); + Console.WriteLine(""); + Console.WriteLine(" 引数なし GUIで起動します。"); + Console.WriteLine(" /HELP このヘルプを表示します。"); + Console.WriteLine(" /CUI CUI(非対話)で生成処理を実行します。"); + Console.WriteLine(""); + Console.WriteLine("</CUI 時の共通引数>"); + Console.WriteLine(""); + Console.WriteLine(" /MODE <DAODEFGEN|DAOSQLGEN> 実行する処理(既定:DAOSQLGEN)"); + Console.WriteLine(" DAODEFGEN DBのスキーマから、D層定義情報ファイル(*.csv)を生成"); + Console.WriteLine(" DAOSQLGEN D層定義情報ファイルから、Dao・DTO・SQL を生成"); + Console.WriteLine(""); + Console.WriteLine("</MODE DAODEFGEN 時の引数>"); + Console.WriteLine(""); + Console.WriteLine(" 必須"); + Console.WriteLine(" /OUTPUT <path> 出力先ファイル(*.csv)"); + Console.WriteLine(""); + Console.WriteLine(" 任意"); +#if NETCOREAPP + Console.WriteLine(" /DAP <SQL|ODB|ODP|MCN|NPS> データ プロバイダ(既定:SQL)"); +#else + Console.WriteLine(" /DAP <SQL|OLE|ODB|ODP|MCN> データ プロバイダ(既定:SQL)"); +#endif + Console.WriteLine(" /CONNSTR <string> 接続文字列"); + Console.WriteLine(" (既定:設定ファイルの ConnectionString_*)"); + Console.WriteLine(" /TABLES <name,name,...> 生成対象(既定:全テーブル・ビュー)"); + Console.WriteLine(" /EXCLUDETABLES <name,name,...> 生成対象から除外"); + Console.WriteLine(" /PRIMARYKEYS <T1:C1|C2,T2:C3> 主キー(DBから取得できない場合に指定)"); + Console.WriteLine(" /CODEPAGE <n> 出力のコード ページ(既定:65001)"); + Console.WriteLine(""); + Console.WriteLine("</MODE DAOSQLGEN 時の引数>"); + Console.WriteLine(""); + Console.WriteLine(" 必須"); + Console.WriteLine(" /DAODEF <path> D層定義情報ファイル(*.csv)へのパス"); + Console.WriteLine(" /TEMPLATE <path> テンプレート ファイルのルート フォルダ"); + Console.WriteLine(" /OUTPUT <path> 出力先フォルダ"); + Console.WriteLine(""); + Console.WriteLine(" 任意"); + Console.WriteLine(" /DAP <SQL|OLE|ODB|ODP|DB2|MCN|NPS> データ プロバイダ(既定:SQL)"); + Console.WriteLine(" /LANG <CS|VB> 生成言語(既定:CS)"); + Console.WriteLine(" /ENTITY エンティティ(DTO)を生成"); + Console.WriteLine(" /TYPEDDATASET 型付きデータセットを生成"); + Console.WriteLine(" /TABLEMAINTENANCE テーブル メンテナンス画面を生成"); + Console.WriteLine(" /ONLYDTO DTOのみ生成(Daoを生成しない)"); + Console.WriteLine(" /ONLYTABLEMAINTENANCE メンテ画面のみ生成"); + Console.WriteLine(" /NOHEADER 定義ファイルの1行目をヘッダとして扱わない"); + Console.WriteLine(" /ESCAPECHAR <c> エスケープ文字(ODP時は1文字必須)"); + Console.WriteLine(" /TSCOLNAME <name> タイム スタンプ列名"); + Console.WriteLine(" /TSUPDMETHOD <method> タイム スタンプの更新方法"); + Console.WriteLine(" /FAMILYNAME <name> 作成者(姓)"); + Console.WriteLine(" (既定:設定ファイルの FamilyName)"); + Console.WriteLine(" /PERSONALNAME <name> 作成者(名)"); + Console.WriteLine(" (既定:設定ファイルの PersonalName)"); + Console.WriteLine(" /XMLENCODING <name> SQL(XML)のエンコーディング(既定:utf-8)"); + Console.WriteLine(" /CODEPAGE <n> クラス ファイルのコード ページ(既定:65001)"); + Console.WriteLine(""); + Console.WriteLine("<終了コード> 0:成功 / 1:引数エラー / 2:生成エラー"); + Console.WriteLine(""); + Console.WriteLine("<パス区切りの注意>"); + Console.WriteLine(" コマンドライン解析では \\ をエスケープ文字として扱うため、"); + Console.WriteLine(" パスの区切りには / を使用してください(\\\\ でも可)。"); + Console.WriteLine(" OK : /OUTPUT \"C:/temp/out\""); + Console.WriteLine(" OK : /OUTPUT \"C:\\\\temp\\\\out\""); + Console.WriteLine(" NG : /OUTPUT \"C:\\temp\\out\" ← \\ が消えます"); + Console.WriteLine(""); + Console.WriteLine("</PRIMARYKEYS の書式>"); + Console.WriteLine(" テーブル名 : 主キー列名 | 主キー列名 ... を、カンマ区切りで複数指定します。"); + Console.WriteLine(" 主キー情報をDBMSから取得できないデータ プロバイダ"); + Console.WriteLine(" (ODBC・OLEDB・MySQL・PostgreSQL)で使用します。"); + Console.WriteLine(" 例 : /PRIMARYKEYS \"Orders:OrderID,OrderDetails:OrderID|ProductID\""); + Console.WriteLine(""); + } + + /// <summary>コマンドライン引数から値を取得する</summary> + /// <param name="argsDic">コマンドライン引数</param> + /// <param name="key">キー("/XXX")</param> + /// <param name="defaultValue">既定値</param> + /// <returns>値</returns> + private static string GetArg(Dictionary<string, string> argsDic, string key, string defaultValue) + { + if (argsDic.ContainsKey(key) && !string.IsNullOrEmpty(argsDic[key])) + { + return argsDic[key]; + } + return defaultValue; + } + + /// <summary>コマンドライン引数から、カンマ区切りの値を配列で取得する</summary> + /// <param name="argsDic">コマンドライン引数</param> + /// <param name="key">キー("/XXX")</param> + /// <returns>値の配列(指定が無い場合は空配列)</returns> + private static string[] GetArrayArg(Dictionary<string, string> argsDic, string key) + { + string value = Program.GetArg(argsDic, key, ""); + + if (string.IsNullOrEmpty(value)) + { + return new string[0]; + } + + List<string> valueLst = new List<string>(); + foreach (string temp in value.Split(',')) + { + if (temp.Trim() != "") + { + valueLst.Add(temp.Trim()); + } + } + + return valueLst.ToArray(); + } + + /// <summary>CUI(非対話)で生成処理を実行する</summary> + /// <param name="argsDic">コマンドライン引数</param> + /// <returns>終了コード(0:成功 / 1:引数エラー / 2:生成エラー)</returns> + private static int RunAsCui(Dictionary<string, string> argsDic) + { + // 実行する処理の切り替え + string mode = Program.GetArg(argsDic, "/MODE", "DAOSQLGEN").ToUpper(); + + if (mode == "DAODEFGEN") + { + // DBのスキーマ → D層定義情報ファイル + return Program.RunDaoDefinitionGen(argsDic); + } + else if (mode == "DAOSQLGEN") + { + // D層定義情報ファイル → Dao・DTO・SQL + return Program.RunDaoAndSqlGen(argsDic); + } + else + { + Console.WriteLine("引数エラー:/MODE には DAODEFGEN または DAOSQLGEN を指定してください。"); + Console.WriteLine("使用方法は /HELP で確認してください。"); + return 1; + } + } + + /// <summary>CUI(非対話)で、DBのスキーマからD層定義情報ファイルを生成する</summary> + /// <param name="argsDic">コマンドライン引数</param> + /// <returns>終了コード(0:成功 / 1:引数エラー / 2:生成エラー)</returns> + private static int RunDaoDefinitionGen(Dictionary<string, string> argsDic) + { + DaoDefinitionOptions opt = new DaoDefinitionOptions(); + + // 出力先(必須) + opt.OutputFilePath = Program.GetArg(argsDic, "/OUTPUT", ""); + + if (string.IsNullOrEmpty(opt.OutputFilePath)) + { + Console.WriteLine("引数エラー:/OUTPUT は必須です。"); + Console.WriteLine("使用方法は /HELP で確認してください。"); + return 1; + } + + // データ プロバイダ + opt.Dap = Program.GetArg(argsDic, "/DAP", "SQL").ToUpper(); + + if (!Program.IsSupportedDap(opt.Dap)) + { + Console.WriteLine("引数エラー:データ プロバイダ[" + + opt.Dap + "]は、このビルドではサポートされていません。"); + Console.WriteLine("使用方法は /HELP で確認してください。"); + return 1; + } + + // 接続文字列(省略時は設定ファイルの値を使用する) + opt.ConnectionString = Program.GetArg(argsDic, "/CONNSTR", ""); + + if (string.IsNullOrEmpty(opt.ConnectionString)) + { + string configKey = Program.GetConnectionStringKey(opt.Dap); + + if (configKey == "") + { + Console.WriteLine("引数エラー:/DAP には SQL, OLE, ODB, ODP, DB2, MCN, NPS を指定してください。"); + return 1; + } + + opt.ConnectionString = GetConfigParameter.GetConfigValue(configKey); + + if (string.IsNullOrEmpty(opt.ConnectionString)) + { + Console.WriteLine("引数エラー:/CONNSTR が指定されておらず、" + + "設定ファイルにも " + configKey + " がありません。"); + return 1; + } + } + + // 生成対象 + opt.Tables = Program.GetArrayArg(argsDic, "/TABLES"); + opt.ExcludeTables = Program.GetArrayArg(argsDic, "/EXCLUDETABLES"); + + // 主キー("T1:C1|C2,T2:C3" 形式) + foreach (string temp in Program.GetArrayArg(argsDic, "/PRIMARYKEYS")) + { + int index = temp.IndexOf(':'); + + if (index <= 0 || index == temp.Length - 1) + { + Console.WriteLine("引数エラー:/PRIMARYKEYS の書式が不正です(" + temp + ")。"); + Console.WriteLine("使用方法は /HELP で確認してください。"); + return 1; + } + + opt.PrimaryKeys[temp.Substring(0, index).Trim()] + = temp.Substring(index + 1).Split('|'); + } + + // エンコーディング + int codePage; + if (!int.TryParse(Program.GetArg(argsDic, "/CODEPAGE", "65001"), out codePage)) + { + Console.WriteLine("引数エラー:/CODEPAGE には数値を指定してください。"); + return 1; + } + opt.CodePage = codePage; + + // 生成処理の呼び出し + // ※ Form1 は表示しない。UIコントロールは初期化のみ行われる。 + Form1 form1 = new Form1(); + form1.IsCui = true; + + Console.WriteLine("生成を開始します。"); + bool result = form1.DaoDefinitionGen(opt); + + if (result) + { + Console.WriteLine("生成が完了しました。"); + return 0; + } + else + { + Console.WriteLine("生成に失敗しました。"); + return 2; + } + } + + /// <summary>DBに接続できるデータ プロバイダか(このビルドでサポートされるか)を判定する</summary> + /// <param name="dap">データ プロバイダ</param> + /// <returns>サポートされる場合 true</returns> + /// <remarks> + /// DB2・HiRDBは、両ビルドともコードがコメントアウトされているためサポートされない。 + /// ※ /MODE DAOSQLGEN はDBに接続しない(テンプレートの選択にのみ使用する)ため、この判定は行わない。 + /// </remarks> + private static bool IsSupportedDap(string dap) + { + switch (dap) + { + case "SQL": + case "ODB": + case "ODP": + case "MCN": + return true; +#if NETCOREAPP + // PostgreSQLは、NETCOREAPPでのみサポートされる。 + case "NPS": + return true; +#else + // OLEDBは、NETCOREAPPではサポートされない。 + case "OLE": + return true; +#endif + default: + return false; } } + + /// <summary>データ プロバイダに対応する、接続文字列の設定キーを取得する</summary> + /// <param name="dap">データ プロバイダ</param> + /// <returns>設定キー(対応しないデータ プロバイダの場合は空文字)</returns> + private static string GetConnectionStringKey(string dap) + { + switch (dap) + { + case "SQL": return "ConnectionString_SQL"; + case "OLE": return "ConnectionString_OLE"; + case "ODB": return "ConnectionString_ODBC"; + case "ODP": return "ConnectionString_ODP"; + case "DB2": return "ConnectionString_DB2"; + case "MCN": return "ConnectionString_MCN"; + case "NPS": return "ConnectionString_NPS"; + default: return ""; + } + } + + /// <summary>CUI(非対話)で、D層定義情報ファイルから Dao・DTO・SQL を生成する</summary> + /// <param name="argsDic">コマンドライン引数</param> + /// <returns>終了コード(0:成功 / 1:引数エラー / 2:生成エラー)</returns> + private static int RunDaoAndSqlGen(Dictionary<string, string> argsDic) + { + DaoGenOptions opt = new DaoGenOptions(); + + // 入出力パス(必須) + opt.DaoDefinitionFilePath = Program.GetArg(argsDic, "/DAODEF", ""); + opt.TemplateRootPath = Program.GetArg(argsDic, "/TEMPLATE", ""); + opt.OutputPath = Program.GetArg(argsDic, "/OUTPUT", ""); + + if (string.IsNullOrEmpty(opt.DaoDefinitionFilePath) + || string.IsNullOrEmpty(opt.TemplateRootPath) + || string.IsNullOrEmpty(opt.OutputPath)) + { + Console.WriteLine("引数エラー:/DAODEF, /TEMPLATE, /OUTPUT は必須です。"); + Console.WriteLine("使用方法は /HELP で確認してください。"); + return 1; + } + + // データ プロバイダ・言語 + opt.Dap = Program.GetArg(argsDic, "/DAP", "SQL").ToUpper(); + opt.IsCSharp = (Program.GetArg(argsDic, "/LANG", "CS").ToUpper() != "VB"); + + // 生成対象 + opt.CreateEntity = argsDic.ContainsKey("/ENTITY"); + opt.CreateTypedDataSet = argsDic.ContainsKey("/TYPEDDATASET"); + opt.CreateTableMaintenance = argsDic.ContainsKey("/TABLEMAINTENANCE"); + opt.OnlyDTO = argsDic.ContainsKey("/ONLYDTO"); + opt.OnlyTableMaintenance = argsDic.ContainsKey("/ONLYTABLEMAINTENANCE"); + + // 生成オプション + opt.DaoDefinitionHeader = !argsDic.ContainsKey("/NOHEADER"); + opt.EscapeChar = Program.GetArg(argsDic, "/ESCAPECHAR", ""); + opt.TimeStampColName = Program.GetArg(argsDic, "/TSCOLNAME", ""); + opt.TimeStampUpdMethod = Program.GetArg(argsDic, "/TSUPDMETHOD", ""); + // 作成者(省略時は設定ファイルの値を使用する。GUIのForm2_Loadと同じ挙動。) + opt.FamilyName = Program.GetArg(argsDic, "/FAMILYNAME", + GetConfigParameter.GetConfigValue("FamilyName") ?? ""); + opt.PersonalName = Program.GetArg(argsDic, "/PERSONALNAME", + GetConfigParameter.GetConfigValue("PersonalName") ?? ""); + + // エンコーディング + opt.XmlEncoding = Program.GetArg(argsDic, "/XMLENCODING", "utf-8"); + int codePage; + if (!int.TryParse(Program.GetArg(argsDic, "/CODEPAGE", "65001"), out codePage)) + { + Console.WriteLine("引数エラー:/CODEPAGE には数値を指定してください。"); + return 1; + } + opt.ClassFileCodePage = codePage; + + // 生成処理の呼び出し + // ※ Form2 は表示しない。UIコントロールは初期化のみ行われる。 + Form2 form2 = new Form2(); + form2.IsCui = true; + form2.Init(opt.Dap); + // Form2_Load は表示時にしか発火しないため、設定の読み込みを明示的に呼ぶ。 + form2.LoadSettingsFromConfig(); + + Console.WriteLine("生成を開始します。"); + bool result = form2.DaoAndSqlGen(opt); + + if (result) + { + Console.WriteLine("生成が完了しました。"); + return 0; + } + else + { + Console.WriteLine("生成に失敗しました。"); + return 2; + } + } + + #endregion /// <summary>This Method gets the string values from resource file based on the key passed</summary> private static string RM_GetString(string key) diff --git a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/README.md b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/README.md new file mode 100644 index 000000000..c2bebb13e --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/README.md @@ -0,0 +1,167 @@ +# DaoGen_Tool(D層自動生成ツール/墨壺)— CLI + +DB のスキーマから、D層の定義情報・Dao クラス・DTO・SQL を生成するツール。 +GUI と CUI の両方を持ち、**CUI は非対話**なのでエージェントから実行できる(#508)。 + +本書は**エージェントが実行するため**の情報を記す。 +**引数の一覧は書かない。** `/HELP` を実行すれば得られ、二重管理になるため。 + +--- + +## 1. ヘルプの実行(まずこれを見る) + +```powershell +# net48 +cd root\programs\CS\Frameworks\Tools\DaoGen_Tool\bin\Debug +.\OpenTouryo.DaoGen_Tool.exe /HELP + +# .NET 10 +cd root\programs\CS\Frameworks\Tools\DaoGen_Tool\bin\Debug\net10.0-windows7.0 +.\OpenTouryo.DaoGen_Tool.exe /HELP +``` + +`/HELP` が**引数仕様の一次情報**。次が得られる。 + +- 起動の切り替え(引数なし=GUI、`/HELP`、`/CUI`) +- `/CUI` 時の共通引数(`/MODE <DAODEFGEN|DAOSQLGEN>`) +- モードごとの必須・任意の引数 +- 終了コード +- パス区切りと `/PRIMARYKEYS` の書式 + +**引数を組み立てる前に必ず `/HELP` を実行すること。** 本書の記述より `/HELP` が正である。 + +--- + +## 2. 実行ファイルの場所(`/HELP` からは分からない) + +**アセンブリ名がプロジェクト名と異なる。** `DaoGen_Tool.exe` ではない。 + +| ターゲット | パス(`DaoGen_Tool` からの相対) | +|---|---| +| net48 | `bin\Debug\OpenTouryo.DaoGen_Tool.exe` | +| .NET 10 | `bin\Debug\net10.0-windows7.0\OpenTouryo.DaoGen_Tool.exe` | + +ビルドは既定のバッチで行う(`root\programs\CS` をカレントにして実行)。 + +```powershell +cmd /c "echo. | call 4_Build_Framework_Tool.bat" # net48 +cmd /c "echo. | call 4_Build_Framework_ToolCore.bat" # .NET 10 +``` + +> `1_DeleteDir.bat` は配下の `bin` / `obj` を再帰的に削除する。 +> フル ビルド(`1_BuildAll.ps1`)の後は**再ビルドが必要**なことがある。 + +--- + +## 3. エージェントが踏みやすい罠 + +### 3.1 パスの区切りは `/` にする + +コマンドライン解析(`StringVariableOperator.GetCommandArgs`)は +**`\` をエスケープ文字として扱う**。`\` は消えるため、別のパスとして解釈される。 + +``` +OK : /OUTPUT "C:/temp/out" +OK : /OUTPUT "C:\\temp\\out" +NG : /OUTPUT "C:\temp\out" ← \ が消える +``` + +PowerShell から渡す場合は変換しておく。 + +```powershell +$out = (Join-Path $env:TEMP "daogen/DaoDef.csv").Replace("\", "/") +``` + +> **終了コードでは検出できない。** +> `\` を使っても処理は成功し、**`0` が返る**。 +> ただし出力先が別のパスになるため、指定した場所にファイルが無い。 +> **生成物の存在を必ず確認すること**(5 節)。 + +### 3.2 標準出力は PowerShell のリダイレクトで受ける + +本ツールは `WinExe` で、CUI 時は `AttachConsole(-1)` でコンソールに接続する。 +このため**リダイレクトの方法によって出力が取れない**。 + +| 方法 | 結果 | +|---|---| +| `& $exe /HELP *>&1 \| Out-File $out` | **取れる** | +| `cmd /c "$exe /HELP > $out"` | **取れない**(0 バイト) | + +### 3.3 GUI が開く条件 + +`/HELP` も `/CUI` も無い場合は `Application.Run(new Form1())` になり、 +**画面が開いて応答が返らない**。エージェントは必ずどちらかを付ける。 + +--- + +## 4. 前提 + +### 4.1 接続文字列 + +`/CONNSTR` を省略すると設定ファイルの `ConnectionString_*` を使う。 +`/DAP` の値に対応するキーが選ばれる。 + +| ターゲット | 設定ファイル | +|---|---| +| net48 | `app.config`(`appSettings`) | +| .NET 10 | `appsettings.json`(`appSettings`) | + +いずれも**実行ファイルと同じフォルダ**に配置される。 +`FamilyName` / `PersonalName`(生成物のヘッダに入る作成者名)も同じ場所。 + +### 4.2 テンプレート + +`/MODE DAOSQLGEN` の `/TEMPLATE` にはテンプレートのルート フォルダを渡す。 +リポジトリ内では次の場所にある(`DaoTemplate*.cs` などが平置き)。 + +``` +root/files/tools/DGenTemplates +``` + +**このフォルダは `DPQuery_Tool` と共有している。** どのテンプレートがどちらで使われるか、 +`EntityTemplate` と `_bk` の使い分け、置換トークンの記法は +[`DGenTemplates/README.md`](../../../../../files/tools/DGenTemplates/README.md) を参照。 + +### 4.3 DB + +`/MODE DAODEFGEN` は DB のスキーマを読むため、接続できる必要がある。 +リポジトリの検証では SQL Server の Northwind を使っている。 + +--- + +## 5. 実行例(2 モードを連続して使う) + +`DAODEFGEN` が出力した定義 CSV を `DAOSQLGEN` の入力に使う。 + +```powershell +$exe = "...\bin\Debug\net10.0-windows7.0\OpenTouryo.DaoGen_Tool.exe" +$work = "C:/temp/daogen" +$csv = "$work/DaoDef.csv" +$tmpl = "C:/OpenTouryo/root/files/tools/DGenTemplates" + +# DB のスキーマ → D層定義情報(*.csv) +& $exe /CUI /MODE DAODEFGEN /OUTPUT $csv /DAP SQL /TABLES "Shippers,Orders" + +# D層定義情報 → Dao・DTO・SQL +& $exe /CUI /MODE DAOSQLGEN /DAODEF $csv /TEMPLATE $tmpl /OUTPUT "$work/gen" ` + /DAP SQL /LANG CS /ENTITY +``` + +**判定は終了コードと生成物の両方で行う。** +終了コードの意味は `/HELP` を参照。生成物は次を確認するとよい。 + +- `DAODEFGEN` … 定義 CSV に対象テーブルが並んでいること +- `DAOSQLGEN` … Dao(`.cs`)・動的 SQL(`.xml`)・静的 SQL(`.sql`) が揃っていること + +--- + +## 6. 疎通確認との関係 + +`3_SmokeTest.ps1` が上記 3 つ(`/HELP`・`DAODEFGEN`・`DAOSQLGEN`)を +net48 / .NET 10 の両方で実行している。 +**動く引数の組み合わせを確かめたい場合は、そちらの定義が参考になる。** + +詳細は [`SMOKETEST.md`](../../../../SMOKETEST.md)。 + +なお **GUI の確認は手作業**として残している([`RELEASE.md`](../../../../RELEASE.md))。 +CUI で確認できるのは生成ロジックまでで、画面の動作は含まない。 diff --git a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/app.config b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/app.config index 3ca5be79d..2a857af9b 100644 --- a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/app.config +++ b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/app.config @@ -24,7 +24,7 @@ <!-- ★入力項目(テンプレート) --> <!-- Daoクラス テンプレート ファイル(拡張子を除く) --> - <add key="DaoTemplateFileName" value="DaoTemplate" /> + <add key="DaoTemplateFileName" value="DaoTemplate3" /> <!-- Entityクラス テンプレート ファイル(拡張子を除く) --> <add key="EntityTemplateFileName" value="EntityTemplate" /> diff --git a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/appsettings.json b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/appsettings.json index 11a391659..c5ea90da1 100644 --- a/root/programs/CS/Frameworks/Tools/DaoGen_Tool/appsettings.json +++ b/root/programs/CS/Frameworks/Tools/DaoGen_Tool/appsettings.json @@ -22,7 +22,7 @@ // ★入力項目(テンプレート) // Daoクラス テンプレート ファイル(拡張子を除く) - "DaoTemplateFileName": "DaoTemplate", + "DaoTemplateFileName": "DaoTemplate3", // Entityクラス テンプレート ファイル(拡張子を除く) "EntityTemplateFileName": "EntityTemplate", diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/ChangeProgressParameter.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/ChangeProgressParameter.cs new file mode 100644 index 000000000..76e17e9d8 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/ChangeProgressParameter.cs @@ -0,0 +1,52 @@ +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** + +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :ChangeProgressParameter +//* クラス日本語名 :ChangeProgressデリゲードの引数 +//* +//* 作成者 :生技 西野 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2011/08/01 西野 大介 新規作成 +//********************************************************************************** + +namespace DeployZipPackWithHTTP +{ + public class ChangeProgressParameter + { + /// <summary>状態</summary> + public string Status = null; + + /// <summary>進捗値</summary> + public int ProgressVal = 0; + + /// <summary>コンストラクタ</summary> + /// <param name="status">状態</param> + /// <param name="progressVal">進捗値</param> + public ChangeProgressParameter(string status, int progressVal) + { + this.Status = status; + this.ProgressVal = progressVal; + } + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Command line.txt b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Command line.txt new file mode 100644 index 000000000..5ddd46181 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Command line.txt @@ -0,0 +1,3 @@ +ショートカットのリンク先に設定すると楽。 + +DeployZipPackWithHTTP.exe /cui /wwwurl "http://localhost/test/test.mft" /wwwuid administrator /wwwpwd seigi \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.Designer.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.Designer.cs new file mode 100644 index 000000000..1620e7a95 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.Designer.cs @@ -0,0 +1,68 @@ +namespace DeployZipPackWithHTTP +{ + partial class CustMsgBox + { + /// <summary> + /// Required designer variable. + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// Clean up any resources being used. + /// </summary> + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// <summary> + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// </summary> + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CustMsgBox)); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + // + // pictureBox1 + // + resources.ApplyResources(this.pictureBox1, "pictureBox1"); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.TabStop = false; + // + // CustMsgBox + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.pictureBox1); + this.Controls.Add(this.textBox1); + this.Name = "CustMsgBox"; + this.Load += new System.EventHandler(this.CustMsgBox_Load); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.PictureBox pictureBox1; + } +} \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.cs new file mode 100644 index 000000000..86004452b --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.cs @@ -0,0 +1,75 @@ +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** + +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :CustMsgBox +//* クラス日本語名 :カスタムのメッセージ ボックス画面 +//* +//* 作成者 :生技 西野 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2011/06/16 西野 大介 新規作成 +//* 2011/07/01 西野 大介 アイコンの変更を可能に +//********************************************************************************** + +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace DeployZipPackWithHTTP +{ + /// <summary>カスタムのメッセージ ボックス画面</summary> + public partial class CustMsgBox : Form + { + /// <summary>タイトル</summary> + public string Title { set; private get; } + /// <summary>メッセージ</summary> + public string Message { set; private get; } + /// <summary>メッセージ</summary> + public Icon SysIco { set; private get; } + + /// <summary>コンストラクタ</summary> + /// <param name="title">タイトル</param> + /// <param name="message">メッセージ</param> + /// <param name="sysIco">アイコン</param> + public CustMsgBox(string title, string message, Icon sysIco) + { + this.Title = title; + this.Message = message; + this.SysIco = sysIco; + + InitializeComponent(); + } + + /// <summary>ロード</summary> + private void CustMsgBox_Load(object sender, EventArgs e) + { + this.Text = this.Title; + this.textBox1.Text = this.Message; + + Bitmap bmp = new Bitmap(288, 32); + Graphics g = Graphics.FromImage(bmp); + g.DrawIcon(this.SysIco, 32, 0); // SystemIcons.Error + pictureBox1.Image = bmp; + } + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.ja-JP.resx b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.ja-JP.resx new file mode 100644 index 000000000..5fbf0a26a --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.ja-JP.resx @@ -0,0 +1,183 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> + <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + AAABAAEAICAAAAEAGACoDAAAFgAAACgAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS1/TS1/QAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACirOg7T847T86irOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukySMwIIsEIIsEy + SMypsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACjreg6T84gOMcIIsEAG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEA + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukxR8sIIsEAG78AG78AG78AG78AG78AG78AG78AG78IIsEx + R8upsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjreg6T84g + OMcIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEAG78AG78AG78AG78AG78AG78AG78AG78A + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADL0fKy + uuwzScwIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEz + ScyyuuzL0fIAAAAAAAAAAAAAAAAAAAAAAAAAAADd4PZlddhIW9EwRssoP8koP8koP8kgOMcIIsEAG78A + G78AG78AG78AG78AG78AG78AG78IIsEgOMcoP8koP8koP8kwRstIW9FkddfU1+wAAAAAAAAAAAAAAAAA + AAD29/3u8PvS1/TGzPHCyPC/xu/Axu/ByPCxuesgOMcAG78AG78AG78AG78AG78AG78AG78AG78gOMex + uOa8wNq2utO2utO2utO2utO+wdXZ2t/f3+IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADDyvAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m8wNpkZGRKSkpKSkpKSkpKSkpKSkpeXl7B + wsMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFy+8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKCgoKCgoKCgoKCgoKCgvLy9ZWVnKysoAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAADc3NzY2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgoKCgo + KCgoKCgoKCgoKChDQ0O/v7/U1NQAAAAAAAAAAAAAAAAAAAAAAAAAAADg4OB+fn5/f3/Dx+EoP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgvLy9DQ0NKSkpKSkpKSkpQUFBkZGR9fX3j4+MA + AAAAAAAAAAAAAAAAAADy8vLv7+/f39/Y2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChDQ0O9vb3Ly8vKysrJycnLy8vPz8/Z2dnx8fH39/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADEyu4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrLy8sAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAxu8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrKysoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCyPAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADL0fJIW9EoP8koP8koP8koP8koP8koP8koP8koP8lIW9G+wdVKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADX2/XL0fLEyvDEyu7L0Oy8wNq2utO2 + utO2utO2utO+wdW7u8FDQ0MoKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT1NpkZGRKSkpKSkpKSkpKSkpKSkpDQ0MvLy8oKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADS0tJKSkooKCgoKCgoKCgoKCgoKCgoKCgoKCgoKChKSkrLy8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0tJkZGRKSkpKSkpKSkpKSkpKSkpK + SkpKSkpKSkpkZGTS0tIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADv7+/k5OTd3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3k5OTv7+8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD/+f////D////AP///gB///wAP//wAA//4AAH/8AAA/8AAAD+AAAAfAAAAD/8A + AA//AAAH/AAAA/gAAAHwAAAA/wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8A + AP//AAD///AA///wAP//8AD///AA/w== +</value> + </data> + <data name="$this.Text" xml:space="preserve"> + <value>エラー</value> + </data> +</root> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.resx b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.resx new file mode 100644 index 000000000..8216d9c9e --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/CustMsgBox.resx @@ -0,0 +1,251 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name=">>textBox1.Parent" xml:space="preserve"> + <value>$this</value> + </data> + <data name=">>textBox1.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name=">>textBox1.Name" xml:space="preserve"> + <value>textBox1</value> + </data> + <data name=">>$this.Type" xml:space="preserve"> + <value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> + <data name="textBox1.Location" type="System.Drawing.Point, System.Drawing"> + <value>118, 13</value> + </data> + <data name="pictureBox1.Location" type="System.Drawing.Point, System.Drawing"> + <value>12, 13</value> + </data> + <data name=">>pictureBox1.Parent" xml:space="preserve"> + <value>$this</value> + </data> + <assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <data name="pictureBox1.TabIndex" type="System.Int32, mscorlib"> + <value>1</value> + </data> + <data name=">>$this.Name" xml:space="preserve"> + <value>CustMsgBox</value> + </data> + <data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing"> + <value>6, 13</value> + </data> + <data name=">>pictureBox1.Type" xml:space="preserve"> + <value>System.Windows.Forms.PictureBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <data name="textBox1.ScrollBars" type="System.Windows.Forms.ScrollBars, System.Windows.Forms"> + <value>Both</value> + </data> + <data name="textBox1.Size" type="System.Drawing.Size, System.Drawing"> + <value>209, 108</value> + </data> + <data name="textBox1.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name=">>pictureBox1.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name="textBox1.Multiline" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>textBox1.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>pictureBox1.Name" xml:space="preserve"> + <value>pictureBox1</value> + </data> + <data name="$this.Text" xml:space="preserve"> + <value>Error</value> + </data> + <data name="pictureBox1.Size" type="System.Drawing.Size, System.Drawing"> + <value>100, 108</value> + </data> + <data name="textBox1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> + <value>Top, Bottom, Left, Right</value> + </data> + <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing"> + <value>339, 134</value> + </data> + <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + AAABAAEAICAAAAEAGACoDAAAFgAAACgAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS1/TS1/QAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACirOg7T847T86irOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukySMwIIsEIIsEy + SMypsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACjreg6T84gOMcIIsEAG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEA + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukxR8sIIsEAG78AG78AG78AG78AG78AG78AG78AG78IIsEx + R8upsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjreg6T84g + OMcIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEAG78AG78AG78AG78AG78AG78AG78AG78A + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADL0fKy + uuwzScwIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEz + ScyyuuzL0fIAAAAAAAAAAAAAAAAAAAAAAAAAAADd4PZlddhIW9EwRssoP8koP8koP8kgOMcIIsEAG78A + G78AG78AG78AG78AG78AG78AG78IIsEgOMcoP8koP8koP8kwRstIW9FkddfU1+wAAAAAAAAAAAAAAAAA + AAD29/3u8PvS1/TGzPHCyPC/xu/Axu/ByPCxuesgOMcAG78AG78AG78AG78AG78AG78AG78AG78gOMex + uOa8wNq2utO2utO2utO2utO+wdXZ2t/f3+IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADDyvAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m8wNpkZGRKSkpKSkpKSkpKSkpKSkpeXl7B + wsMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFy+8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKCgoKCgoKCgoKCgoKCgvLy9ZWVnKysoAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAADc3NzY2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgoKCgo + KCgoKCgoKCgoKChDQ0O/v7/U1NQAAAAAAAAAAAAAAAAAAAAAAAAAAADg4OB+fn5/f3/Dx+EoP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgvLy9DQ0NKSkpKSkpKSkpQUFBkZGR9fX3j4+MA + AAAAAAAAAAAAAAAAAADy8vLv7+/f39/Y2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChDQ0O9vb3Ly8vKysrJycnLy8vPz8/Z2dnx8fH39/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADEyu4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrLy8sAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAxu8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrKysoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCyPAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADL0fJIW9EoP8koP8koP8koP8koP8koP8koP8koP8lIW9G+wdVKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADX2/XL0fLEyvDEyu7L0Oy8wNq2utO2 + utO2utO2utO+wdW7u8FDQ0MoKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT1NpkZGRKSkpKSkpKSkpKSkpKSkpDQ0MvLy8oKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADS0tJKSkooKCgoKCgoKCgoKCgoKCgoKCgoKCgoKChKSkrLy8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0tJkZGRKSkpKSkpKSkpKSkpKSkpK + SkpKSkpKSkpkZGTS0tIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADv7+/k5OTd3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3k5OTv7+8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD/+f////D////AP///gB///wAP//wAA//4AAH/8AAA/8AAAD+AAAAfAAAAD/8A + AA//AAAH/AAAA/gAAAHwAAAA/wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8A + AP//AAD///AA///wAP//8AD///AA/w== +</value> + </data> + <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>True</value> + </metadata> +</root> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTP.csproj b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTP.csproj new file mode 100644 index 000000000..7fa54813d --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTP.csproj @@ -0,0 +1,191 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>9.0.30729</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{F0163F46-FA9D-435F-B187-EC3C1E3DF8D7}</ProjectGuid> + <OutputType>WinExe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>DeployZipPackWithHTTP</RootNamespace> + <AssemblyName>OpenTouryo.DeployZipPackWithHTTP</AssemblyName> + <SccProjectName> + </SccProjectName> + <SccLocalPath> + </SccLocalPath> + <SccAuxPath> + </SccAuxPath> + <SccProvider> + </SccProvider> + <FileUpgradeFlags> + </FileUpgradeFlags> + <OldToolsVersion>3.5</OldToolsVersion> + <UpgradeBackupLocation> + </UpgradeBackupLocation> + <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> + <IsWebBootstrapper>true</IsWebBootstrapper> + <StartupObject> + </StartupObject> + <ApplicationIcon>app.ico</ApplicationIcon> + <TargetFrameworkProfile /> + <PublishUrl>http://localhost/DeployZipPackWithHTTP/</PublishUrl> + <Install>true</Install> + <InstallFrom>Web</InstallFrom> + <UpdateEnabled>true</UpdateEnabled> + <UpdateMode>Foreground</UpdateMode> + <UpdateInterval>7</UpdateInterval> + <UpdateIntervalUnits>Days</UpdateIntervalUnits> + <UpdatePeriodically>false</UpdatePeriodically> + <UpdateRequired>false</UpdateRequired> + <MapFileExtensions>true</MapFileExtensions> + <ApplicationRevision>0</ApplicationRevision> + <ApplicationVersion>1.0.0.%2a</ApplicationVersion> + <UseApplicationTrust>false</UseApplicationTrust> + <BootstrapperEnabled>true</BootstrapperEnabled> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">.\</SolutionDir> + <RestorePackages>true</RestorePackages> + <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <ItemGroup> + <Reference Include="OpenTouryo.Business.RichClient, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\Infrastructure\Build\OpenTouryo.Business.RichClient.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.Framework, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\Infrastructure\Build\OpenTouryo.Framework.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.Framework.RichClient, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\Infrastructure\Build\OpenTouryo.Framework.RichClient.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.Public, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> + <SpecificVersion>False</SpecificVersion> + <HintPath>..\..\Infrastructure\Build\OpenTouryo.Public.dll</HintPath> + </Reference> + <Reference Include="Microsoft.VisualBasic" /> + <Reference Include="System" /> + <Reference Include="System.Configuration" /> + <Reference Include="System.Drawing" /> + <Reference Include="System.Web.Extensions" /> + <Reference Include="System.Windows.Forms" /> + </ItemGroup> + <ItemGroup> + <Compile Include="ChangeProgressParameter.cs" /> + <Compile Include="MyException.cs" /> + <Compile Include="Form2.cs"> + <SubType>Form</SubType> + </Compile> + <Compile Include="Form2.Designer.cs"> + <DependentUpon>Form2.cs</DependentUpon> + </Compile> + <Compile Include="LogLevel.cs" /> + <Compile Include="CustMsgBox.cs"> + <SubType>Form</SubType> + </Compile> + <Compile Include="CustMsgBox.Designer.cs"> + <DependentUpon>CustMsgBox.cs</DependentUpon> + </Compile> + <Compile Include="Entry.cs" /> + <Compile Include="Form1.cs"> + <SubType>Form</SubType> + </Compile> + <Compile Include="Form1.Designer.cs"> + <DependentUpon>Form1.cs</DependentUpon> + </Compile> + <Compile Include="Program.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Resources\Resource.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTime>True</DesignTime> + <DependentUpon>Resource.resx</DependentUpon> + </Compile> + <EmbeddedResource Include="CustMsgBox.ja-JP.resx"> + <DependentUpon>CustMsgBox.cs</DependentUpon> + </EmbeddedResource> + <EmbeddedResource Include="Form1.ja-JP.resx"> + <DependentUpon>Form1.cs</DependentUpon> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </EmbeddedResource> + <EmbeddedResource Include="Form1.resx"> + <SubType>Designer</SubType> + <DependentUpon>Form1.cs</DependentUpon> + </EmbeddedResource> + <EmbeddedResource Include="Form2.ja-JP.resx"> + <DependentUpon>Form2.cs</DependentUpon> + </EmbeddedResource> + <EmbeddedResource Include="Resources\Resource.ja-JP.resx" /> + <EmbeddedResource Include="Resources\Resource.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>Resource.Designer.cs</LastGenOutput> + </EmbeddedResource> + <None Include="app.config" /> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Log4DeployZipPackWithHTTP.xml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </EmbeddedResource> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="CustMsgBox.resx"> + <DependentUpon>CustMsgBox.cs</DependentUpon> + </EmbeddedResource> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="Form2.resx"> + <DependentUpon>Form2.cs</DependentUpon> + </EmbeddedResource> + <EmbeddedResource Include="MSGDefinition_ja-JP.xml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </EmbeddedResource> + </ItemGroup> + <ItemGroup> + <Resource Include="app.ico" /> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="MSGDefinition.xml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </EmbeddedResource> + </ItemGroup> + <ItemGroup> + <!--ZIP は OpenTouryo.Public の ZipperV2 / UnZipperV2(SharpZipLib)を使う(#528)。 + DotNetZip は非推奨かつ既知脆弱性(GHSA-xhg6-9j5j-w4vf)のため除去した。 + SharpZipLib は OpenTouryo.Public の依存として Build に配置される。--> + <PackageReference Include="SharpZipLib"> + <Version>1.4.2</Version> + </PackageReference> + <!--設定と履歴の保存に使う(#528)。 + BinaryFormatter が .NET 9 以降で削除されたため JSON に替えた。--> + <PackageReference Include="Newtonsoft.Json"> + <Version>13.0.3</Version> + </PackageReference> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTP.sln b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTP.sln new file mode 100644 index 000000000..b1d0d316d --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTP.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32126.317 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeployZipPackWithHTTP", "DeployZipPackWithHTTP.csproj", "{F0163F46-FA9D-435F-B187-EC3C1E3DF8D7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F0163F46-FA9D-435F-B187-EC3C1E3DF8D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0163F46-FA9D-435F-B187-EC3C1E3DF8D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0163F46-FA9D-435F-B187-EC3C1E3DF8D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0163F46-FA9D-435F-B187-EC3C1E3DF8D7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {52D312DC-E37A-4F2A-AF7F-AECDC645D53F} + EndGlobalSection +EndGlobal diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTPCore.csproj b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTPCore.csproj new file mode 100644 index 000000000..c1dfffbf8 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTPCore.csproj @@ -0,0 +1,113 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>WinExe</OutputType> + <!--RichClient(Business.RichClient / Framework.RichClient)が + net10.0-windows7.0 のため、こちらも合わせる。--> + <TargetFramework>net10.0-windows7.0</TargetFramework> + <UseWindowsForms>true</UseWindowsForms> + <ApplicationIcon /> + <StartupObject /> + <RootNamespace>DeployZipPackWithHTTP</RootNamespace> + <AssemblyName>OpenTouryo.DeployZipPackWithHTTP</AssemblyName> + <!--WFO1000(デザイナのシリアル化を構成していないプロパティ)を抑止する。 + .NET の WinForms アナライザが既定でエラーにするが、 + Status / Title / Message は画面から使うだけでデザイナには出さない。 + net48 側では出ない指摘であり、コードの不具合ではない。--> + <NoWarn>$(NoWarn);WFO1000</NoWarn> + </PropertyGroup> + + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> + <DefineConstants>TRACE;NETCOREAPP</DefineConstants> + </PropertyGroup> + + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> + <DefineConstants>TRACE;NETCOREAPP</DefineConstants> + </PropertyGroup> + + <ItemGroup> + <Compile Remove="Properties\AssemblyInfo.cs" /> + <!--Sample\ 配下は別プロジェクト(SampleConsoleApp)と配布物である。 + **SDK 形式は配下の **\*.cs を既定で拾う**ため、除外しないと + 入れ子のプロジェクトが混ざって CS0579(属性の重複)になる。--> + <Compile Remove="Sample\**" /> + <EmbeddedResource Remove="Sample\**" /> + <None Remove="Sample\**" /> + </ItemGroup> + + <ItemGroup> + <None Remove="app.config" /> + <None Remove="Command line.txt" /> + </ItemGroup> + + <ItemGroup> + <Folder Include="Properties\" /> + </ItemGroup> + + <ItemGroup> + <!--ZIP は OpenTouryo.Public の ZipperV2 / UnZipperV2(SharpZipLib)を使う(#528)。 + フレームワークは HintPath 参照のため、NuGet の推移的依存が効かない。 + Public が使うパッケージは、ここにも並べる必要がある。--> + <PackageReference Include="log4net" Version="3.3.0" /> + <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.4" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.4" /> + <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="9.0.4" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.4" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> + <PackageReference Include="SharpZipLib" Version="1.4.2" /> + </ItemGroup> + + <ItemGroup> + <!--RichClient は net10.0-windows7.0 の側に出力される。 + **net10.0 のフォルダには無い**ので、パスを取り違えないこと。--> + <Reference Include="OpenTouryo.Business.RichClient"> + <HintPath>..\..\Infrastructure\Build_netcore100\net10.0-windows7.0\OpenTouryo.Business.RichClient.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.Framework.RichClient"> + <HintPath>..\..\Infrastructure\Build_netcore100\net10.0-windows7.0\OpenTouryo.Framework.RichClient.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.Framework"> + <HintPath>..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.Framework.dll</HintPath> + </Reference> + <Reference Include="OpenTouryo.Public"> + <HintPath>..\..\Infrastructure\Build_netcore100\net10.0\OpenTouryo.Public.dll</HintPath> + </Reference> + </ItemGroup> + + <ItemGroup> + <Compile Update="Resources\Resource.Designer.cs"> + <DesignTime>True</DesignTime> + <AutoGen>True</AutoGen> + <DependentUpon>Resource.resx</DependentUpon> + </Compile> + </ItemGroup> + + <ItemGroup> + <EmbeddedResource Update="Resources\Resource.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>Resource.Designer.cs</LastGenOutput> + </EmbeddedResource> + </ItemGroup> + + <ItemGroup> + <!--Update ではなく Include にする。**.xml は既定の項目に含まれない**ため、 + Update だけでは何も起きず、出力にコピーされない(#528)。 + ResourceLoader がこれらを実ファイルとして探すので、出力に要る。--> + <EmbeddedResource Include="Log4DeployZipPackWithHTTP.xml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </EmbeddedResource> + <EmbeddedResource Include="MSGDefinition.xml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </EmbeddedResource> + <EmbeddedResource Include="MSGDefinition_ja-JP.xml"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </EmbeddedResource> + </ItemGroup> + + <ItemGroup> + <None Update="appsettings.json"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </None> + </ItemGroup> + +</Project> diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTPCore.sln b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTPCore.sln new file mode 100644 index 000000000..459dbdeae --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/DeployZipPackWithHTTPCore.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32126.317 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeployZipPackWithHTTPCore", "DeployZipPackWithHTTPCore.csproj", "{B988A3B4-7296-4491-878B-7C3C2A330A1F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B988A3B4-7296-4491-878B-7C3C2A330A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B988A3B4-7296-4491-878B-7C3C2A330A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B988A3B4-7296-4491-878B-7C3C2A330A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B988A3B4-7296-4491-878B-7C3C2A330A1F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A32A525E-B7F7-4751-877C-46F7BB73BCE5} + EndGlobalSection +EndGlobal diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Entry.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Entry.cs new file mode 100644 index 000000000..81b4bed91 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Entry.cs @@ -0,0 +1,262 @@ +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** + +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :Entry +//* クラス日本語名 :エントリ +//* +//* 作成者 :生技 西野 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2011/xx/xx 西野 大介 新規作成 +//* 2011/04/25 西野 大介 IEquatableの実装(List.Remove対策) +//* ・List.Remove メソッド +//* http://msdn.microsoft.com/ja-jp/library/cd666k3e.aspx +//* ・EqualityComparer.Default プロパティ +//* http://msdn.microsoft.com/ja-jp/library/ms224763.aspx +//* ・IEquatable ジェネリック インターフェイス +//* http://msdn.microsoft.com/ja-jp/library/ms131187.aspx +//********************************************************************************** + +using System; +using System.Collections.Generic; + +namespace DeployZipPackWithHTTP +{ + /// <summary>エントリ</summary> + [Serializable()] + public class Entry : IEquatable<Entry> + { + #region メンバ + + /// <summary>WWWサーバのURL</summary> + public string WWWURL { get; set; } + /// <summary>WWWサーバのユーザID</summary> + public string WWWUID { get; set; } + /// <summary>WWWサーバのパスワード</summary> + public string WWWPWD { get; set; } + /// <summary>WWWサーバのドメイン</summary> + public string WWWDomain { get; set; } + + /// <summary>ProxyサーバのURL</summary> + public string ProxyURL { get; set; } + /// <summary>ProxyサーバのユーザID</summary> + public string ProxyUID { get; set; } + /// <summary>Proxyサーバのパスワード</summary> + public string ProxyPWD { get; set; } + /// <summary>Proxyサーバのドメイン</summary> + public string ProxyDomain { get; set; } + + /// <summary>マニュフェストの最終更新日付</summary> + public string HttpLastModified { get; set; } + + /// <summary>インストール ディレクトリ</summary> + public string InstallDir { get; set; } + /// <summary>起動exe</summary> + public string StartExe { get; set; } + + /// <summary>ZipFileコンテンツ</summary> + public List<string> ZipFiles { get; set; } + /// <summary>ZipFileコンテンツの最終更新日付</summary> + public Dictionary<string, string> HttpZipLastModified { get; set; } + /// <summary>ZipFileコンテンツの内容物(解凍先ファイル)</summary> + public Dictionary<string, string[]> HttpZipContents { get; set; } + + #endregion + + /// <summary>コンストラクタ</summary> + public Entry() + { + this.ZipFiles + = new List<string>(); + this.HttpZipLastModified + = new Dictionary<string, string>(); + this.HttpZipContents + = new Dictionary<string, string[]>(); + } + + #region IEquatableの実装 + + /// <summary>ハッシュを返す</summary> + /// <returns>ハッシュコード</returns> + /// <remarks>全メンバのハッシュコードのXOR</remarks> + public override int GetHashCode() + { + int ret = 0; + //--- + if (this.WWWURL != null) + { + ret ^= this.WWWURL.GetHashCode(); + } + if (this.WWWUID != null) + { + ret ^= this.WWWUID.GetHashCode(); + } + if (this.WWWPWD != null) + { + ret ^= this.WWWPWD.GetHashCode(); + } + if (this.WWWDomain != null) + { + ret ^= this.WWWDomain.GetHashCode(); + } + //--- + if (this.ProxyURL != null) + { + ret ^= this.ProxyURL.GetHashCode(); + } + if (this.ProxyUID != null) + { + ret ^= this.ProxyUID.GetHashCode(); + } + if (this.ProxyPWD != null) + { + ret ^= this.ProxyPWD.GetHashCode(); + } + if (this.ProxyDomain != null) + { + ret ^= this.ProxyDomain.GetHashCode(); + } + //--- + if (this.HttpLastModified != null) + { + ret ^= this.HttpLastModified.GetHashCode(); + } + //--- + if (this.InstallDir != null) + { + ret ^= this.InstallDir.GetHashCode(); + } + if (this.StartExe != null) + { + ret ^= this.StartExe.GetHashCode(); + } + //--- + if (this.ZipFiles != null) + { + ret ^= this.ZipFiles.GetHashCode(); + } + if (this.HttpZipLastModified != null) + { + ret ^= this.HttpZipLastModified.GetHashCode(); + } + if (this.HttpZipContents != null) + { + ret ^= this.HttpZipContents.GetHashCode(); + } + + return ret; + } + + /// <summary>Equals</summary> + /// <param name="entry">Entry</param> + /// <returns> + /// true:等しい + /// false:等しくない + /// </returns> + /// <remarks>全メンバの==のAND</remarks> + public bool Equals(Entry entry) + { + // null対応 + if (entry == null) { return false; } + + // 一意性の保障はWWWURL(ID)だけで判断可能。 + return + (this.WWWURL == entry.WWWURL); + } + + /// <summary>Equals</summary> + /// <param name="obj">Entry</param> + /// <returns> + /// true:等しい + /// false:等しくない + /// </returns> + public override bool Equals(Object obj) + { + if (obj == null) + { + // nullの場合(ベースへ) + return base.Equals(obj); + } + else + { + // nullでない場合 + if (!(obj is Entry)) + { + // 型が違う + return false; + } + else + { + // 型が一致(オーバロードヘ) + return Equals(obj as Entry); + } + } + } + + /// <summary>比較演算子(==)</summary> + /// <param name="l">右辺</param> + /// <param name="r">左辺</param> + /// <returns> + /// true:等しい + /// false:等しくない + /// </returns> + public static bool operator ==(Entry l, Entry r) + { + // Check for null on left side. + if (Object.ReferenceEquals(l, null)) + { + // Check for null on right side. + if (Object.ReferenceEquals(r, null)) + { + // null == null = true. + return true; + } + else + { + // Only the left side is null. + return false; + } + } + else + { + // Equals handles case of null on right side. + return l.Equals(r); + } + } + + /// <summary>比較演算子(!=)</summary> + /// <param name="l">右辺</param> + /// <param name="r">左辺</param> + /// <returns> + /// true:等しい + /// false:等しくない + /// </returns> + public static bool operator !=(Entry l, Entry r) + { + // ==演算子の逆 + return !(l == r); + } + + #endregion + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.Designer.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.Designer.cs new file mode 100644 index 000000000..6454aa8cd --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.Designer.cs @@ -0,0 +1,667 @@ +namespace DeployZipPackWithHTTP +{ + partial class Form1 + { + /// <summary> + /// 必要なデザイナ変数です。 + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// 使用中のリソースをすべてクリーンアップします。 + /// </summary> + /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param> + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows フォーム デザイナで生成されたコード + + /// <summary> + /// デザイナ サポートに必要なメソッドです。このメソッドの内容を + /// コード エディタで変更しないでください。 + /// </summary> + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); + this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog(); + this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.lblStatus = new System.Windows.Forms.Label(); + this.openFilesDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.panel1 = new System.Windows.Forms.Panel(); + this.tabDeployZipPac = new System.Windows.Forms.TabControl(); + this.tabPageDeployWithHTTP = new System.Windows.Forms.TabPage(); + this.btnDelHistory = new System.Windows.Forms.Button(); + this.lblHistorys = new System.Windows.Forms.Label(); + this.cmbHistorys = new System.Windows.Forms.ComboBox(); + this.btnCheckUpdateAndInstall = new System.Windows.Forms.Button(); + this.gbxWWW = new System.Windows.Forms.GroupBox(); + this.txtURL = new System.Windows.Forms.TextBox(); + this.txtDomain = new System.Windows.Forms.TextBox(); + this.lblDomain = new System.Windows.Forms.Label(); + this.lblURL = new System.Windows.Forms.Label(); + this.txtPWD = new System.Windows.Forms.TextBox(); + this.lblPWD = new System.Windows.Forms.Label(); + this.lblUID = new System.Windows.Forms.Label(); + this.txtUID = new System.Windows.Forms.TextBox(); + this.gbxProxy = new System.Windows.Forms.GroupBox(); + this.txtProxyDomain = new System.Windows.Forms.TextBox(); + this.lblProxyDomain = new System.Windows.Forms.Label(); + this.lblProxyPWD = new System.Windows.Forms.Label(); + this.txtProxyURL = new System.Windows.Forms.TextBox(); + this.txtProxyPWD = new System.Windows.Forms.TextBox(); + this.lblProxyURL = new System.Windows.Forms.Label(); + this.txtProxyUID = new System.Windows.Forms.TextBox(); + this.lblProxyUID = new System.Windows.Forms.Label(); + this.tabPageZipPackage = new System.Windows.Forms.TabPage(); + this.lblFolder = new System.Windows.Forms.Label(); + this.txtFile = new System.Windows.Forms.TextBox(); + this.lblFile = new System.Windows.Forms.Label(); + this.txtPass = new System.Windows.Forms.TextBox(); + this.lblEnc = new System.Windows.Forms.Label(); + this.btnSelectFolder = new System.Windows.Forms.Button(); + this.lblExt = new System.Windows.Forms.Label(); + this.btnSelectSaveFile = new System.Windows.Forms.Button(); + this.cbxExt = new System.Windows.Forms.CheckBox(); + this.txtExt = new System.Windows.Forms.TextBox(); + this.tabZipUnZip = new System.Windows.Forms.TabControl(); + this.tabPageZip = new System.Windows.Forms.TabPage(); + this.lblRootDirCheck = new System.Windows.Forms.Label(); + this.cbxRootDir = new System.Windows.Forms.CheckBox(); + this.btnCompress = new System.Windows.Forms.Button(); + this.cmbCmpLv = new System.Windows.Forms.ComboBox(); + this.lblCyp = new System.Windows.Forms.Label(); + this.lblCmpLv = new System.Windows.Forms.Label(); + this.cmbCyp = new System.Windows.Forms.ComboBox(); + this.tabPageUnZip = new System.Windows.Forms.TabPage(); + this.btnDecomp = new System.Windows.Forms.Button(); + this.lblEEFA = new System.Windows.Forms.Label(); + this.cmbEEFA = new System.Windows.Forms.ComboBox(); + this.cmbEnc = new System.Windows.Forms.ComboBox(); + this.lblPass = new System.Windows.Forms.Label(); + this.txtFolder = new System.Windows.Forms.TextBox(); + this.tabPageManifesto = new System.Windows.Forms.TabPage(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.lblInsDir = new System.Windows.Forms.Label(); + this.txtInsDir = new System.Windows.Forms.TextBox(); + this.lblExeName = new System.Windows.Forms.Label(); + this.txtExeName = new System.Windows.Forms.TextBox(); + this.btnCreateManifesto = new System.Windows.Forms.Button(); + this.btnRemoveZIPFile = new System.Windows.Forms.Button(); + this.btnAddZIPFile = new System.Windows.Forms.Button(); + this.lbxZIPFiles = new System.Windows.Forms.ListBox(); + this.panel1.SuspendLayout(); + this.tabDeployZipPac.SuspendLayout(); + this.tabPageDeployWithHTTP.SuspendLayout(); + this.gbxWWW.SuspendLayout(); + this.gbxProxy.SuspendLayout(); + this.tabPageZipPackage.SuspendLayout(); + this.tabZipUnZip.SuspendLayout(); + this.tabPageZip.SuspendLayout(); + this.tabPageUnZip.SuspendLayout(); + this.tabPageManifesto.SuspendLayout(); + this.SuspendLayout(); + // + // folderBrowserDialog1 + // + resources.ApplyResources(this.folderBrowserDialog1, "folderBrowserDialog1"); + // + // saveFileDialog1 + // + resources.ApplyResources(this.saveFileDialog1, "saveFileDialog1"); + // + // openFileDialog1 + // + this.openFileDialog1.FileName = "openFileDialog1"; + resources.ApplyResources(this.openFileDialog1, "openFileDialog1"); + // + // lblStatus + // + resources.ApplyResources(this.lblStatus, "lblStatus"); + this.lblStatus.Name = "lblStatus"; + // + // openFilesDialog1 + // + this.openFilesDialog1.FileName = "openFilesDialog1"; + resources.ApplyResources(this.openFilesDialog1, "openFilesDialog1"); + this.openFilesDialog1.Multiselect = true; + // + // panel1 + // + resources.ApplyResources(this.panel1, "panel1"); + this.panel1.Controls.Add(this.tabDeployZipPac); + this.panel1.Name = "panel1"; + // + // tabDeployZipPac + // + resources.ApplyResources(this.tabDeployZipPac, "tabDeployZipPac"); + this.tabDeployZipPac.Controls.Add(this.tabPageDeployWithHTTP); + this.tabDeployZipPac.Controls.Add(this.tabPageZipPackage); + this.tabDeployZipPac.Controls.Add(this.tabPageManifesto); + this.tabDeployZipPac.Name = "tabDeployZipPac"; + this.tabDeployZipPac.SelectedIndex = 0; + // + // tabPageDeployWithHTTP + // + resources.ApplyResources(this.tabPageDeployWithHTTP, "tabPageDeployWithHTTP"); + this.tabPageDeployWithHTTP.Controls.Add(this.btnDelHistory); + this.tabPageDeployWithHTTP.Controls.Add(this.lblHistorys); + this.tabPageDeployWithHTTP.Controls.Add(this.cmbHistorys); + this.tabPageDeployWithHTTP.Controls.Add(this.btnCheckUpdateAndInstall); + this.tabPageDeployWithHTTP.Controls.Add(this.gbxWWW); + this.tabPageDeployWithHTTP.Controls.Add(this.gbxProxy); + this.tabPageDeployWithHTTP.Name = "tabPageDeployWithHTTP"; + this.tabPageDeployWithHTTP.UseVisualStyleBackColor = true; + // + // btnDelHistory + // + resources.ApplyResources(this.btnDelHistory, "btnDelHistory"); + this.btnDelHistory.Name = "btnDelHistory"; + this.btnDelHistory.UseVisualStyleBackColor = true; + this.btnDelHistory.Click += new System.EventHandler(this.btnDelHistory_Click); + // + // lblHistorys + // + resources.ApplyResources(this.lblHistorys, "lblHistorys"); + this.lblHistorys.Name = "lblHistorys"; + // + // cmbHistorys + // + resources.ApplyResources(this.cmbHistorys, "cmbHistorys"); + this.cmbHistorys.FormattingEnabled = true; + this.cmbHistorys.Name = "cmbHistorys"; + this.cmbHistorys.SelectedIndexChanged += new System.EventHandler(this.cmbHistorys_SelectedIndexChanged); + // + // btnCheckUpdateAndInstall + // + resources.ApplyResources(this.btnCheckUpdateAndInstall, "btnCheckUpdateAndInstall"); + this.btnCheckUpdateAndInstall.Name = "btnCheckUpdateAndInstall"; + this.btnCheckUpdateAndInstall.UseVisualStyleBackColor = true; + this.btnCheckUpdateAndInstall.Click += new System.EventHandler(this.btnCheckUpdateAndInstall_Click); + // + // gbxWWW + // + resources.ApplyResources(this.gbxWWW, "gbxWWW"); + this.gbxWWW.Controls.Add(this.txtURL); + this.gbxWWW.Controls.Add(this.txtDomain); + this.gbxWWW.Controls.Add(this.lblDomain); + this.gbxWWW.Controls.Add(this.lblURL); + this.gbxWWW.Controls.Add(this.txtPWD); + this.gbxWWW.Controls.Add(this.lblPWD); + this.gbxWWW.Controls.Add(this.lblUID); + this.gbxWWW.Controls.Add(this.txtUID); + this.gbxWWW.Name = "gbxWWW"; + this.gbxWWW.TabStop = false; + // + // txtURL + // + resources.ApplyResources(this.txtURL, "txtURL"); + this.txtURL.Name = "txtURL"; + // + // txtDomain + // + resources.ApplyResources(this.txtDomain, "txtDomain"); + this.txtDomain.Name = "txtDomain"; + // + // lblDomain + // + resources.ApplyResources(this.lblDomain, "lblDomain"); + this.lblDomain.Name = "lblDomain"; + // + // lblURL + // + resources.ApplyResources(this.lblURL, "lblURL"); + this.lblURL.Name = "lblURL"; + // + // txtPWD + // + resources.ApplyResources(this.txtPWD, "txtPWD"); + this.txtPWD.Name = "txtPWD"; + // + // lblPWD + // + resources.ApplyResources(this.lblPWD, "lblPWD"); + this.lblPWD.Name = "lblPWD"; + // + // lblUID + // + resources.ApplyResources(this.lblUID, "lblUID"); + this.lblUID.Name = "lblUID"; + // + // txtUID + // + resources.ApplyResources(this.txtUID, "txtUID"); + this.txtUID.Name = "txtUID"; + // + // gbxProxy + // + resources.ApplyResources(this.gbxProxy, "gbxProxy"); + this.gbxProxy.Controls.Add(this.txtProxyDomain); + this.gbxProxy.Controls.Add(this.lblProxyDomain); + this.gbxProxy.Controls.Add(this.lblProxyPWD); + this.gbxProxy.Controls.Add(this.txtProxyURL); + this.gbxProxy.Controls.Add(this.txtProxyPWD); + this.gbxProxy.Controls.Add(this.lblProxyURL); + this.gbxProxy.Controls.Add(this.txtProxyUID); + this.gbxProxy.Controls.Add(this.lblProxyUID); + this.gbxProxy.Name = "gbxProxy"; + this.gbxProxy.TabStop = false; + // + // txtProxyDomain + // + resources.ApplyResources(this.txtProxyDomain, "txtProxyDomain"); + this.txtProxyDomain.Name = "txtProxyDomain"; + // + // lblProxyDomain + // + resources.ApplyResources(this.lblProxyDomain, "lblProxyDomain"); + this.lblProxyDomain.Name = "lblProxyDomain"; + // + // lblProxyPWD + // + resources.ApplyResources(this.lblProxyPWD, "lblProxyPWD"); + this.lblProxyPWD.Name = "lblProxyPWD"; + // + // txtProxyURL + // + resources.ApplyResources(this.txtProxyURL, "txtProxyURL"); + this.txtProxyURL.Name = "txtProxyURL"; + // + // txtProxyPWD + // + resources.ApplyResources(this.txtProxyPWD, "txtProxyPWD"); + this.txtProxyPWD.Name = "txtProxyPWD"; + // + // lblProxyURL + // + resources.ApplyResources(this.lblProxyURL, "lblProxyURL"); + this.lblProxyURL.Name = "lblProxyURL"; + // + // txtProxyUID + // + resources.ApplyResources(this.txtProxyUID, "txtProxyUID"); + this.txtProxyUID.Name = "txtProxyUID"; + // + // lblProxyUID + // + resources.ApplyResources(this.lblProxyUID, "lblProxyUID"); + this.lblProxyUID.Name = "lblProxyUID"; + // + // tabPageZipPackage + // + resources.ApplyResources(this.tabPageZipPackage, "tabPageZipPackage"); + this.tabPageZipPackage.Controls.Add(this.lblFolder); + this.tabPageZipPackage.Controls.Add(this.txtFile); + this.tabPageZipPackage.Controls.Add(this.lblFile); + this.tabPageZipPackage.Controls.Add(this.txtPass); + this.tabPageZipPackage.Controls.Add(this.lblEnc); + this.tabPageZipPackage.Controls.Add(this.btnSelectFolder); + this.tabPageZipPackage.Controls.Add(this.lblExt); + this.tabPageZipPackage.Controls.Add(this.btnSelectSaveFile); + this.tabPageZipPackage.Controls.Add(this.cbxExt); + this.tabPageZipPackage.Controls.Add(this.txtExt); + this.tabPageZipPackage.Controls.Add(this.tabZipUnZip); + this.tabPageZipPackage.Controls.Add(this.cmbEnc); + this.tabPageZipPackage.Controls.Add(this.lblPass); + this.tabPageZipPackage.Controls.Add(this.txtFolder); + this.tabPageZipPackage.Name = "tabPageZipPackage"; + this.tabPageZipPackage.UseVisualStyleBackColor = true; + // + // lblFolder + // + resources.ApplyResources(this.lblFolder, "lblFolder"); + this.lblFolder.Name = "lblFolder"; + // + // txtFile + // + resources.ApplyResources(this.txtFile, "txtFile"); + this.txtFile.Name = "txtFile"; + // + // lblFile + // + resources.ApplyResources(this.lblFile, "lblFile"); + this.lblFile.Name = "lblFile"; + // + // txtPass + // + resources.ApplyResources(this.txtPass, "txtPass"); + this.txtPass.Name = "txtPass"; + // + // lblEnc + // + resources.ApplyResources(this.lblEnc, "lblEnc"); + this.lblEnc.Name = "lblEnc"; + // + // btnSelectFolder + // + resources.ApplyResources(this.btnSelectFolder, "btnSelectFolder"); + this.btnSelectFolder.Name = "btnSelectFolder"; + this.btnSelectFolder.UseVisualStyleBackColor = true; + this.btnSelectFolder.Click += new System.EventHandler(this.btnSelectFolder_Click); + // + // lblExt + // + resources.ApplyResources(this.lblExt, "lblExt"); + this.lblExt.Name = "lblExt"; + // + // btnSelectSaveFile + // + resources.ApplyResources(this.btnSelectSaveFile, "btnSelectSaveFile"); + this.btnSelectSaveFile.Name = "btnSelectSaveFile"; + this.btnSelectSaveFile.UseVisualStyleBackColor = true; + this.btnSelectSaveFile.Click += new System.EventHandler(this.btnSelectSaveFile_Click); + // + // cbxExt + // + resources.ApplyResources(this.cbxExt, "cbxExt"); + this.cbxExt.Name = "cbxExt"; + this.cbxExt.UseVisualStyleBackColor = true; + this.cbxExt.CheckedChanged += new System.EventHandler(this.cbxExt_CheckedChanged); + // + // txtExt + // + resources.ApplyResources(this.txtExt, "txtExt"); + this.txtExt.Name = "txtExt"; + // + // tabZipUnZip + // + resources.ApplyResources(this.tabZipUnZip, "tabZipUnZip"); + this.tabZipUnZip.Controls.Add(this.tabPageZip); + this.tabZipUnZip.Controls.Add(this.tabPageUnZip); + this.tabZipUnZip.Name = "tabZipUnZip"; + this.tabZipUnZip.SelectedIndex = 0; + // + // tabPageZip + // + resources.ApplyResources(this.tabPageZip, "tabPageZip"); + this.tabPageZip.Controls.Add(this.lblRootDirCheck); + this.tabPageZip.Controls.Add(this.cbxRootDir); + this.tabPageZip.Controls.Add(this.btnCompress); + this.tabPageZip.Controls.Add(this.cmbCmpLv); + this.tabPageZip.Controls.Add(this.lblCyp); + this.tabPageZip.Controls.Add(this.lblCmpLv); + this.tabPageZip.Controls.Add(this.cmbCyp); + this.tabPageZip.Name = "tabPageZip"; + this.tabPageZip.UseVisualStyleBackColor = true; + // + // lblRootDirCheck + // + resources.ApplyResources(this.lblRootDirCheck, "lblRootDirCheck"); + this.lblRootDirCheck.Name = "lblRootDirCheck"; + // + // cbxRootDir + // + resources.ApplyResources(this.cbxRootDir, "cbxRootDir"); + this.cbxRootDir.Name = "cbxRootDir"; + this.cbxRootDir.UseVisualStyleBackColor = true; + // + // btnCompress + // + resources.ApplyResources(this.btnCompress, "btnCompress"); + this.btnCompress.Name = "btnCompress"; + this.btnCompress.UseVisualStyleBackColor = true; + this.btnCompress.Click += new System.EventHandler(this.btnCompress_Click); + // + // cmbCmpLv + // + resources.ApplyResources(this.cmbCmpLv, "cmbCmpLv"); + this.cmbCmpLv.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cmbCmpLv.FormattingEnabled = true; + this.cmbCmpLv.Name = "cmbCmpLv"; + // + // lblCyp + // + resources.ApplyResources(this.lblCyp, "lblCyp"); + this.lblCyp.Name = "lblCyp"; + // + // lblCmpLv + // + resources.ApplyResources(this.lblCmpLv, "lblCmpLv"); + this.lblCmpLv.Name = "lblCmpLv"; + // + // cmbCyp + // + resources.ApplyResources(this.cmbCyp, "cmbCyp"); + this.cmbCyp.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cmbCyp.FormattingEnabled = true; + this.cmbCyp.Name = "cmbCyp"; + // + // tabPageUnZip + // + resources.ApplyResources(this.tabPageUnZip, "tabPageUnZip"); + this.tabPageUnZip.Controls.Add(this.btnDecomp); + this.tabPageUnZip.Controls.Add(this.lblEEFA); + this.tabPageUnZip.Controls.Add(this.cmbEEFA); + this.tabPageUnZip.Name = "tabPageUnZip"; + this.tabPageUnZip.UseVisualStyleBackColor = true; + // + // btnDecomp + // + resources.ApplyResources(this.btnDecomp, "btnDecomp"); + this.btnDecomp.Name = "btnDecomp"; + this.btnDecomp.UseVisualStyleBackColor = true; + this.btnDecomp.Click += new System.EventHandler(this.btnDecomp_Click); + // + // lblEEFA + // + resources.ApplyResources(this.lblEEFA, "lblEEFA"); + this.lblEEFA.Name = "lblEEFA"; + // + // cmbEEFA + // + resources.ApplyResources(this.cmbEEFA, "cmbEEFA"); + this.cmbEEFA.FormattingEnabled = true; + this.cmbEEFA.Name = "cmbEEFA"; + // + // cmbEnc + // + resources.ApplyResources(this.cmbEnc, "cmbEnc"); + this.cmbEnc.FormattingEnabled = true; + this.cmbEnc.Items.AddRange(new object[] { + resources.GetString("cmbEnc.Items"), + resources.GetString("cmbEnc.Items1"), + resources.GetString("cmbEnc.Items2")}); + this.cmbEnc.Name = "cmbEnc"; + // + // lblPass + // + resources.ApplyResources(this.lblPass, "lblPass"); + this.lblPass.Name = "lblPass"; + // + // txtFolder + // + resources.ApplyResources(this.txtFolder, "txtFolder"); + this.txtFolder.Name = "txtFolder"; + // + // tabPageManifesto + // + resources.ApplyResources(this.tabPageManifesto, "tabPageManifesto"); + this.tabPageManifesto.Controls.Add(this.label3); + this.tabPageManifesto.Controls.Add(this.label2); + this.tabPageManifesto.Controls.Add(this.label1); + this.tabPageManifesto.Controls.Add(this.lblInsDir); + this.tabPageManifesto.Controls.Add(this.txtInsDir); + this.tabPageManifesto.Controls.Add(this.lblExeName); + this.tabPageManifesto.Controls.Add(this.txtExeName); + this.tabPageManifesto.Controls.Add(this.btnCreateManifesto); + this.tabPageManifesto.Controls.Add(this.btnRemoveZIPFile); + this.tabPageManifesto.Controls.Add(this.btnAddZIPFile); + this.tabPageManifesto.Controls.Add(this.lbxZIPFiles); + this.tabPageManifesto.Name = "tabPageManifesto"; + this.tabPageManifesto.UseVisualStyleBackColor = true; + // + // label3 + // + resources.ApplyResources(this.label3, "label3"); + this.label3.Name = "label3"; + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // lblInsDir + // + resources.ApplyResources(this.lblInsDir, "lblInsDir"); + this.lblInsDir.Name = "lblInsDir"; + // + // txtInsDir + // + resources.ApplyResources(this.txtInsDir, "txtInsDir"); + this.txtInsDir.Name = "txtInsDir"; + // + // lblExeName + // + resources.ApplyResources(this.lblExeName, "lblExeName"); + this.lblExeName.Name = "lblExeName"; + // + // txtExeName + // + resources.ApplyResources(this.txtExeName, "txtExeName"); + this.txtExeName.Name = "txtExeName"; + // + // btnCreateManifesto + // + resources.ApplyResources(this.btnCreateManifesto, "btnCreateManifesto"); + this.btnCreateManifesto.Name = "btnCreateManifesto"; + this.btnCreateManifesto.UseVisualStyleBackColor = true; + this.btnCreateManifesto.Click += new System.EventHandler(this.btnCreateManifesto_Click); + // + // btnRemoveZIPFile + // + resources.ApplyResources(this.btnRemoveZIPFile, "btnRemoveZIPFile"); + this.btnRemoveZIPFile.Name = "btnRemoveZIPFile"; + this.btnRemoveZIPFile.UseVisualStyleBackColor = true; + this.btnRemoveZIPFile.Click += new System.EventHandler(this.btnRemoveZIPFile_Click); + // + // btnAddZIPFile + // + resources.ApplyResources(this.btnAddZIPFile, "btnAddZIPFile"); + this.btnAddZIPFile.Name = "btnAddZIPFile"; + this.btnAddZIPFile.UseVisualStyleBackColor = true; + this.btnAddZIPFile.Click += new System.EventHandler(this.btnAddZIPFile_Click); + // + // lbxZIPFiles + // + resources.ApplyResources(this.lbxZIPFiles, "lbxZIPFiles"); + this.lbxZIPFiles.FormattingEnabled = true; + this.lbxZIPFiles.Name = "lbxZIPFiles"; + // + // Form1 + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.panel1); + this.Controls.Add(this.lblStatus); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.Name = "Form1"; + this.Load += new System.EventHandler(this.Form1_Load); + this.panel1.ResumeLayout(false); + this.tabDeployZipPac.ResumeLayout(false); + this.tabPageDeployWithHTTP.ResumeLayout(false); + this.tabPageDeployWithHTTP.PerformLayout(); + this.gbxWWW.ResumeLayout(false); + this.gbxWWW.PerformLayout(); + this.gbxProxy.ResumeLayout(false); + this.gbxProxy.PerformLayout(); + this.tabPageZipPackage.ResumeLayout(false); + this.tabPageZipPackage.PerformLayout(); + this.tabZipUnZip.ResumeLayout(false); + this.tabPageZip.ResumeLayout(false); + this.tabPageZip.PerformLayout(); + this.tabPageUnZip.ResumeLayout(false); + this.tabPageUnZip.PerformLayout(); + this.tabPageManifesto.ResumeLayout(false); + this.tabPageManifesto.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog1; + private System.Windows.Forms.SaveFileDialog saveFileDialog1; + private System.Windows.Forms.OpenFileDialog openFileDialog1; + private System.Windows.Forms.Label lblStatus; + private System.Windows.Forms.OpenFileDialog openFilesDialog1; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.TabControl tabDeployZipPac; + private System.Windows.Forms.TabPage tabPageDeployWithHTTP; + private System.Windows.Forms.Button btnDelHistory; + private System.Windows.Forms.Label lblHistorys; + private System.Windows.Forms.ComboBox cmbHistorys; + private System.Windows.Forms.Button btnCheckUpdateAndInstall; + private System.Windows.Forms.GroupBox gbxWWW; + private System.Windows.Forms.TextBox txtURL; + private System.Windows.Forms.TextBox txtDomain; + private System.Windows.Forms.Label lblDomain; + private System.Windows.Forms.Label lblURL; + private System.Windows.Forms.TextBox txtPWD; + private System.Windows.Forms.Label lblPWD; + private System.Windows.Forms.Label lblUID; + private System.Windows.Forms.TextBox txtUID; + private System.Windows.Forms.GroupBox gbxProxy; + private System.Windows.Forms.TextBox txtProxyDomain; + private System.Windows.Forms.Label lblProxyDomain; + private System.Windows.Forms.Label lblProxyPWD; + private System.Windows.Forms.TextBox txtProxyURL; + private System.Windows.Forms.TextBox txtProxyPWD; + private System.Windows.Forms.Label lblProxyURL; + private System.Windows.Forms.TextBox txtProxyUID; + private System.Windows.Forms.Label lblProxyUID; + private System.Windows.Forms.TabPage tabPageZipPackage; + private System.Windows.Forms.Label lblFolder; + private System.Windows.Forms.TextBox txtFile; + private System.Windows.Forms.Label lblFile; + private System.Windows.Forms.TextBox txtPass; + private System.Windows.Forms.Label lblEnc; + private System.Windows.Forms.Button btnSelectFolder; + private System.Windows.Forms.Label lblExt; + private System.Windows.Forms.Button btnSelectSaveFile; + private System.Windows.Forms.CheckBox cbxExt; + private System.Windows.Forms.TextBox txtExt; + private System.Windows.Forms.TabControl tabZipUnZip; + private System.Windows.Forms.TabPage tabPageZip; + private System.Windows.Forms.CheckBox cbxRootDir; + private System.Windows.Forms.Button btnCompress; + private System.Windows.Forms.ComboBox cmbCmpLv; + private System.Windows.Forms.Label lblCyp; + private System.Windows.Forms.Label lblCmpLv; + private System.Windows.Forms.ComboBox cmbCyp; + private System.Windows.Forms.TabPage tabPageUnZip; + private System.Windows.Forms.Button btnDecomp; + private System.Windows.Forms.Label lblEEFA; + private System.Windows.Forms.ComboBox cmbEEFA; + private System.Windows.Forms.ComboBox cmbEnc; + private System.Windows.Forms.Label lblPass; + private System.Windows.Forms.TextBox txtFolder; + private System.Windows.Forms.TabPage tabPageManifesto; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label lblInsDir; + private System.Windows.Forms.TextBox txtInsDir; + private System.Windows.Forms.Label lblExeName; + private System.Windows.Forms.TextBox txtExeName; + private System.Windows.Forms.Button btnCreateManifesto; + private System.Windows.Forms.Button btnRemoveZIPFile; + private System.Windows.Forms.Button btnAddZIPFile; + private System.Windows.Forms.ListBox lbxZIPFiles; + private System.Windows.Forms.Label lblRootDirCheck; + private System.Windows.Forms.Label label3; + } +} + diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.cs new file mode 100644 index 000000000..c5d41224f --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.cs @@ -0,0 +1,762 @@ +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** + +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :Form1 +//* クラス日本語名 :メイン画面 +//* +//* 作成者 :生技 西野 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2011/04/18 西野 大介 新規作成 +//* 2011/07/01 西野 大介 履歴コンボは都度クリア +//* 2011/07/04 西野 大介 圧縮・解凍に入力チェック+例外処理を追加 +//* 2011/07/04 西野 大介 マニュフェスト作成に入力チェック+例外処理を追加 +//* 2011/08/30 西野 大介 異常終了時に退避ディレクトリからリカバリ。 +//* 2011/08/30 西野 大介 テンポラリの削除処理を追加した(例外処理を追加)。 +//* 2011/08/30 西野 大介 ファイル ダイアログのリセット処理を追加した。 +//* 2011/08/30 西野 大介 ChangeProgressParameterの使用に漏れがあった。 +//* 2011/09/05 西野 大介 GCするコードを追加→修正(解凍ZIPがCloseされないため) +//* 2011/09/08 西野 大介 リカバリ処理のログ出力位置の変更 +//* (リカバリしない時ログを出力しないよう変更)。 +//* 2011/09/12 西野 大介 画面表示せず、ログ出力のみする例外処理方式を追加 +//* 2014/04/24 Sai For internationalization, Replaced all the Japanese language exception messages with GetMessage.GetMessageDescription() method call +//* Moved all the Japanese language exception messages to MSGDefinition_ja-JP.xml file Placed all the converted +//* Japanese language exception messages to MSGDefinition.xml file for internationalization supporting English Language. +//* 2014/04/25 Sai Replaced all the Japanese language in both UI and code with ResorceManager.GetString() method call +//* 2020/08/03 西野 大介 NETCOREAPP対応 +//********************************************************************************** + +using System; +using System.IO; +using System.Text; +using System.Collections.Generic; +using System.Drawing; +using System.Resources; +using System.Windows.Forms; + +using Touryo.Infrastructure.Business.RichClient.Asynchronous; +using Touryo.Infrastructure.Framework.RichClient.Asynchronous; +using Touryo.Infrastructure.Framework.Util; +using Touryo.Infrastructure.Public.IO; +using Touryo.Infrastructure.Public.Str; + +namespace DeployZipPackWithHTTP +{ + /// <summary>メイン画面</summary> + public partial class Form1 : Form + { + /// <summary>ステータス表示用</summary> + public string Status + { + set + { + this.lblStatus.Text = value; + } + get + { + return this.lblStatus.Text; + } + } + + /// <summary> + /// Getting ResourceManager instance from Resources to apply internationalization + /// </summary> + private ResourceManager ResourceMgr + { + get + { + return Resources.Resource.ResourceManager; + } + } + + #region 初期処理 + + /// <summary>コンストラクタ</summary> + public Form1() + { + InitializeComponent(); + } + + /// <summary>画面ロード</summary> + private void Form1_Load(object sender, EventArgs e) + { + // デプロイ + + // 列挙型設定 + this.cmbEnc.SelectedIndex = 0; + this.cmbCyp.DataSource = Enum.GetValues(typeof(ZipEncryptionAlgorithmV2)); + this.cmbCmpLv.DataSource = Enum.GetValues(typeof(ZipCompressionLevelV2)); + this.cmbEEFA.DataSource = Enum.GetValues(typeof(ExtractExistingFileActionV2)); + + // 自己解凍書庫(cbxFormat / cmbFormat)は廃止した(#528)。 + // SharpZipLib に相当機能が無いため。配布フローは .zip しか扱わず、 + // 作った自己解凍 EXE を本ツール自身が読む経路も無かった。 + + // ZIP作成 + this.txtExt.Text = "txt,csv,cs"; + + this.txtExt.Enabled = false; + + // 声明文作成 + + //--- + + // 履歴を復元 + this.LoadBins(); + } + + /// <summary>履歴で初期化</summary> + private void cmbHistorys_SelectedIndexChanged(object sender, EventArgs e) + { + // 履歴で初期化 + Entry entry = null; + + foreach (Entry temp in Program.Histories) + { + if (this.cmbHistorys.Text == temp.WWWURL) + { + entry = temp; + } + } + + if (entry != null) + { + this.txtURL.Text = entry.WWWURL; + this.txtUID.Text = entry.WWWUID; + this.txtPWD.Text = entry.WWWPWD; + this.txtDomain.Text = entry.WWWDomain; + + this.txtProxyURL.Text = entry.ProxyURL; + this.txtProxyUID.Text = entry.ProxyUID; + this.txtProxyPWD.Text = entry.ProxyPWD; + this.txtProxyDomain.Text = entry.ProxyDomain; + } + } + + #region データ ロード + + /// <summary>バイナリファイルをロード</summary> + private void LoadBins() + { + this.LoadEntry(); + this.LoadHistories(); + + this.Refresh(); + } + + /// <summary>エントリのロード</summary> + private void LoadEntry() + { + // current.bin(前回入力) + Entry entry = Program.LoadCurrent(); + + // 設定 + if (entry != null) + { + this.txtURL.Text = entry.WWWURL; + this.txtUID.Text = entry.WWWUID; + this.txtPWD.Text = entry.WWWPWD; + this.txtDomain.Text = entry.WWWDomain; + + this.txtProxyURL.Text = entry.ProxyURL; + this.txtProxyUID.Text = entry.ProxyUID; + this.txtProxyPWD.Text = entry.ProxyPWD; + this.txtProxyDomain.Text = entry.ProxyDomain; + } + } + + /// <summary>履歴のロード</summary> + private void LoadHistories() + { + // histories.bin(履歴) + //Program.Histories = Program.LoadHistories(); + Program.LoadHistories(); + + // 設定 + this.cmbHistorys.Items.Clear(); + if (Program.Histories != null) + { + foreach (Entry history in Program.Histories) + { + this.cmbHistorys.Items.Add(history.WWWURL); + } + } + //else + //{ + // Program.Histories = new List<Entry>(); + //} + } + + #endregion + + #endregion + + #region 圧縮・解凍 + + /// <summary>圧縮処理</summary> + private void btnCompress_Click(object sender, EventArgs e) + { + try + { + // チェック処理 + this.CheckComp_DeComp(); + + // UIコントロールから情報を取得する。 + string[] exts = null; + if (this.txtExt.Enabled) + { + exts = this.txtExt.Text.Split(','); + } + + // ルートのディレクトリを作るか作らないか。 + // チェック無し … 指定ZIPファイル名をルートZIP内フォルダに含める(個別のフォルダ圧縮) + // チェック有り … 含めない(ルート フォルダからの圧縮) + string rootPathInArchive = ""; + + if (!this.cbxRootDir.Checked) + { + string[] temp = this.txtFile.Text.Split('\\'); + rootPathInArchive = temp[temp.Length - 1]; + } + + int count = this.Compress( + this.txtFile.Text, this.txtFolder.Text, exts, false, rootPathInArchive, + Encoding.GetEncoding((string)this.cmbEnc.SelectedItem), + (ZipEncryptionAlgorithmV2)this.cmbCyp.SelectedItem, this.txtPass.Text, + (ZipCompressionLevelV2)this.cmbCmpLv.SelectedItem); + + // 旧 StatusMSG(DotNetZip のログ文言)は無い。圧縮したファイル数を出す。 + // **文言は直書きしない。** Resources\Resource.resx に置いて + // ResourceMgr.GetString で取り出す(国際化のため)。 + CustMsgBox custMsgBox = new CustMsgBox( + ResourceMgr.GetString("Error0002"), + string.Format(ResourceMgr.GetString("I0007"), count), + SystemIcons.Information); + custMsgBox.ShowDialog(); + } + catch (Exception ex) + { + //MessageBox.Show(ex.Message, "エラーが発生しました。", MessageBoxButtons.OK, MessageBoxIcon.Error); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + MessageBox.Show(ex.Message, ResourceMgr.GetString("E0001"), MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// <summary>圧縮処理</summary> + /// <param name="zipFileToCreate">圧縮ファイル名(拡張子は付けない。".zip"が付く)</param> + /// <param name="directoryToZip">圧縮対象フォルダ</param> + /// <param name="excludeExts">除外する拡張子(nullなら除外しない)</param> + /// <param name="topOnly">直下のファイルだけを対象にする(サブフォルダを再帰しない)</param> + /// <param name="rootPathInArchive">書庫内ルートフォルダ(空ならルートから)</param> + /// <param name="enc">エンコーディング</param> + /// <param name="cyp">暗号化</param> + /// <param name="zipPassword">パスワード</param> + /// <param name="cmpLv">圧縮レベル</param> + /// <returns>圧縮したファイル数</returns> + /// <remarks> + /// btnCompress_Click から切り出したもの(#528)。 + /// **UIコントロールを参照しない。** 引数は組み込み型のみで、CUI からも呼べる。 + /// 例外の表示は、呼び出し側の責務とする。 + /// + /// topOnly は CUI で足したもの(GUI には対応するチェック ボックスが無い)。 + /// **これが無いと「ルート直下だけの ZIP」が作れない。** + /// CreateZipFromFolder は再帰するため、ルートを対象にすると + /// サブフォルダまで入ってしまう。 + /// </remarks> + public int Compress( + string zipFileToCreate, string directoryToZip, + string[] excludeExts, bool topOnly, string rootPathInArchive, + Encoding enc, ZipEncryptionAlgorithmV2 cyp, string zipPassword, + ZipCompressionLevelV2 cmpLv) + { + // 圧縮部品 + ZipperV2 z = new ZipperV2(); + + // 進捗報告処理 + z.SaveProgress = Program.MySaveProgressEventHandler; + + // 選択基準 + // + // 除外拡張子と「直下だけ」は、どちらも選択デリゲートで実現する。 + // **ZipperV2 は変えない。** 走査はするが、選ばれなければ書庫に入らない。 + ZipBaseV2.SelectionDelegate scd = null; + object info = null; + + if (topOnly) + { + scd = Program.SelectionCriteriaDlgt3; + info = new object[] { directoryToZip, excludeExts }; + } + else if (excludeExts != null) + { + scd = Program.SelectionCriteriaDlgt1; + info = excludeExts; + } + + // 圧縮:デリゲートでフィルタ + // + // 旧 Zipper には selectionCriteriaString("name != *.txt" 等)で + // フィルタするオーバーロードもあったが、DotNetZip 独自の DSL であり + // 代替が無いため廃止した(#524)。デリゲートに一本化している。 + z.CreateZipFromFolder( + zipFileToCreate, directoryToZip, + scd, info, rootPathInArchive, // ここを空文字列にするとルートフォルダ無しになる。 + enc, cyp, zipPassword, cmpLv); + + return z.ZippedFiles.Length; + } + + /// <summary>解凍処理</summary> + private void btnDecomp_Click(object sender, EventArgs e) + { + try + { + // チェック処理 + this.CheckComp_DeComp(); + + // 解凍部品 + UnZipperV2 uz = new UnZipperV2(); + + // 選択基準 + string[] exts = null; + ZipBaseV2.SelectionDelegate scd = null; + + if (this.txtExt.Enabled) + { + exts = this.txtExt.Text.Split(','); + scd = Program.SelectionCriteriaDlgt2; + } + + // 解凍時、上書き制御 + uz.ExtractProgress = Program.MyExtractProgressEventHandler; + + // 解凍:デリゲートでフィルタ + uz.ExtractFileFromZip( + this.txtFile.Text, this.txtFolder.Text, scd, exts, + (ExtractExistingFileActionV2)this.cmbEEFA.SelectedItem, + Encoding.GetEncoding((string)this.cmbEnc.SelectedItem), + this.txtPass.Text); + + // 旧 StatusMSG(DotNetZip のログ文言)は無い。解凍したファイル数を出す。 + CustMsgBox custMsgBox = new CustMsgBox( + ResourceMgr.GetString("Error0003"), + string.Format(ResourceMgr.GetString("I0008"), uz.ExtractedFiles.Length), + SystemIcons.Information); + custMsgBox.ShowDialog(); + } + catch(Exception ex) + { + //MessageBox.Show(ex.Message, "エラーが発生しました。", MessageBoxButtons.OK, MessageBoxIcon.Error); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + MessageBox.Show(ex.Message, ResourceMgr.GetString("E0001"), MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// <summary>チェック処理</summary> + private void CheckComp_DeComp() + { + if (string.IsNullOrEmpty(this.txtFolder.Text)) + { + //throw new Exception(string.Format(GetMessage.GetMessageDescription("E0007"), "フォルダ パス")); + //For internationalization, Replaced all the Japanese language exception messages with GetMessage.GetMessageDescription() method call + throw new Exception(string.Format(GetMessage.GetMessageDescription("E0007"), GetMessage.GetMessageDescription("M0001"))); + } + + if(string.IsNullOrEmpty(this.txtFile.Text)) + { + //throw new Exception(string.Format(GetMessage.GetMessageDescription("E0007"), "ファイル パス")); + //For internationalization, Replaced all the Japanese language exception messages with GetMessage.GetMessageDescription() method call + throw new Exception(string.Format(GetMessage.GetMessageDescription("E0007"), GetMessage.GetMessageDescription("M0002"))); + } + } + + #region いろいろ選択 + + /// <summary>フォルダ選択</summary> + private void btnSelectFolder_Click(object sender, EventArgs e) + { + //this.folderBrowserDialog1.ShowDialog(); + this.txtFolder.Text = BrowseFolder(); //folderBrowserDialog1.SelectedPath; + } + + /// <summary> + /// フォルダ選択(OpenFileDialogで代用) + /// </summary> + /// <remarks> + /// https://gomana2.hatenablog.jp/entry/2020/07/15/163000 + /// </remarks> + /// <returns> + /// 選択フォルダのパス + /// </returns> + private string BrowseFolder() + { + using (var ofd = new OpenFileDialog() { + FileName = "SelectFolder", Filter = "Folder|.", + CheckFileExists = false, InitialDirectory = Environment.CurrentDirectory}) + { + if (ofd.ShowDialog() == DialogResult.OK) + { + return Path.GetDirectoryName(ofd.FileName); + } + } + + return ""; + } + + /// <summary>ファイル選択</summary> + private void btnSelectSaveFile_Click(object sender, EventArgs e) + { + //if (this.tabZipUnZip.SelectedTab.Text == "圧縮") + if (this.tabZipUnZip.SelectedTab.Text == ResourceMgr.GetString("T0001")) + { + // 保存 + this.saveFileDialog1.DefaultExt = ""; + this.saveFileDialog1.ShowDialog(); + this.txtFile.Text = saveFileDialog1.FileName; + } + else + { + // 開く + //this.openFileDialog1.Filter = "ZIPファイル|*.zip"; + this.openFileDialog1.Filter = ResourceMgr.GetString("EXT0001"); + + this.openFileDialog1.ShowDialog(); + this.txtFile.Text = openFileDialog1.FileName; + } + } + + /// <summary>拡張子選択</summary> + private void cbxExt_CheckedChanged(object sender, EventArgs e) + { + if (((CheckBox)sender).Checked == true) + { + this.txtExt.Enabled = true; + } + else + { + this.txtExt.Enabled = false; + } + } + + + #endregion + + #endregion + + #region マニュフェスト + + /// <summary>ZIPを追加する</summary> + private void btnAddZIPFile_Click(object sender, EventArgs e) + { + this.openFilesDialog1.Reset(); // ごみを消去 + this.openFilesDialog1.ShowDialog(); + string[] zipFiles = this.openFilesDialog1.FileNames; + + foreach (string zipFile in zipFiles) + { + // 追加済みフラグ + bool isAdded = false; + + if (zipFile.Substring(zipFile.Length - 4, 4).ToLower() == ".zip") + { + foreach (string temp in this.lbxZIPFiles.Items) + { + // 追加済みフラグ + if (temp == zipFile) + { + isAdded = true; + } + } + + // 追加済みで無い場合。 + if (!isAdded) + { + this.lbxZIPFiles.Items.Add(zipFile); + } + } + } + } + + /// <summary>ZIPを削除する</summary> + private void btnRemoveZIPFile_Click(object sender, EventArgs e) + { + this.lbxZIPFiles.Items.Remove( + this.lbxZIPFiles.SelectedItem); + } + + /// <summary>マニュフェストファイルを生成</summary> + private void btnCreateManifesto_Click(object sender, EventArgs e) + { + try + { + // UIコントロールから情報を取得する。 + List<string> zipFiles = new List<string>(); + foreach (string zipFile in this.lbxZIPFiles.Items) + { + zipFiles.Add(zipFile); + } + + // 保存 + this.saveFileDialog1.Reset(); // ごみを消去 + this.saveFileDialog1.DefaultExt = "mft"; + this.saveFileDialog1.ShowDialog(); + + this.CreateManifesto( + zipFiles.ToArray(), this.txtInsDir.Text, + this.txtExeName.Text, this.saveFileDialog1.FileName); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message, ResourceMgr.GetString("E0001"), MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// <summary>マニュフェストファイルを生成</summary> + /// <param name="zipFiles">ZIPファイルのパス</param> + /// <param name="insDir">インストール先ディレクトリ</param> + /// <param name="exeName">起動アセンブリ(カンマ区切り)</param> + /// <param name="mftFilePath">出力するマニュフェスト ファイルのパス</param> + /// <remarks> + /// btnCreateManifesto_Click から切り出したもの(#528)。 + /// **UIコントロールを参照しない。** 引数は組み込み型のみで、CUI からも呼べる。 + /// 対話(SaveFileDialog)と例外の表示は、呼び出し側の責務とする。 + /// </remarks> + public void CreateManifesto( + string[] zipFiles, string insDir, string exeName, string mftFilePath) + { + if (zipFiles == null || zipFiles.Length ==0) + { + throw new Exception(string.Format(GetMessage.GetMessageDescription("E0007"), GetMessage.GetMessageDescription("M0003"))); + } + + if (string.IsNullOrEmpty(insDir)) + { + throw new Exception(string.Format(GetMessage.GetMessageDescription("E0007"), GetMessage.GetMessageDescription("M0004"))); + } + + if (string.IsNullOrEmpty(exeName)) + { + throw new Exception(string.Format(GetMessage.GetMessageDescription("E0007"), GetMessage.GetMessageDescription("M0005"))); + } + + using (StreamWriter sw = new StreamWriter( + mftFilePath, false, Encoding.GetEncoding(CustomEncode.UTF_8))) + { + sw.WriteLine("ins " + insDir); + sw.WriteLine("exe " + exeName); + + foreach (string zipFile in zipFiles) + { + // 2026/08/08 まで zipFile.Split('\\') の末尾を採っていた(#528)。 + // **CUI では区切りが「/」になる**(コマンドライン解析が「\」を + // エスケープ文字として食べるため、呼び出し側が「/」で渡す)。 + // Path.GetFileName は両方の区切りを解釈するので、GUI でも結果は変わらない。 + sw.WriteLine("zip " + Path.GetFileName(zipFile)); + sw.WriteLine("md5 " + Program.GetMD5Hash(zipFile)); + } + } + } + + #endregion + + #region 更新チェック&インストール + + /// <summary>更新チェック&インストール</summary> + private void btnCheckUpdateAndInstall_Click(object sender, EventArgs e) + { + // エントリを生成 + Entry entry = new Entry(); + + entry.WWWURL = txtURL.Text; + entry.WWWUID = txtUID.Text; + entry.WWWPWD = txtPWD.Text; + entry.WWWDomain = txtDomain.Text; + //--- + entry.ProxyURL = txtProxyURL.Text; + entry.ProxyUID = txtProxyUID.Text; + entry.ProxyPWD = txtProxyPWD.Text; + entry.ProxyDomain = txtProxyDomain.Text; + + // エントリを保存 + Program.SaveCurrent(entry); + + // 履歴をロード + this.LoadHistories(); + + #region 更新処理の実行 + + // 非同期呼び出し + Program.Af = new MyBaseAsyncFunc(this.panel1); + + // 非同期処理本体デレゲード + Program.Af.AsyncFunc = new BaseAsyncFunc.AsyncFuncDelegate(Program.ExecUpdate); + + // 進捗報告・無名関数デレゲード + Program.Af.ChangeProgress = delegate(object param) + { + this.Status = ((ChangeProgressParameter)param).Status; + this.Refresh(); + }; + + // 結果設定・無名関数デレゲード + Program.Af.SetResult = delegate(object retVal) + { + if (retVal is MyException) + { + // 戻し + Program.Recover(); + + // メッセージ表示時 + MyException my_ex = (MyException)retVal; + string message = my_ex.Message; + + // ログ出力用のフィールドがあるか?ないか? + if (string.IsNullOrEmpty(my_ex.ToLog)) + { + Program.OutPutMessage(message, LogLevel.InfoLog); + } + else + { + Program.OutPutMessage(message + "\r\n" + my_ex.ToLog, LogLevel.InfoLog); + } + + MessageBox.Show(message, ResourceMgr.GetString("M0001"), MessageBoxButtons.OK, MessageBoxIcon.Information); + } + else if (retVal is Exception) + { + // 戻し + Program.Recover(); + + // 例外発生時 + string message = ""; + Exception ex = (Exception)retVal; + + message += ResourceMgr.GetString("M0002") + "\r\n"; + message += ex.Message; + message += "\r\n"; + + message += "\r\n"; + message += ResourceMgr.GetString("M0003") + "\r\n"; + message += ex.StackTrace; + message += "\r\n"; + + if (ex.InnerException != null) + { + message += "\r\n"; + message += ResourceMgr.GetString("M0004") + "\r\n"; + message += ex.InnerException.ToString(); + message += "\r\n"; + } + + Program.OutPutMessage(message, LogLevel.ErrorLog); + + CustMsgBox custMsgBox = new CustMsgBox(ResourceMgr.GetString("Error0001"), string.Format(message), SystemIcons.Error); + custMsgBox.ShowDialog(); + } + else + { + // 正常終了 + + // 履歴を保存 + Program.SaveHistories(); + + // エントリ・履歴の復元する。 + this.LoadBins(); + } + + // テンポラリの削除 + File.Delete(Program.OrgCurrentDirectory + Program.TempMftFileName); + + // GCでZIPが解放される可能性 + //GC.Collect(); + Program.system_gc_collecting(); + try + { + File.Delete(Program.OrgCurrentDirectory + Program.TempZipFileName); + } + catch (Exception ex) + { + // 例外を潰してログに出力 + Program.OutPutMessage(Program.TempZipFileName + ResourceMgr.GetString("E0002") + ex.ToString(), LogLevel.ErrorLog); + } + }; + + // 非同期処理を開始させる。 + Program.Af.Parameter = entry; + + if (Program.Af.Start()) + { + //this.XXXX(string.Format("キューイングされました、現在のスレッド数:{0}", BaseAsyncFunc.ThreadCount.ToString())); + } + else + { + //this.XXXX(string.Format("非同期スレッドが最大数に達しています。:{0}", BaseAsyncFunc.ThreadCount.ToString())); + } + + #endregion + } + + #endregion + + /// <summary>履歴を消す</summary> + private void btnDelHistory_Click(object sender, EventArgs e) + { + // 削除対象エントリ + Entry entry = null; + + // 履歴を消す + foreach (Entry temp in Program.Histories) + { + // 履歴に一致 + if (this.cmbHistorys.Text == temp.WWWURL) + { + entry = temp; + } + } + + if (entry != null) + { + // 履歴を更新 + Program.Histories.Remove(entry); + // 履歴を保存 + Program.SaveHistories(); + + // 画面を変更 + + // コンボボックス + this.LoadHistories(); + + // テキストボックス + this.txtURL.Text = ""; + this.txtUID.Text = ""; + this.txtPWD.Text = ""; + this.txtDomain.Text = ""; + + this.txtProxyURL.Text = ""; + this.txtProxyUID.Text = ""; + this.txtProxyPWD.Text = ""; + this.txtProxyDomain.Text = ""; + } + } + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.ja-JP.resx b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.ja-JP.resx new file mode 100644 index 000000000..1d52a61fe --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.ja-JP.resx @@ -0,0 +1,363 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="lblStatus.Text" xml:space="preserve"> + <value>ステータス</value> + </data> + <data name="openFilesDialog1.Filter" xml:space="preserve"> + <value>ZIPファイル|*.zip</value> + </data> + <data name="btnDelHistory.Text" xml:space="preserve"> + <value>削除</value> + </data> + <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> + <data name="lblHistorys.Size" type="System.Drawing.Size, System.Drawing"> + <value>59, 13</value> + </data> + <data name="lblHistorys.Text" xml:space="preserve"> + <value>設定ロード</value> + </data> + <data name="btnCheckUpdateAndInstall.Text" xml:space="preserve"> + <value>更新をチェックしてインストール</value> + </data> + <data name="lblDomain.Size" type="System.Drawing.Size, System.Drawing"> + <value>42, 13</value> + </data> + <data name="lblDomain.Text" xml:space="preserve"> + <value>ドメイン</value> + </data> + <data name="lblPWD.Size" type="System.Drawing.Size, System.Drawing"> + <value>54, 13</value> + </data> + <data name="lblPWD.Text" xml:space="preserve"> + <value>パスワード</value> + </data> + <data name="lblUID.Size" type="System.Drawing.Size, System.Drawing"> + <value>48, 13</value> + </data> + <data name="lblUID.Text" xml:space="preserve"> + <value>ユーザID</value> + </data> + <data name="gbxWWW.Text" xml:space="preserve"> + <value>WWWサーバ</value> + </data> + <data name="lblProxyDomain.Size" type="System.Drawing.Size, System.Drawing"> + <value>42, 13</value> + </data> + <data name="lblProxyDomain.Text" xml:space="preserve"> + <value>ドメイン</value> + </data> + <data name="lblProxyPWD.Size" type="System.Drawing.Size, System.Drawing"> + <value>54, 13</value> + </data> + <data name="lblProxyPWD.Text" xml:space="preserve"> + <value>パスワード</value> + </data> + <data name="lblProxyUID.Size" type="System.Drawing.Size, System.Drawing"> + <value>48, 13</value> + </data> + <data name="lblProxyUID.Text" xml:space="preserve"> + <value>ユーザID</value> + </data> + <data name="gbxProxy.Text" xml:space="preserve"> + <value>Proxyサーバ</value> + </data> + <data name="tabPageDeployWithHTTP.Text" xml:space="preserve"> + <value>HTTPでデプロイ</value> + </data> + <data name="lblFolder.Size" type="System.Drawing.Size, System.Drawing"> + <value>42, 13</value> + </data> + <data name="lblFolder.Text" xml:space="preserve"> + <value>フォルダ</value> + </data> + <data name="lblFile.Size" type="System.Drawing.Size, System.Drawing"> + <value>53, 13</value> + </data> + <data name="lblFile.Text" xml:space="preserve"> + <value>ファイル名</value> + </data> + <data name="btnSelectFolder.Text" xml:space="preserve"> + <value>選択</value> + </data> + <data name="lblExt.Text" xml:space="preserve"> + <value>除外拡張子</value> + </data> + <data name="btnSelectSaveFile.Text" xml:space="preserve"> + <value>選択</value> + </data> + <data name="lblRootDirCheck.Size" type="System.Drawing.Size, System.Drawing"> + <value>404, 11</value> + </data> + <data name="lblRootDirCheck.Text" xml:space="preserve"> + <value>チェック有り:指定ZIPファイル名をルートZIP内フォルダに含めない(ルート フォルダからの圧縮)。</value> + </data> + <data name="cbxRootDir.Size" type="System.Drawing.Size, System.Drawing"> + <value>390, 15</value> + </data> + <data name="cbxRootDir.Text" xml:space="preserve"> + <value>チェック無し:指定ZIPファイル名をルートZIP内フォルダに含める(個別のフォルダ圧縮)。</value> + </data> + <data name="btnCompress.Text" xml:space="preserve"> + <value>圧縮</value> + </data> + <data name="lblFormat.Size" type="System.Drawing.Size, System.Drawing"> + <value>31, 13</value> + </data> + <data name="lblFormat.Text" xml:space="preserve"> + <value>形式</value> + </data> + <data name="lblCyp.Size" type="System.Drawing.Size, System.Drawing"> + <value>43, 13</value> + </data> + <data name="lblCyp.Text" xml:space="preserve"> + <value>暗号化</value> + </data> + <data name="lblCmpLv.Size" type="System.Drawing.Size, System.Drawing"> + <value>43, 13</value> + </data> + <data name="lblCmpLv.Text" xml:space="preserve"> + <value>圧縮Lv</value> + </data> + <data name="tabPageZip.Text" xml:space="preserve"> + <value>圧縮</value> + </data> + <data name="btnDecomp.Text" xml:space="preserve"> + <value>解凍</value> + </data> + <data name="lblEEFA.Size" type="System.Drawing.Size, System.Drawing"> + <value>64, 13</value> + </data> + <data name="lblEEFA.Text" xml:space="preserve"> + <value>上書き動作</value> + </data> + <data name="tabPageUnZip.Text" xml:space="preserve"> + <value>解凍(テスト)</value> + </data> + <data name="lblPass.Size" type="System.Drawing.Size, System.Drawing"> + <value>38, 13</value> + </data> + <data name="lblPass.Text" xml:space="preserve"> + <value>解パス</value> + </data> + <data name="tabPageZipPackage.Text" xml:space="preserve"> + <value>Zipパッケージを作成</value> + </data> + <data name="label3.Size" type="System.Drawing.Size, System.Drawing"> + <value>374, 13</value> + </data> + <data name="label3.Text" xml:space="preserve"> + <value>EXE名(パス)はカンマ区切りで指定可能で、先頭のEXEが起動の対象となる。</value> + </data> + <data name="label2.Size" type="System.Drawing.Size, System.Drawing"> + <value>383, 13</value> + </data> + <data name="label2.Text" xml:space="preserve"> + <value>起動するEXEのパスは、[インストール ディレクトリ] + [EXE名(パス)]で構成される。</value> + </data> + <data name="label1.Size" type="System.Drawing.Size, System.Drawing"> + <value>413, 13</value> + </data> + <data name="label1.Text" xml:space="preserve"> + <value>インストール ディレクトリには環境変数を指定可能:%USERPROFILE%\XXX\YYY\ZZZ</value> + </data> + <data name="lblInsDir.Size" type="System.Drawing.Size, System.Drawing"> + <value>114, 13</value> + </data> + <data name="lblInsDir.Text" xml:space="preserve"> + <value>インストール ディレクトリ</value> + </data> + <data name="lblExeName.Size" type="System.Drawing.Size, System.Drawing"> + <value>71, 13</value> + </data> + <data name="lblExeName.Text" xml:space="preserve"> + <value>EXE名(パス)</value> + </data> + <data name="btnCreateManifesto.Text" xml:space="preserve"> + <value>マニュフェストファイルを作成する</value> + </data> + <data name="btnRemoveZIPFile.Text" xml:space="preserve"> + <value>削除する</value> + </data> + <data name="btnAddZIPFile.Text" xml:space="preserve"> + <value>追加する</value> + </data> + <data name="tabPageManifesto.Text" xml:space="preserve"> + <value>配置マニュフェストを作成</value> + </data> + <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + AAABAAEAICAAAAEAGACoDAAAFgAAACgAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS1/TS1/QAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACirOg7T847T86irOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukySMwIIsEIIsEy + SMypsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACjreg6T84gOMcIIsEAG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEA + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukxR8sIIsEAG78AG78AG78AG78AG78AG78AG78AG78IIsEx + R8upsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjreg6T84g + OMcIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEAG78AG78AG78AG78AG78AG78AG78AG78A + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADL0fKy + uuwzScwIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEz + ScyyuuzL0fIAAAAAAAAAAAAAAAAAAAAAAAAAAADd4PZlddhIW9EwRssoP8koP8koP8kgOMcIIsEAG78A + G78AG78AG78AG78AG78AG78AG78IIsEgOMcoP8koP8koP8kwRstIW9FkddfU1+wAAAAAAAAAAAAAAAAA + AAD29/3u8PvS1/TGzPHCyPC/xu/Axu/ByPCxuesgOMcAG78AG78AG78AG78AG78AG78AG78AG78gOMex + uOa8wNq2utO2utO2utO2utO+wdXZ2t/f3+IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADDyvAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m8wNpkZGRKSkpKSkpKSkpKSkpKSkpeXl7B + wsMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFy+8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKCgoKCgoKCgoKCgoKCgvLy9ZWVnKysoAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAADc3NzY2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgoKCgo + KCgoKCgoKCgoKChDQ0O/v7/U1NQAAAAAAAAAAAAAAAAAAAAAAAAAAADg4OB+fn5/f3/Dx+EoP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgvLy9DQ0NKSkpKSkpKSkpQUFBkZGR9fX3j4+MA + AAAAAAAAAAAAAAAAAADy8vLv7+/f39/Y2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChDQ0O9vb3Ly8vKysrJycnLy8vPz8/Z2dnx8fH39/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADEyu4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrLy8sAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAxu8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrKysoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCyPAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADL0fJIW9EoP8koP8koP8koP8koP8koP8koP8koP8lIW9G+wdVKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADX2/XL0fLEyvDEyu7L0Oy8wNq2utO2 + utO2utO2utO+wdW7u8FDQ0MoKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT1NpkZGRKSkpKSkpKSkpKSkpKSkpDQ0MvLy8oKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADS0tJKSkooKCgoKCgoKCgoKCgoKCgoKCgoKCgoKChKSkrLy8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0tJkZGRKSkpKSkpKSkpKSkpKSkpK + SkpKSkpKSkpkZGTS0tIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADv7+/k5OTd3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3k5OTv7+8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD/+f////D////AP///gB///wAP//wAA//4AAH/8AAA/8AAAD+AAAAfAAAAD/8A + AA//AAAH/AAAA/gAAAHwAAAA/wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8A + AP//AAD///AA///wAP//8AD///AA/w== +</value> + </data> +</root> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.resx b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.resx new file mode 100644 index 000000000..1e7a71f84 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form1.resx @@ -0,0 +1,1922 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <data name="lblCmpLv.TabIndex" type="System.Int32, mscorlib"> + <value>11</value> + </data> + <data name=">>btnCreateManifesto.Type" xml:space="preserve"> + <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblStatus.Text" xml:space="preserve"> + <value>Status</value> + </data> + <data name=">>lblRootDirCheck.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>tabPageZip.Type" xml:space="preserve"> + <value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>txtUID.Parent" xml:space="preserve"> + <value>gbxWWW</value> + </data> + <data name=">>btnCheckUpdateAndInstall.Type" xml:space="preserve"> + <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>cbxRootDir.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name=">>txtDomain.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>btnSelectSaveFile.Type" xml:space="preserve"> + <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>btnAddZIPFile.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name="cbxFormat.TabIndex" type="System.Int32, mscorlib"> + <value>17</value> + </data> + <data name=">>txtProxyPWD.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>txtExeName.ZOrder" xml:space="preserve"> + <value>6</value> + </data> + <data name=">>lblPWD.Name" xml:space="preserve"> + <value>lblPWD</value> + </data> + <data name=">>lblProxyUID.Name" xml:space="preserve"> + <value>lblProxyUID</value> + </data> + <data name=">>label3.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> + <data name="txtExeName.Size" type="System.Drawing.Size, System.Drawing"> + <value>292, 20</value> + </data> + <data name="tabPageZip.Location" type="System.Drawing.Point, System.Drawing"> + <value>4, 22</value> + </data> + <data name=">>btnRemoveZIPFile.Name" xml:space="preserve"> + <value>btnRemoveZIPFile</value> + </data> + <data name="lbxZIPFiles.Location" type="System.Drawing.Point, System.Drawing"> + <value>15, 16</value> + </data> + <data name="tabPageZipPackage.Location" type="System.Drawing.Point, System.Drawing"> + <value>4, 22</value> + </data> + <data name=">>lblStatus.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name="lblUID.TabIndex" type="System.Int32, mscorlib"> + <value>2</value> + </data> + <data name="lblCyp.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>btnSelectSaveFile.Name" xml:space="preserve"> + <value>btnSelectSaveFile</value> + </data> + <data name="cmbHistorys.TabIndex" type="System.Int32, mscorlib"> + <value>18</value> + </data> + <data name="lblStatus.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name="lblDomain.TabIndex" type="System.Int32, mscorlib"> + <value>7</value> + </data> + <data name="txtPWD.Location" type="System.Drawing.Point, System.Drawing"> + <value>87, 72</value> + </data> + <data name="lblEnc.TabIndex" type="System.Int32, mscorlib"> + <value>6</value> + </data> + <data name=">>btnCompress.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name=">>lblRootDirCheck.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name=">>tabPageDeployWithHTTP.Type" xml:space="preserve"> + <value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>cbxRootDir.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name=">>txtProxyDomain.Parent" xml:space="preserve"> + <value>gbxProxy</value> + </data> + <data name="btnDecomp.Text" xml:space="preserve"> + <value>Thawing</value> + </data> + <data name="lblProxyPWD.Text" xml:space="preserve"> + <value>Password</value> + </data> + <data name=">>txtPass.Name" xml:space="preserve"> + <value>txtPass</value> + </data> + <data name=">>txtProxyPWD.ZOrder" xml:space="preserve"> + <value>4</value> + </data> + <data name="lblFile.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="lblHistorys.Size" type="System.Drawing.Size, System.Drawing"> + <value>70, 13</value> + </data> + <data name="txtProxyURL.Size" type="System.Drawing.Size, System.Drawing"> + <value>331, 20</value> + </data> + <data name="lblPass.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 122</value> + </data> + <data name=">>tabPageDeployWithHTTP.Name" xml:space="preserve"> + <value>tabPageDeployWithHTTP</value> + </data> + <data name="btnDecomp.Location" type="System.Drawing.Point, System.Drawing"> + <value>9, 133</value> + </data> + <data name="lblExt.Size" type="System.Drawing.Size, System.Drawing"> + <value>69, 27</value> + </data> + <data name=">>cmbEnc.ZOrder" xml:space="preserve"> + <value>11</value> + </data> + <data name=">>txtFile.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name="txtPass.Enabled" type="System.Boolean, mscorlib"> + <value>False</value> + </data> + <data name=">>cbxRootDir.Name" xml:space="preserve"> + <value>cbxRootDir</value> + </data> + <data name="lblExeName.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 230</value> + </data> + <data name="tabZipUnZip.Location" type="System.Drawing.Point, System.Drawing"> + <value>6, 148</value> + </data> + <data name="btnSelectFolder.Size" type="System.Drawing.Size, System.Drawing"> + <value>89, 25</value> + </data> + <data name=">>lblProxyPWD.Parent" xml:space="preserve"> + <value>gbxProxy</value> + </data> + <data name=">>cmbCmpLv.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name="lblInsDir.Text" xml:space="preserve"> + <value>Installation directory</value> + </data> + <data name=">>lblFolder.Name" xml:space="preserve"> + <value>lblFolder</value> + </data> + <data name="lblEEFA.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="lblDomain.Size" type="System.Drawing.Size, System.Drawing"> + <value>43, 13</value> + </data> + <data name="lblInsDir.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 207</value> + </data> + <data name="lblExeName.Size" type="System.Drawing.Size, System.Drawing"> + <value>87, 13</value> + </data> + <data name=">>lblProxyURL.ZOrder" xml:space="preserve"> + <value>5</value> + </data> + <data name="label3.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 291</value> + </data> + <data name="cmbEEFA.Location" type="System.Drawing.Point, System.Drawing"> + <value>106, 13</value> + </data> + <data name=">>lblExt.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>btnCompress.Type" xml:space="preserve"> + <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblEEFA.Location" type="System.Drawing.Point, System.Drawing"> + <value>4, 16</value> + </data> + <data name=">>lblProxyURL.Parent" xml:space="preserve"> + <value>gbxProxy</value> + </data> + <data name="tabZipUnZip.Size" type="System.Drawing.Size, System.Drawing"> + <value>430, 193</value> + </data> + <data name=">>txtProxyUID.Name" xml:space="preserve"> + <value>txtProxyUID</value> + </data> + <data name=">>lblProxyPWD.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>tabPageZipPackage.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name=">>lblCyp.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>cmbHistorys.Type" xml:space="preserve"> + <value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="gbxProxy.TabIndex" type="System.Int32, mscorlib"> + <value>6</value> + </data> + <data name="lblExt.Text" xml:space="preserve"> + <value>Exclusion extension</value> + </data> + <data name=">>lblCyp.ZOrder" xml:space="preserve"> + <value>7</value> + </data> + <data name="btnSelectSaveFile.Location" type="System.Drawing.Point, System.Drawing"> + <value>332, 35</value> + </data> + <data name="label2.TabIndex" type="System.Int32, mscorlib"> + <value>10</value> + </data> + <data name="lblRootDirCheck.Font" type="System.Drawing.Font, System.Drawing"> + <value>MS UI Gothic, 8.25pt</value> + </data> + <data name=">>txtProxyUID.ZOrder" xml:space="preserve"> + <value>6</value> + </data> + <data name="btnAddZIPFile.Size" type="System.Drawing.Size, System.Drawing"> + <value>415, 25</value> + </data> + <data name="cmbHistorys.Location" type="System.Drawing.Point, System.Drawing"> + <value>93, 10</value> + </data> + <data name="lblProxyUID.Text" xml:space="preserve"> + <value>User ID</value> + </data> + <data name=">>txtFile.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblStatus.Location" type="System.Drawing.Point, System.Drawing"> + <value>5, 404</value> + </data> + <data name="lblProxyPWD.Location" type="System.Drawing.Point, System.Drawing"> + <value>18, 77</value> + </data> + <data name="lblExt.TabIndex" type="System.Int32, mscorlib"> + <value>18</value> + </data> + <data name="$this.Text" xml:space="preserve"> + <value>DeployZipPackWithHTTP</value> + </data> + <data name="btnSelectFolder.TabIndex" type="System.Int32, mscorlib"> + <value>1</value> + </data> + <data name="txtDomain.PasswordChar" type="System.Char, mscorlib" xml:space="preserve"> + <value>*</value> + </data> + <data name="tabPageUnZip.Location" type="System.Drawing.Point, System.Drawing"> + <value>4, 22</value> + </data> + <data name=">>lblStatus.Parent" xml:space="preserve"> + <value>$this</value> + </data> + <data name="tabPageZip.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name=">>cmbEnc.Name" xml:space="preserve"> + <value>cmbEnc</value> + </data> + <data name=">>lblProxyDomain.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name=">>lblProxyDomain.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtProxyDomain.TabIndex" type="System.Int32, mscorlib"> + <value>8</value> + </data> + <data name=">>txtExt.Name" xml:space="preserve"> + <value>txtExt</value> + </data> + <data name="lblPWD.TabIndex" type="System.Int32, mscorlib"> + <value>5</value> + </data> + <data name="lblUID.Size" type="System.Drawing.Size, System.Drawing"> + <value>43, 13</value> + </data> + <data name="txtProxyDomain.Location" type="System.Drawing.Point, System.Drawing"> + <value>87, 101</value> + </data> + <data name="lblHistorys.TabIndex" type="System.Int32, mscorlib"> + <value>9</value> + </data> + <data name=">>lblURL.ZOrder" xml:space="preserve"> + <value>3</value> + </data> + <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <data name="tabPageUnZip.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms"> + <value>3, 3, 3, 3</value> + </data> + <data name=">>saveFileDialog1.Name" xml:space="preserve"> + <value>saveFileDialog1</value> + </data> + <data name=">>btnDelHistory.Parent" xml:space="preserve"> + <value>tabPageDeployWithHTTP</value> + </data> + <data name=">>cmbEEFA.Parent" xml:space="preserve"> + <value>tabPageUnZip</value> + </data> + <data name="btnCheckUpdateAndInstall.Size" type="System.Drawing.Size, System.Drawing"> + <value>424, 25</value> + </data> + <data name="cbxFormat.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>txtInsDir.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtPWD.PasswordChar" type="System.Char, mscorlib" xml:space="preserve"> + <value>*</value> + </data> + <data name=">>cbxFormat.Type" xml:space="preserve"> + <value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtDomain.Size" type="System.Drawing.Size, System.Drawing"> + <value>331, 20</value> + </data> + <data name="lblRootDirCheck.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>lblPWD.Parent" xml:space="preserve"> + <value>gbxWWW</value> + </data> + <data name=">>tabDeployZipPac.Name" xml:space="preserve"> + <value>tabDeployZipPac</value> + </data> + <data name="txtExt.Location" type="System.Drawing.Point, System.Drawing"> + <value>94, 64</value> + </data> + <data name="btnCheckUpdateAndInstall.Location" type="System.Drawing.Point, System.Drawing"> + <value>6, 321</value> + </data> + <data name="lblExt.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 67</value> + </data> + <data name=">>btnAddZIPFile.ZOrder" xml:space="preserve"> + <value>9</value> + </data> + <data name="lblProxyPWD.TabIndex" type="System.Int32, mscorlib"> + <value>12</value> + </data> + <data name=">>txtPass.ZOrder" xml:space="preserve"> + <value>3</value> + </data> + <data name="btnAddZIPFile.Location" type="System.Drawing.Point, System.Drawing"> + <value>15, 142</value> + </data> + <data name=">>gbxWWW.Type" xml:space="preserve"> + <value>System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="btnSelectSaveFile.Text" xml:space="preserve"> + <value>Selection</value> + </data> + <data name=">>tabZipUnZip.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name="lblURL.Size" type="System.Drawing.Size, System.Drawing"> + <value>29, 13</value> + </data> + <data name=">>gbxWWW.Parent" xml:space="preserve"> + <value>tabPageDeployWithHTTP</value> + </data> + <data name="cbxRootDir.Size" type="System.Drawing.Size, System.Drawing"> + <value>540, 15</value> + </data> + <data name="lblHistorys.Text" xml:space="preserve"> + <value>Load settings</value> + </data> + <data name=">>txtProxyURL.Parent" xml:space="preserve"> + <value>gbxProxy</value> + </data> + <data name=">>label2.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name="cmbFormat.Size" type="System.Drawing.Size, System.Drawing"> + <value>337, 21</value> + </data> + <data name="lblEEFA.TabIndex" type="System.Int32, mscorlib"> + <value>5</value> + </data> + <data name=">>lblFile.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name="tabPageZip.Text" xml:space="preserve"> + <value>Compression</value> + </data> + <data name=">>txtUID.Name" xml:space="preserve"> + <value>txtUID</value> + </data> + <data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing"> + <value>6, 13</value> + </data> + <data name="tabPageDeployWithHTTP.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name=">>tabPageUnZip.Type" xml:space="preserve"> + <value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="cmbHistorys.Size" type="System.Drawing.Size, System.Drawing"> + <value>245, 21</value> + </data> + <data name=">>cbxExt.Type" xml:space="preserve"> + <value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>openFilesDialog1.Name" xml:space="preserve"> + <value>openFilesDialog1</value> + </data> + <data name=">>btnDelHistory.Type" xml:space="preserve"> + <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblURL.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="tabPageDeployWithHTTP.Text" xml:space="preserve"> + <value>Deployed in HTTP</value> + </data> + <data name="openFilesDialog1.Filter" xml:space="preserve"> + <value>ZIP file |. * Zip</value> + </data> + <data name="txtProxyPWD.PasswordChar" type="System.Char, mscorlib" xml:space="preserve"> + <value>*</value> + </data> + <data name="btnCreateManifesto.Text" xml:space="preserve"> + <value>I want to create a manifest file</value> + </data> + <data name="lblProxyPWD.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>lblPass.Name" xml:space="preserve"> + <value>lblPass</value> + </data> + <data name=">>txtInsDir.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name=">>lblUID.Name" xml:space="preserve"> + <value>lblUID</value> + </data> + <data name=">>lblFolder.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>cbxExt.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name="lblProxyDomain.Size" type="System.Drawing.Size, System.Drawing"> + <value>43, 13</value> + </data> + <data name=">>lblDomain.ZOrder" xml:space="preserve"> + <value>2</value> + </data> + <data name="txtUID.TabIndex" type="System.Int32, mscorlib"> + <value>3</value> + </data> + <data name="label2.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 277</value> + </data> + <data name="lblProxyPWD.Size" type="System.Drawing.Size, System.Drawing"> + <value>53, 13</value> + </data> + <data name=">>lblFile.ZOrder" xml:space="preserve"> + <value>2</value> + </data> + <data name=">>lblURL.Parent" xml:space="preserve"> + <value>gbxWWW</value> + </data> + <data name=">>openFileDialog1.Type" xml:space="preserve"> + <value>System.Windows.Forms.OpenFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblExeName.Text" xml:space="preserve"> + <value>EXE name (path)</value> + </data> + <data name="lblCmpLv.Text" xml:space="preserve"> + <value>Compression Lv</value> + </data> + <data name="lblCyp.Location" type="System.Drawing.Point, System.Drawing"> + <value>2, 10</value> + </data> + <data name=">>$this.Type" xml:space="preserve"> + <value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="cbxFormat.Location" type="System.Drawing.Point, System.Drawing"> + <value>396, 66</value> + </data> + <data name=">>lblFile.Name" xml:space="preserve"> + <value>lblFile</value> + </data> + <data name="lblInsDir.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="tabPageZip.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms"> + <value>3, 3, 3, 3</value> + </data> + <data name="lblFormat.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="lblUID.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 48</value> + </data> + <data name="gbxWWW.Location" type="System.Drawing.Point, System.Drawing"> + <value>6, 35</value> + </data> + <data name=">>tabDeployZipPac.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name="lblPWD.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 75</value> + </data> + <data name=">>lblHistorys.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name=">>txtPWD.ZOrder" xml:space="preserve"> + <value>4</value> + </data> + <data name="lblFormat.Location" type="System.Drawing.Point, System.Drawing"> + <value>2, 66</value> + </data> + <data name=">>cmbEEFA.ZOrder" xml:space="preserve"> + <value>2</value> + </data> + <data name="txtFolder.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name=">>txtUID.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblFile.Text" xml:space="preserve"> + <value>File name</value> + </data> + <data name=">>txtURL.Parent" xml:space="preserve"> + <value>gbxWWW</value> + </data> + <data name="cmbCyp.Enabled" type="System.Boolean, mscorlib"> + <value>False</value> + </data> + <data name="lblFile.TabIndex" type="System.Int32, mscorlib"> + <value>4</value> + </data> + <data name="lblEnc.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 94</value> + </data> + <data name=">>lblInsDir.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name="txtUID.Size" type="System.Drawing.Size, System.Drawing"> + <value>331, 20</value> + </data> + <data name="gbxWWW.TabIndex" type="System.Int32, mscorlib"> + <value>7</value> + </data> + <data name="txtURL.TabIndex" type="System.Int32, mscorlib"> + <value>8</value> + </data> + <data name="tabZipUnZip.TabIndex" type="System.Int32, mscorlib"> + <value>21</value> + </data> + <data name=">>lblStatus.Name" xml:space="preserve"> + <value>lblStatus</value> + </data> + <data name="txtProxyDomain.PasswordChar" type="System.Char, mscorlib" xml:space="preserve"> + <value>*</value> + </data> + <data name=">>lblEnc.ZOrder" xml:space="preserve"> + <value>4</value> + </data> + <data name="txtProxyURL.TabIndex" type="System.Int32, mscorlib"> + <value>8</value> + </data> + <data name=">>btnCompress.ZOrder" xml:space="preserve"> + <value>3</value> + </data> + <data name=">>cmbFormat.Type" xml:space="preserve"> + <value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>lblHistorys.Name" xml:space="preserve"> + <value>lblHistorys</value> + </data> + <data name="cmbCmpLv.TabIndex" type="System.Int32, mscorlib"> + <value>12</value> + </data> + <data name=">>lblDomain.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>folderBrowserDialog1.Type" xml:space="preserve"> + <value>System.Windows.Forms.FolderBrowserDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="btnDelHistory.Size" type="System.Drawing.Size, System.Drawing"> + <value>86, 25</value> + </data> + <data name="cbxRootDir.Text" xml:space="preserve"> + <value>(Folder compression of individual) to be included in the root folder in the ZIP specified ZIP file name: unchecked.</value> + </data> + <data name="cmbEnc.Items2" xml:space="preserve"> + <value>euc-jp</value> + </data> + <data name="lblEnc.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="lblCmpLv.Size" type="System.Drawing.Size, System.Drawing"> + <value>58, 28</value> + </data> + <data name=">>tabPageManifesto.ZOrder" xml:space="preserve"> + <value>2</value> + </data> + <data name="btnCompress.TabIndex" type="System.Int32, mscorlib"> + <value>5</value> + </data> + <data name="tabPageZip.Size" type="System.Drawing.Size, System.Drawing"> + <value>422, 167</value> + </data> + <data name=">>gbxProxy.Type" xml:space="preserve"> + <value>System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblProxyUID.Size" type="System.Drawing.Size, System.Drawing"> + <value>43, 13</value> + </data> + <data name="tabPageDeployWithHTTP.Size" type="System.Drawing.Size, System.Drawing"> + <value>442, 353</value> + </data> + <data name=">>lblFile.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>cbxExt.Name" xml:space="preserve"> + <value>cbxExt</value> + </data> + <data name=">>cmbHistorys.ZOrder" xml:space="preserve"> + <value>2</value> + </data> + <data name=">>panel1.Name" xml:space="preserve"> + <value>panel1</value> + </data> + <data name=">>lblFolder.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name="label3.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms"> + <value>NoControl</value> + </data> + <data name="lblProxyUID.Location" type="System.Drawing.Point, System.Drawing"> + <value>18, 50</value> + </data> + <data name="lblInsDir.Size" type="System.Drawing.Size, System.Drawing"> + <value>100, 13</value> + </data> + <data name=">>txtInsDir.Name" xml:space="preserve"> + <value>txtInsDir</value> + </data> + <data name=">>lblEEFA.Name" xml:space="preserve"> + <value>lblEEFA</value> + </data> + <data name=">>gbxProxy.ZOrder" xml:space="preserve"> + <value>5</value> + </data> + <data name=">>btnDecomp.Type" xml:space="preserve"> + <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>lblExt.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name=">>btnSelectFolder.Name" xml:space="preserve"> + <value>btnSelectFolder</value> + </data> + <data name="lblFormat.TabIndex" type="System.Int32, mscorlib"> + <value>13</value> + </data> + <data name="lblRootDirCheck.Location" type="System.Drawing.Point, System.Drawing"> + <value>25, 114</value> + </data> + <data name=">>label1.ZOrder" xml:space="preserve"> + <value>2</value> + </data> + <data name=">>lblProxyUID.Parent" xml:space="preserve"> + <value>gbxProxy</value> + </data> + <data name="txtInsDir.TabIndex" type="System.Int32, mscorlib"> + <value>7</value> + </data> + <data name="lblPass.Size" type="System.Drawing.Size, System.Drawing"> + <value>69, 13</value> + </data> + <data name=">>btnSelectFolder.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name=">>cmbHistorys.Name" xml:space="preserve"> + <value>cmbHistorys</value> + </data> + <data name="txtPWD.Size" type="System.Drawing.Size, System.Drawing"> + <value>331, 20</value> + </data> + <data name=">>txtFile.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name="cbxRootDir.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="lblUID.Text" xml:space="preserve"> + <value>User ID</value> + </data> + <data name="lblHistorys.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>lblUID.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="tabPageManifesto.Text" xml:space="preserve"> + <value>To create a deployment manifest</value> + </data> + <data name="lblEnc.Size" type="System.Drawing.Size, System.Drawing"> + <value>44, 13</value> + </data> + <data name="btnSelectFolder.Text" xml:space="preserve"> + <value>Selection</value> + </data> + <data name=">>tabPageUnZip.Parent" xml:space="preserve"> + <value>tabZipUnZip</value> + </data> + <data name=">>btnAddZIPFile.Type" xml:space="preserve"> + <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>lblFolder.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name=">>lblCmpLv.ZOrder" xml:space="preserve"> + <value>8</value> + </data> + <data name=">>cmbFormat.Name" xml:space="preserve"> + <value>cmbFormat</value> + </data> + <data name="txtProxyPWD.Location" type="System.Drawing.Point, System.Drawing"> + <value>87, 74</value> + </data> + <data name="label1.Text" xml:space="preserve"> + <value>% USERPROFILE% \ XXX \ YYY \ ZZZ: you can specify the environment variable to the installation directory</value> + </data> + <data name=">>tabPageManifesto.Name" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name="txtProxyPWD.Size" type="System.Drawing.Size, System.Drawing"> + <value>331, 20</value> + </data> + <data name=">>txtPass.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>btnDelHistory.Name" xml:space="preserve"> + <value>btnDelHistory</value> + </data> + <data name=">>txtPWD.Parent" xml:space="preserve"> + <value>gbxWWW</value> + </data> + <data name="lblEEFA.Text" xml:space="preserve"> + <value>Overwrite operation</value> + </data> + <data name="cbxFormat.Enabled" type="System.Boolean, mscorlib"> + <value>False</value> + </data> + <data name="lblPWD.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="lblFile.Size" type="System.Drawing.Size, System.Drawing"> + <value>52, 13</value> + </data> + <data name="lblFormat.Text" xml:space="preserve"> + <value>Format</value> + </data> + <data name=">>txtURL.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name=">>txtProxyDomain.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblUID.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>lblPWD.ZOrder" xml:space="preserve"> + <value>5</value> + </data> + <data name="gbxWWW.Text" xml:space="preserve"> + <value>WWW server</value> + </data> + <data name=">>txtDomain.Name" xml:space="preserve"> + <value>txtDomain</value> + </data> + <data name=">>txtFolder.ZOrder" xml:space="preserve"> + <value>13</value> + </data> + <data name=">>lblEnc.Name" xml:space="preserve"> + <value>lblEnc</value> + </data> + <data name=">>btnCompress.Name" xml:space="preserve"> + <value>btnCompress</value> + </data> + <data name="btnRemoveZIPFile.Location" type="System.Drawing.Point, System.Drawing"> + <value>15, 171</value> + </data> + <data name="txtDomain.Location" type="System.Drawing.Point, System.Drawing"> + <value>87, 99</value> + </data> + <data name=">>saveFileDialog1.Type" xml:space="preserve"> + <value>System.Windows.Forms.SaveFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblExeName.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>btnRemoveZIPFile.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name=">>lblCmpLv.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name=">>lblProxyPWD.Name" xml:space="preserve"> + <value>lblProxyPWD</value> + </data> + <data name=">>lbxZIPFiles.Type" xml:space="preserve"> + <value>System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>label2.Name" xml:space="preserve"> + <value>label2</value> + </data> + <data name="lblDomain.Text" xml:space="preserve"> + <value>Domain</value> + </data> + <data name="lblFormat.Size" type="System.Drawing.Size, System.Drawing"> + <value>39, 13</value> + </data> + <data name=">>cmbCyp.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name="lblProxyDomain.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="lblProxyDomain.Text" xml:space="preserve"> + <value>Domain</value> + </data> + <data name="lblProxyURL.Size" type="System.Drawing.Size, System.Drawing"> + <value>29, 13</value> + </data> + <data name="cmbEEFA.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name=">>lblEEFA.Parent" xml:space="preserve"> + <value>tabPageUnZip</value> + </data> + <data name="lblProxyDomain.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 104</value> + </data> + <data name=">>txtFolder.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtExt.TabIndex" type="System.Int32, mscorlib"> + <value>19</value> + </data> + <data name="tabPageManifesto.Location" type="System.Drawing.Point, System.Drawing"> + <value>4, 22</value> + </data> + <data name=">>lblFormat.Name" xml:space="preserve"> + <value>lblFormat</value> + </data> + <data name="lblFile.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 40</value> + </data> + <data name=">>txtFolder.Name" xml:space="preserve"> + <value>txtFolder</value> + </data> + <data name=">>lblCyp.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name=">>txtProxyUID.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="btnDelHistory.TabIndex" type="System.Int32, mscorlib"> + <value>19</value> + </data> + <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + AAABAAEAICAAAAEAGACoDAAAFgAAACgAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS1/TS1/QAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACirOg7T847T86irOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukySMwIIsEIIsEy + SMypsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACjreg6T84gOMcIIsEAG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEA + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukxR8sIIsEAG78AG78AG78AG78AG78AG78AG78AG78IIsEx + R8upsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjreg6T84g + OMcIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEAG78AG78AG78AG78AG78AG78AG78AG78A + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADL0fKy + uuwzScwIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEz + ScyyuuzL0fIAAAAAAAAAAAAAAAAAAAAAAAAAAADd4PZlddhIW9EwRssoP8koP8koP8kgOMcIIsEAG78A + G78AG78AG78AG78AG78AG78AG78IIsEgOMcoP8koP8koP8kwRstIW9FkddfU1+wAAAAAAAAAAAAAAAAA + AAD29/3u8PvS1/TGzPHCyPC/xu/Axu/ByPCxuesgOMcAG78AG78AG78AG78AG78AG78AG78AG78gOMex + uOa8wNq2utO2utO2utO2utO+wdXZ2t/f3+IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADDyvAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m8wNpkZGRKSkpKSkpKSkpKSkpKSkpeXl7B + wsMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFy+8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKCgoKCgoKCgoKCgoKCgvLy9ZWVnKysoAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAADc3NzY2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgoKCgo + KCgoKCgoKCgoKChDQ0O/v7/U1NQAAAAAAAAAAAAAAAAAAAAAAAAAAADg4OB+fn5/f3/Dx+EoP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgvLy9DQ0NKSkpKSkpKSkpQUFBkZGR9fX3j4+MA + AAAAAAAAAAAAAAAAAADy8vLv7+/f39/Y2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChDQ0O9vb3Ly8vKysrJycnLy8vPz8/Z2dnx8fH39/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADEyu4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrLy8sAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAxu8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrKysoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCyPAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADL0fJIW9EoP8koP8koP8koP8koP8koP8koP8koP8lIW9G+wdVKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADX2/XL0fLEyvDEyu7L0Oy8wNq2utO2 + utO2utO2utO+wdW7u8FDQ0MoKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT1NpkZGRKSkpKSkpKSkpKSkpKSkpDQ0MvLy8oKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADS0tJKSkooKCgoKCgoKCgoKCgoKCgoKCgoKCgoKChKSkrLy8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0tJkZGRKSkpKSkpKSkpKSkpKSkpK + SkpKSkpKSkpkZGTS0tIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADv7+/k5OTd3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3k5OTv7+8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD/+f////D////AP///gB///wAP//wAA//4AAH/8AAA/8AAAD+AAAAfAAAAD/8A + AA//AAAH/AAAA/gAAAHwAAAA/wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8A + AP//AAD///AA///wAP//8AD///AA/w== +</value> + </data> + <data name=">>txtPWD.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="tabPageDeployWithHTTP.Location" type="System.Drawing.Point, System.Drawing"> + <value>4, 22</value> + </data> + <data name=">>cmbHistorys.Parent" xml:space="preserve"> + <value>tabPageDeployWithHTTP</value> + </data> + <data name=">>tabPageManifesto.Parent" xml:space="preserve"> + <value>tabDeployZipPac</value> + </data> + <data name="cbxFormat.Size" type="System.Drawing.Size, System.Drawing"> + <value>15, 14</value> + </data> + <data name="lblProxyURL.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="lblProxyUID.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>lbxZIPFiles.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name=">>lblFormat.ZOrder" xml:space="preserve"> + <value>5</value> + </data> + <data name="btnCreateManifesto.TabIndex" type="System.Int32, mscorlib"> + <value>4</value> + </data> + <data name="lblPass.Text" xml:space="preserve"> + <value>Solution path</value> + </data> + <data name=">>openFilesDialog1.Type" xml:space="preserve"> + <value>System.Windows.Forms.OpenFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtExt.Size" type="System.Drawing.Size, System.Drawing"> + <value>306, 20</value> + </data> + <data name=">>lblExeName.Name" xml:space="preserve"> + <value>lblExeName</value> + </data> + <data name="lblDomain.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 102</value> + </data> + <data name="label3.TabIndex" type="System.Int32, mscorlib"> + <value>11</value> + </data> + <data name="lblFolder.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>lblRootDirCheck.Name" xml:space="preserve"> + <value>lblRootDirCheck</value> + </data> + <data name="lblCyp.Text" xml:space="preserve"> + <value>Encryption</value> + </data> + <data name="txtPass.Location" type="System.Drawing.Point, System.Drawing"> + <value>94, 119</value> + </data> + <data name="btnDecomp.TabIndex" type="System.Int32, mscorlib"> + <value>6</value> + </data> + <data name="cmbEnc.TabIndex" type="System.Int32, mscorlib"> + <value>8</value> + </data> + <data name=">>lblProxyURL.Name" xml:space="preserve"> + <value>lblProxyURL</value> + </data> + <data name=">>lblPass.ZOrder" xml:space="preserve"> + <value>12</value> + </data> + <data name=">>lblEnc.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>tabZipUnZip.Type" xml:space="preserve"> + <value>System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtFolder.Location" type="System.Drawing.Point, System.Drawing"> + <value>94, 10</value> + </data> + <data name=">>btnRemoveZIPFile.ZOrder" xml:space="preserve"> + <value>8</value> + </data> + <data name="gbxProxy.Location" type="System.Drawing.Point, System.Drawing"> + <value>6, 174</value> + </data> + <data name=">>tabPageZipPackage.Name" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name=">>btnSelectSaveFile.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name=">>lblPass.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name=">>lblExt.Name" xml:space="preserve"> + <value>lblExt</value> + </data> + <data name=">>btnCheckUpdateAndInstall.ZOrder" xml:space="preserve"> + <value>3</value> + </data> + <data name="lblFolder.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 13</value> + </data> + <data name="btnRemoveZIPFile.TabIndex" type="System.Int32, mscorlib"> + <value>3</value> + </data> + <data name=">>cmbEEFA.Type" xml:space="preserve"> + <value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtProxyUID.Location" type="System.Drawing.Point, System.Drawing"> + <value>87, 47</value> + </data> + <data name=">>tabPageZip.Name" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name="lblProxyURL.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 23</value> + </data> + <data name=">>label1.Name" xml:space="preserve"> + <value>label1</value> + </data> + <data name=">>tabPageUnZip.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name="label2.Text" xml:space="preserve"> + <value>The path of the EXE to start is made in the installation directory] + [(path) EXE name.</value> + </data> + <data name="tabDeployZipPac.Size" type="System.Drawing.Size, System.Drawing"> + <value>450, 379</value> + </data> + <data name="btnAddZIPFile.TabIndex" type="System.Int32, mscorlib"> + <value>2</value> + </data> + <data name="btnCompress.Location" type="System.Drawing.Point, System.Drawing"> + <value>9, 133</value> + </data> + <data name="cmbFormat.Location" type="System.Drawing.Point, System.Drawing"> + <value>53, 63</value> + </data> + <data name="txtExeName.Location" type="System.Drawing.Point, System.Drawing"> + <value>138, 226</value> + </data> + <data name="cbxExt.TabIndex" type="System.Int32, mscorlib"> + <value>20</value> + </data> + <data name="txtDomain.TabIndex" type="System.Int32, mscorlib"> + <value>6</value> + </data> + <data name="cbxRootDir.TabIndex" type="System.Int32, mscorlib"> + <value>18</value> + </data> + <data name="lblInsDir.TabIndex" type="System.Int32, mscorlib"> + <value>8</value> + </data> + <data name="panel1.Size" type="System.Drawing.Size, System.Drawing"> + <value>462, 392</value> + </data> + <data name="lblEEFA.Size" type="System.Drawing.Size, System.Drawing"> + <value>99, 13</value> + </data> + <data name=">>tabPageZipPackage.Type" xml:space="preserve"> + <value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="btnSelectSaveFile.Size" type="System.Drawing.Size, System.Drawing"> + <value>89, 25</value> + </data> + <data name="txtPass.PasswordChar" type="System.Char, mscorlib" xml:space="preserve"> + <value>*</value> + </data> + <data name=">>lblCmpLv.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="cbxExt.Location" type="System.Drawing.Point, System.Drawing"> + <value>406, 67</value> + </data> + <data name="txtProxyPWD.TabIndex" type="System.Int32, mscorlib"> + <value>11</value> + </data> + <data name="lblRootDirCheck.TabIndex" type="System.Int32, mscorlib"> + <value>19</value> + </data> + <data name="label1.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 249</value> + </data> + <data name=">>lblInsDir.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>btnAddZIPFile.Name" xml:space="preserve"> + <value>btnAddZIPFile</value> + </data> + <data name=">>btnCreateManifesto.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name="cmbEnc.Items1" xml:space="preserve"> + <value>shift_jis</value> + </data> + <data name="gbxWWW.Size" type="System.Drawing.Size, System.Drawing"> + <value>424, 133</value> + </data> + <data name="label1.Size" type="System.Drawing.Size, System.Drawing"> + <value>420, 28</value> + </data> + <data name=">>label2.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="btnAddZIPFile.Text" xml:space="preserve"> + <value>Add</value> + </data> + <data name="lblFolder.Text" xml:space="preserve"> + <value>Folder</value> + </data> + <data name="cmbEEFA.Size" type="System.Drawing.Size, System.Drawing"> + <value>312, 21</value> + </data> + <data name="lbxZIPFiles.ScrollAlwaysVisible" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="lblStatus.Size" type="System.Drawing.Size, System.Drawing"> + <value>450, 16</value> + </data> + <data name=">>lblExeName.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name=">>lblRootDirCheck.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name=">>btnSelectFolder.Type" xml:space="preserve"> + <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>txtProxyUID.Parent" xml:space="preserve"> + <value>gbxProxy</value> + </data> + <data name="lblCyp.TabIndex" type="System.Int32, mscorlib"> + <value>9</value> + </data> + <data name=">>cmbCmpLv.Name" xml:space="preserve"> + <value>cmbCmpLv</value> + </data> + <data name=">>tabPageManifesto.Type" xml:space="preserve"> + <value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>txtDomain.Parent" xml:space="preserve"> + <value>gbxWWW</value> + </data> + <data name="txtProxyDomain.Size" type="System.Drawing.Size, System.Drawing"> + <value>331, 20</value> + </data> + <data name=">>label2.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name="lblCyp.Size" type="System.Drawing.Size, System.Drawing"> + <value>57, 13</value> + </data> + <data name=">>lblInsDir.ZOrder" xml:space="preserve"> + <value>3</value> + </data> + <data name=">>cmbCmpLv.Type" xml:space="preserve"> + <value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="tabPageZipPackage.Text" xml:space="preserve"> + <value>Create a Zip package</value> + </data> + <data name=">>lblProxyDomain.Name" xml:space="preserve"> + <value>lblProxyDomain</value> + </data> + <data name="txtFile.Size" type="System.Drawing.Size, System.Drawing"> + <value>232, 20</value> + </data> + <data name=">>txtFolder.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name=">>txtURL.Name" xml:space="preserve"> + <value>txtURL</value> + </data> + <data name="lblDomain.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="txtFile.TabIndex" type="System.Int32, mscorlib"> + <value>2</value> + </data> + <data name="tabDeployZipPac.TabIndex" type="System.Int32, mscorlib"> + <value>23</value> + </data> + <data name="txtPass.Size" type="System.Drawing.Size, System.Drawing"> + <value>327, 20</value> + </data> + <data name=">>gbxWWW.Name" xml:space="preserve"> + <value>gbxWWW</value> + </data> + <data name=">>txtInsDir.ZOrder" xml:space="preserve"> + <value>4</value> + </data> + <data name="btnCompress.Size" type="System.Drawing.Size, System.Drawing"> + <value>402, 25</value> + </data> + <data name=">>tabPageZip.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name="panel1.TabIndex" type="System.Int32, mscorlib"> + <value>23</value> + </data> + <data name="lblFolder.TabIndex" type="System.Int32, mscorlib"> + <value>3</value> + </data> + <data name="lblURL.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name=">>txtExeName.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="cmbCyp.TabIndex" type="System.Int32, mscorlib"> + <value>10</value> + </data> + <data name=">>lbxZIPFiles.ZOrder" xml:space="preserve"> + <value>10</value> + </data> + <data name="lblURL.Location" type="System.Drawing.Point, System.Drawing"> + <value>19, 21</value> + </data> + <data name="txtInsDir.Location" type="System.Drawing.Point, System.Drawing"> + <value>138, 204</value> + </data> + <data name="txtFile.Location" type="System.Drawing.Point, System.Drawing"> + <value>94, 37</value> + </data> + <data name="btnDelHistory.Text" xml:space="preserve"> + <value>Delete</value> + </data> + <data name=">>btnSelectFolder.ZOrder" xml:space="preserve"> + <value>5</value> + </data> + <data name="tabDeployZipPac.Location" type="System.Drawing.Point, System.Drawing"> + <value>6, 7</value> + </data> + <data name="btnDecomp.Size" type="System.Drawing.Size, System.Drawing"> + <value>380, 25</value> + </data> + <data name=">>tabZipUnZip.ZOrder" xml:space="preserve"> + <value>10</value> + </data> + <data name=">>lblHistorys.Parent" xml:space="preserve"> + <value>tabPageDeployWithHTTP</value> + </data> + <data name="btnRemoveZIPFile.Text" xml:space="preserve"> + <value>Remove</value> + </data> + <data name="label2.Size" type="System.Drawing.Size, System.Drawing"> + <value>403, 13</value> + </data> + <data name="lblPass.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="cbxExt.Size" type="System.Drawing.Size, System.Drawing"> + <value>15, 14</value> + </data> + <data name="cmbEnc.Enabled" type="System.Boolean, mscorlib"> + <value>False</value> + </data> + <data name="cmbEnc.Size" type="System.Drawing.Size, System.Drawing"> + <value>327, 21</value> + </data> + <data name="lblRootDirCheck.Size" type="System.Drawing.Size, System.Drawing"> + <value>600, 11</value> + </data> + <data name="lblProxyURL.Text" xml:space="preserve"> + <value>URL</value> + </data> + <data name="btnCheckUpdateAndInstall.Text" xml:space="preserve"> + <value>Install it check for updates</value> + </data> + <data name=">>lblProxyPWD.ZOrder" xml:space="preserve"> + <value>2</value> + </data> + <data name=">>lblStatus.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtPWD.TabIndex" type="System.Int32, mscorlib"> + <value>4</value> + </data> + <data name=">>cmbEnc.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name="cmbCyp.Size" type="System.Drawing.Size, System.Drawing"> + <value>358, 21</value> + </data> + <data name="lblHistorys.Location" type="System.Drawing.Point, System.Drawing"> + <value>24, 13</value> + </data> + <data name=">>txtProxyURL.ZOrder" xml:space="preserve"> + <value>3</value> + </data> + <data name=">>lblURL.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtURL.Location" type="System.Drawing.Point, System.Drawing"> + <value>87, 17</value> + </data> + <data name="btnRemoveZIPFile.Size" type="System.Drawing.Size, System.Drawing"> + <value>415, 25</value> + </data> + <data name="cmbEnc.Items" xml:space="preserve"> + <value>utf-8</value> + </data> + <data name="lblProxyURL.TabIndex" type="System.Int32, mscorlib"> + <value>7</value> + </data> + <data name=">>tabDeployZipPac.Parent" xml:space="preserve"> + <value>panel1</value> + </data> + <data name=">>btnDelHistory.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name="tabPageUnZip.TabIndex" type="System.Int32, mscorlib"> + <value>1</value> + </data> + <data name=">>txtProxyDomain.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name="txtProxyURL.Location" type="System.Drawing.Point, System.Drawing"> + <value>87, 20</value> + </data> + <data name=">>lblCyp.Name" xml:space="preserve"> + <value>lblCyp</value> + </data> + <data name="cmbCyp.Location" type="System.Drawing.Point, System.Drawing"> + <value>61, 7</value> + </data> + <data name="txtUID.Location" type="System.Drawing.Point, System.Drawing"> + <value>87, 44</value> + </data> + <data name="cbxExt.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name="txtPass.TabIndex" type="System.Int32, mscorlib"> + <value>15</value> + </data> + <data name="lblCmpLv.Location" type="System.Drawing.Point, System.Drawing"> + <value>3, 38</value> + </data> + <data name="lblPass.TabIndex" type="System.Int32, mscorlib"> + <value>16</value> + </data> + <data name=">>txtExt.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>tabDeployZipPac.Type" xml:space="preserve"> + <value>System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>tabPageUnZip.Name" xml:space="preserve"> + <value>tabPageUnZip</value> + </data> + <data name=">>btnCheckUpdateAndInstall.Name" xml:space="preserve"> + <value>btnCheckUpdateAndInstall</value> + </data> + <data name=">>btnRemoveZIPFile.Type" xml:space="preserve"> + <value>System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="label3.Text" xml:space="preserve"> + <value>EXE name (path) to be specified in a comma-separated, EXE the first is subject to activation.</value> + </data> + <data name=">>txtPass.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name=">>lblProxyDomain.Parent" xml:space="preserve"> + <value>gbxProxy</value> + </data> + <data name=">>btnCreateManifesto.ZOrder" xml:space="preserve"> + <value>7</value> + </data> + <data name=">>panel1.Parent" xml:space="preserve"> + <value>$this</value> + </data> + <data name=">>txtProxyDomain.Name" xml:space="preserve"> + <value>txtProxyDomain</value> + </data> + <data name="lblExeName.TabIndex" type="System.Int32, mscorlib"> + <value>6</value> + </data> + <data name=">>gbxProxy.Name" xml:space="preserve"> + <value>gbxProxy</value> + </data> + <data name="label2.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <data name=">>lblPWD.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>lblProxyUID.ZOrder" xml:space="preserve"> + <value>7</value> + </data> + <data name="lblPWD.Size" type="System.Drawing.Size, System.Drawing"> + <value>53, 13</value> + </data> + <data name=">>lblEEFA.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="label1.TabIndex" type="System.Int32, mscorlib"> + <value>9</value> + </data> + <data name=">>panel1.Type" xml:space="preserve"> + <value>System.Windows.Forms.Panel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>lblFormat.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="btnCreateManifesto.Location" type="System.Drawing.Point, System.Drawing"> + <value>15, 319</value> + </data> + <data name=">>lblURL.Name" xml:space="preserve"> + <value>lblURL</value> + </data> + <data name=">>txtExeName.Name" xml:space="preserve"> + <value>txtExeName</value> + </data> + <data name="gbxProxy.Size" type="System.Drawing.Size, System.Drawing"> + <value>424, 133</value> + </data> + <data name=">>txtDomain.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name=">>openFileDialog1.Name" xml:space="preserve"> + <value>openFileDialog1</value> + </data> + <data name="lbxZIPFiles.Size" type="System.Drawing.Size, System.Drawing"> + <value>415, 121</value> + </data> + <data name=">>txtProxyPWD.Parent" xml:space="preserve"> + <value>gbxProxy</value> + </data> + <data name=">>cbxFormat.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name=">>tabPageDeployWithHTTP.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name="txtProxyUID.TabIndex" type="System.Int32, mscorlib"> + <value>10</value> + </data> + <data name=">>txtProxyURL.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>tabPageDeployWithHTTP.Parent" xml:space="preserve"> + <value>tabDeployZipPac</value> + </data> + <data name="tabPageZipPackage.TabIndex" type="System.Int32, mscorlib"> + <value>1</value> + </data> + <data name=">>cmbCyp.ZOrder" xml:space="preserve"> + <value>9</value> + </data> + <data name=">>cbxFormat.Name" xml:space="preserve"> + <value>cbxFormat</value> + </data> + <data name=">>txtExt.ZOrder" xml:space="preserve"> + <value>9</value> + </data> + <data name=">>lblFormat.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name=">>label1.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name="tabPageUnZip.Text" xml:space="preserve"> + <value>Thawing (test)</value> + </data> + <data name=">>txtExt.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name=">>lblProxyUID.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="btnDelHistory.Location" type="System.Drawing.Point, System.Drawing"> + <value>344, 8</value> + </data> + <data name=">>txtProxyURL.Name" xml:space="preserve"> + <value>txtProxyURL</value> + </data> + <data name="cmbCmpLv.Size" type="System.Drawing.Size, System.Drawing"> + <value>358, 21</value> + </data> + <data name="lblFolder.Size" type="System.Drawing.Size, System.Drawing"> + <value>36, 13</value> + </data> + <data name=">>cbxFormat.ZOrder" xml:space="preserve"> + <value>2</value> + </data> + <data name=">>lblCmpLv.Name" xml:space="preserve"> + <value>lblCmpLv</value> + </data> + <data name=">>label1.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="btnCheckUpdateAndInstall.TabIndex" type="System.Int32, mscorlib"> + <value>14</value> + </data> + <data name=">>lblUID.ZOrder" xml:space="preserve"> + <value>6</value> + </data> + <data name="cbxRootDir.Location" type="System.Drawing.Point, System.Drawing"> + <value>8, 91</value> + </data> + <data name=">>gbxWWW.ZOrder" xml:space="preserve"> + <value>4</value> + </data> + <data name=">>cmbCyp.Name" xml:space="preserve"> + <value>cmbCyp</value> + </data> + <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing"> + <value>464, 427</value> + </data> + <data name="lblProxyUID.TabIndex" type="System.Int32, mscorlib"> + <value>9</value> + </data> + <data name="lblRootDirCheck.Text" xml:space="preserve"> + <value>(Compression from the root folder) that you do not want to include in the root folder in the ZIP ZIP file name specified: Checked.</value> + </data> + <data name=">>cbxExt.ZOrder" xml:space="preserve"> + <value>8</value> + </data> + <data name="gbxProxy.Text" xml:space="preserve"> + <value>Proxy server</value> + </data> + <data name=">>folderBrowserDialog1.Name" xml:space="preserve"> + <value>folderBrowserDialog1</value> + </data> + <data name="cmbFormat.TabIndex" type="System.Int32, mscorlib"> + <value>14</value> + </data> + <data name=">>btnSelectSaveFile.ZOrder" xml:space="preserve"> + <value>7</value> + </data> + <data name="tabPageZipPackage.Size" type="System.Drawing.Size, System.Drawing"> + <value>442, 353</value> + </data> + <data name=">>txtURL.Type" xml:space="preserve"> + <value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>lblPass.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtURL.Size" type="System.Drawing.Size, System.Drawing"> + <value>331, 20</value> + </data> + <data name=">>lblDomain.Name" xml:space="preserve"> + <value>lblDomain</value> + </data> + <data name=">>txtFile.Name" xml:space="preserve"> + <value>txtFile</value> + </data> + <data name="btnSelectSaveFile.TabIndex" type="System.Int32, mscorlib"> + <value>7</value> + </data> + <data name="txtInsDir.Size" type="System.Drawing.Size, System.Drawing"> + <value>292, 20</value> + </data> + <data name=">>lblUID.Parent" xml:space="preserve"> + <value>gbxWWW</value> + </data> + <data name=">>txtPWD.Name" xml:space="preserve"> + <value>txtPWD</value> + </data> + <data name=">>tabZipUnZip.Name" xml:space="preserve"> + <value>tabZipUnZip</value> + </data> + <data name="cmbEnc.Location" type="System.Drawing.Point, System.Drawing"> + <value>94, 91</value> + </data> + <data name=">>gbxProxy.Parent" xml:space="preserve"> + <value>tabPageDeployWithHTTP</value> + </data> + <data name=">>btnDecomp.Parent" xml:space="preserve"> + <value>tabPageUnZip</value> + </data> + <data name=">>lblDomain.Parent" xml:space="preserve"> + <value>gbxWWW</value> + </data> + <data name="lblProxyDomain.TabIndex" type="System.Int32, mscorlib"> + <value>9</value> + </data> + <data name="cbxRootDir.Font" type="System.Drawing.Font, System.Drawing"> + <value>MS UI Gothic, 8.25pt</value> + </data> + <data name=">>cmbEEFA.Name" xml:space="preserve"> + <value>cmbEEFA</value> + </data> + <data name=">>tabPageZip.Parent" xml:space="preserve"> + <value>tabZipUnZip</value> + </data> + <data name=">>label3.Name" xml:space="preserve"> + <value>label3</value> + </data> + <data name=">>btnDecomp.Name" xml:space="preserve"> + <value>btnDecomp</value> + </data> + <data name=">>cbxRootDir.Type" xml:space="preserve"> + <value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="lblEnc.Text" xml:space="preserve"> + <value>Encode</value> + </data> + <data name="tabPageDeployWithHTTP.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms"> + <value>3, 3, 3, 3</value> + </data> + <data name="lblURL.Text" xml:space="preserve"> + <value>URL</value> + </data> + <data name="panel1.Location" type="System.Drawing.Point, System.Drawing"> + <value>1, 2</value> + </data> + <data name="btnCreateManifesto.Size" type="System.Drawing.Size, System.Drawing"> + <value>415, 25</value> + </data> + <data name=">>lblHistorys.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>$this.Name" xml:space="preserve"> + <value>Form1</value> + </data> + <data name="btnCompress.Text" xml:space="preserve"> + <value>Compression</value> + </data> + <data name=">>txtExeName.Parent" xml:space="preserve"> + <value>tabPageManifesto</value> + </data> + <data name="txtProxyUID.Size" type="System.Drawing.Size, System.Drawing"> + <value>331, 20</value> + </data> + <data name="tabPageZipPackage.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms"> + <value>3, 3, 3, 3</value> + </data> + <data name=">>lblEEFA.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name="lbxZIPFiles.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name=">>cmbEnc.Type" xml:space="preserve"> + <value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="txtFolder.Size" type="System.Drawing.Size, System.Drawing"> + <value>232, 20</value> + </data> + <data name=">>lblExeName.ZOrder" xml:space="preserve"> + <value>5</value> + </data> + <data name="cmbCmpLv.Location" type="System.Drawing.Point, System.Drawing"> + <value>61, 35</value> + </data> + <data name=">>label3.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>lbxZIPFiles.Name" xml:space="preserve"> + <value>lbxZIPFiles</value> + </data> + <data name="tabPageManifesto.TabIndex" type="System.Int32, mscorlib"> + <value>2</value> + </data> + <data name=">>lblExeName.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="tabPageManifesto.Size" type="System.Drawing.Size, System.Drawing"> + <value>442, 353</value> + </data> + <data name=">>tabPageZipPackage.Parent" xml:space="preserve"> + <value>tabDeployZipPac</value> + </data> + <data name=">>btnDecomp.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name=">>btnCreateManifesto.Name" xml:space="preserve"> + <value>btnCreateManifesto</value> + </data> + <data name=">>lblProxyURL.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name="tabPageUnZip.Size" type="System.Drawing.Size, System.Drawing"> + <value>422, 167</value> + </data> + <data name=">>lblEnc.Parent" xml:space="preserve"> + <value>tabPageZipPackage</value> + </data> + <data name="lblPWD.Text" xml:space="preserve"> + <value>Password</value> + </data> + <data name=">>cmbFormat.ZOrder" xml:space="preserve"> + <value>4</value> + </data> + <data name=">>label3.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name=">>cmbCmpLv.ZOrder" xml:space="preserve"> + <value>6</value> + </data> + <data name=">>cmbFormat.Parent" xml:space="preserve"> + <value>tabPageZip</value> + </data> + <data name=">>lblInsDir.Name" xml:space="preserve"> + <value>lblInsDir</value> + </data> + <data name=">>btnCheckUpdateAndInstall.Parent" xml:space="preserve"> + <value>tabPageDeployWithHTTP</value> + </data> + <data name="txtExeName.TabIndex" type="System.Int32, mscorlib"> + <value>5</value> + </data> + <data name=">>txtUID.ZOrder" xml:space="preserve"> + <value>7</value> + </data> + <data name="btnSelectFolder.Location" type="System.Drawing.Point, System.Drawing"> + <value>332, 8</value> + </data> + <data name=">>cmbCyp.Type" xml:space="preserve"> + <value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>lblExt.ZOrder" xml:space="preserve"> + <value>6</value> + </data> + <data name=">>txtProxyPWD.Name" xml:space="preserve"> + <value>txtProxyPWD</value> + </data> + <data name=">>panel1.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name="label3.Size" type="System.Drawing.Size, System.Drawing"> + <value>433, 26</value> + </data> + <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>True</value> + </metadata> + <metadata name="saveFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>178, 17</value> + </metadata> + <metadata name="openFilesDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>441, 17</value> + </metadata> + <metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>309, 17</value> + </metadata> + <metadata name="folderBrowserDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>17, 17</value> + </metadata> +</root> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.Designer.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.Designer.cs new file mode 100644 index 000000000..1f6138575 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.Designer.cs @@ -0,0 +1,77 @@ +namespace DeployZipPackWithHTTP +{ + partial class Form2 + { + /// <summary> + /// Required designer variable. + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// Clean up any resources being used. + /// </summary> + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// <summary> + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// </summary> + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form2)); + this.panel1 = new System.Windows.Forms.Panel(); + this.lblStatus = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.Controls.Add(this.lblStatus); + this.panel1.Controls.Add(this.progressBar1); + resources.ApplyResources(this.panel1, "panel1"); + this.panel1.Name = "panel1"; + // + // lblStatus + // + resources.ApplyResources(this.lblStatus, "lblStatus"); + this.lblStatus.Name = "lblStatus"; + // + // progressBar1 + // + resources.ApplyResources(this.progressBar1, "progressBar1"); + this.progressBar1.Name = "progressBar1"; + // + // Form2 + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.panel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "Form2"; + this.Load += new System.EventHandler(this.Form2_Load); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Label lblStatus; + private System.Windows.Forms.ProgressBar progressBar1; + } +} \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.cs new file mode 100644 index 000000000..a1ff3d42e --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.cs @@ -0,0 +1,377 @@ +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** + +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :Form2 +//* クラス日本語名 :サブ画面(CUIの進捗報告画面) +//* +//* 作成者 :生技 西野 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2011/06/17 西野 大介 新規作成 +//* 2011/07/01 西野 大介 最後に進捗が100%になるように変更 +//* 2011/07/01 西野 大介 コマンドライン引数のハッシュキーを全て大文字化 +//* 2011/08/01 西野 大介 タイトルをメッセージ定義から取得するように変更。 +//* 2011/08/01 西野 大介 最大化、最小化、閉じるボタンを無効にした。 +//* 2011/08/01 西野 大介 最後、自身を閉じる(非同期待機時間を設定可能に) +//* 2011/08/01 西野 大介 /QUIET クワイエット モードを追加した。 +//* 2011/08/01 西野 大介 進捗値の進み具合を調整した。 +//* 2011/08/01 西野 大介 ステータスの書き込み(終了時) +//* 2011/08/30 西野 大介 異常終了時に退避ディレクトリからリカバリ。 +//* 2011/08/30 西野 大介 テンポラリの削除処理を追加した(例外処理を追加)。 +//* 2011/08/30 西野 大介 Exceptionではメッセージ表示しないよう修正した。 +//* 2011/09/05 西野 大介 GCするコードを追加→修正(解凍ZIPがCloseされないため) +//* 2011/09/08 西野 大介 リカバリ処理のログ出力位置の変更 +//* (リカバリしない時ログを出力しないよう変更)。 +//* 2011/09/12 西野 大介 画面表示せず、ログ出力のみする例外処理方式を追加 +//* 2014/04/26 Sai Replaced all the Japanese language in both UI and code with ResorceManager.GetString() method call +//* 2020/08/03 西野 大介 NETCOREAPP対応 +//********************************************************************************** + +using System; +using System.IO; +using System.Collections.Generic; +using System.Threading; +using System.Security.Permissions; +using System.Resources; +using System.Windows.Forms; + +using Touryo.Infrastructure.Business.RichClient.Asynchronous; +using Touryo.Infrastructure.Framework.RichClient.Asynchronous; +using Touryo.Infrastructure.Framework.Util; +using Touryo.Infrastructure.Public.Util; + +namespace DeployZipPackWithHTTP +{ + public partial class Form2 : Form + { + /// <summary>値</summary> + private List<string> ValsLst; + /// <summary>コマンド・値</summary> + private Dictionary<string, string> ArgsDic; + + /// <summary>ステータス表示用</summary> + public string Status + { + set + { + this.lblStatus.Text = value; + } + get + { + return this.lblStatus.Text; + } + } + + /// <summary> + /// Getting ResourceManager instance from Resources to apply internationalization + /// </summary> + private ResourceManager ResourceMgr + { + get + { + return Resources.Resource.ResourceManager; + } + } + + /// <summary>コンストラクタ</summary> + /// <param name="valsLst">値</param> + /// <param name="argsDic">コマンド・値</param> + public Form2(List<string> valsLst, Dictionary<string, string> argsDic) + { + InitializeComponent(); + + this.ValsLst = valsLst; + this.ArgsDic = argsDic; + + // タイトルの設定 + string temp + = GetMessage.GetMessageDescription("I0000"); + + if (string.IsNullOrEmpty(temp)) + { + // IsNullOrEmptyの場合はデフォルト + } + else + { + // タイトルを設定した。 + this.Text = temp; + } + } + + /// <summary>Form2_Load</summary> + private void Form2_Load(object sender, EventArgs e) + { + // コマンドの確認 + Program.ConfirmCommand(this.ValsLst, this.ArgsDic); + + // エントリを生成 + Entry entry = new Entry(); + + // コマンドラインから各値を取得する。 + entry.WWWURL = Program.NullToEmptyString(this.ArgsDic, "/WWWURL"); + entry.WWWUID = Program.NullToEmptyString(this.ArgsDic, "/WWWUID"); + entry.WWWPWD = Program.NullToEmptyString(this.ArgsDic, "/WWWPWD"); + entry.WWWDomain = Program.NullToEmptyString(this.ArgsDic, "/WWWDOMAIN"); + //--- + entry.ProxyURL = Program.NullToEmptyString(this.ArgsDic, "/PROXYURL"); + entry.ProxyUID = Program.NullToEmptyString(this.ArgsDic, "/PROXYUID"); + entry.ProxyPWD = Program.NullToEmptyString(this.ArgsDic, "/PROXYPWD"); + entry.ProxyDomain = Program.NullToEmptyString(this.ArgsDic, "/PROXYDOMAIN"); + + //// エントリを保存 + //Program.SaveCurrent(entry); + + // 履歴をロード + Program.LoadHistories(); + + #region 更新処理の実行 + + // 非同期呼び出し + Program.Af = new MyBaseAsyncFunc(this.panel1); + + // 非同期処理本体デレゲード + Program.Af.AsyncFunc = new BaseAsyncFunc.AsyncFuncDelegate(Program.ExecUpdate); + + // 進捗報告・無名関数デレゲード + Program.Af.ChangeProgress = delegate(object param) + { + ChangeProgressParameter cpp = (ChangeProgressParameter)param; + + this.Status = cpp.Status; + + // 知的でないプログレス的なもの + int progressVal = this.progressBar1.Value + cpp.ProgressVal; + if (progressVal < this.progressBar1.Maximum - 5) + { + // 95%を超えない場合、変更する。 + this.progressBar1.Value = progressVal; + } + else + { + // 95%を超える場合、変更しない。 + } + + this.Refresh(); + }; + + // 結果設定・無名関数デレゲード + Program.Af.SetResult = delegate(object retVal) + { + if (retVal is MyException) + { + // 戻し + Program.Recover(); + + // メッセージ表示時 + MyException my_ex = (MyException)retVal; + string message = my_ex.Message; + + // ログ出力用のフィールドがあるか?ないか? + if (string.IsNullOrEmpty(my_ex.ToLog)) + { + Program.OutPutMessage(message, LogLevel.InfoLog); + } + else + { + Program.OutPutMessage(message + "\r\n" + my_ex.ToLog, LogLevel.InfoLog); + } + + // ステータスを書き込む + this.Status = ResourceMgr.GetString("S0001"); + if (ArgsDic.ContainsKey("/QUIET")) + { + // メッセージ表示しない + } + else + { + // メッセージ表示する + MessageBox.Show(message, ResourceMgr.GetString("M0001"), MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + else if (retVal is Exception) + { + // 戻し + Program.Recover(); + + // 例外発生時 + string message = ""; + Exception ex = (Exception)retVal; + + message += ResourceMgr.GetString("M0002") + "\r\n"; + message += ex.Message; + message += "\r\n"; + + message += "\r\n"; + message += ResourceMgr.GetString("M0003") + "\r\n"; + message += ex.StackTrace; + message += "\r\n"; + + if (ex.InnerException != null) + { + message += "\r\n"; + message += ResourceMgr.GetString("M0004") + "\r\n"; + message += ex.InnerException.ToString(); + message += "\r\n"; + } + + Program.OutPutMessage(message, LogLevel.ErrorLog); + + // ステータスを書き込む + this.Status = ResourceMgr.GetString("S0002"); + + // Exceptionではメッセージ表示しない。 + + //if (ArgsDic.ContainsKey("/QUIET")) + //{ + // // メッセージ表示しない + //} + //else + //{ + // // メッセージ表示する + // CustMsgBox custMsgBox = new CustMsgBox( + // "エラー", message, SystemIcons.Error); + + // custMsgBox.ShowDialog(); + //} + } + else + { + // 正常終了 + + // ステータスを書き込む + //this.Status = "正常終了"; + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + this.Status = ResourceMgr.GetString("S0001"); + + // 履歴を保存 + Program.SaveHistories(); + } + + // 進捗を100%に変更 + this.progressBar1.Value = 100; + + // テンポラリの削除 + File.Delete(Program.OrgCurrentDirectory + Program.TempMftFileName); + + // GCでZIPが解放される可能性 + //GC.Collect(); + Program.system_gc_collecting(); + try + { + File.Delete(Program.OrgCurrentDirectory + Program.TempZipFileName); + } + catch(Exception ex) + { + // 例外を潰してログに出力 + Program.OutPutMessage(Program.TempZipFileName + ResourceMgr.GetString("E0002") + ex.ToString(), LogLevel.ErrorLog); + } + + // 終了処理 + this.BeginInvoke(new MethodInvoker(FinalBeginInvoke)); + }; + + // 非同期処理を開始させる。 + Program.Af.Parameter = entry; + + if (Program.Af.Start()) + { + //this.XXXX(string.Format("キューイングされました、現在のスレッド数:{0}", BaseAsyncFunc.ThreadCount.ToString())); + } + else + { + //this.XXXX(string.Format("非同期スレッドが最大数に達しています。:{0}", BaseAsyncFunc.ThreadCount.ToString())); + } + + #endregion + } + + /// <summary>終了処理(3秒待って終了)</summary> + private void FinalBeginInvoke() + { + // 非同期呼び出し + Program.Af = new MyBaseAsyncFunc(this.panel1); + + // 非同期処理本体デレゲード + Program.Af.AsyncFunc = delegate(object o) + { + // 指定時間スリープ + string temp = GetConfigParameter.GetConfigValue("PDWSleepSec"); + + if (!string.IsNullOrEmpty(temp)) + { + int sleepSec = 0; + if (int.TryParse(temp, out sleepSec)) + { + // 指定の時間スリープ + Thread.Sleep(sleepSec * 1000); + } + } + + return null; + }; + + // 進捗報告・無名関数デレゲード + Program.Af.ChangeProgress = null; + + // 結果設定・無名関数デレゲード + Program.Af.SetResult = delegate(object retVal) + { + // スリープの後、自身を閉じる。 + this.Close(); + }; + + // 非同期処理を開始させる。 + Program.Af.Parameter = null; + + if (Program.Af.Start()) + { + //this.XXXX(string.Format("キューイングされました、現在のスレッド数:{0}", BaseAsyncFunc.ThreadCount.ToString())); + } + else + { + //this.XXXX(string.Format("非同期スレッドが最大数に達しています。:{0}", BaseAsyncFunc.ThreadCount.ToString())); + } + } + + /// <summary> + /// 閉じるボタンの無効化 + /// http://dobon.net/vb/dotnet/form/disabledclosebutton.html + /// </summary> + /// <param name="m">Windowメッセージ</param> + [SecurityPermission( + SecurityAction.LinkDemand, + Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override void WndProc(ref Message m) + { + const int WM_SYSCOMMAND = 0x112; + const int SC_CLOSE = 0xF060; + + if (m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) + { + return; + } + + base.WndProc(ref m); + } + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.ja-JP.resx b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.ja-JP.resx new file mode 100644 index 000000000..2da80c190 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.ja-JP.resx @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> + <data name="lblStatus.Size" type="System.Drawing.Size, System.Drawing"> + <value>52, 13</value> + </data> + <data name="lblStatus.Text" xml:space="preserve"> + <value>ステータス</value> + </data> + <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + AAABAAEAICAAAAEAGACoDAAAFgAAACgAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS1/TS1/QAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACirOg7T847T86irOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukySMwIIsEIIsEy + SMypsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACjreg6T84gOMcIIsEAG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEA + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukxR8sIIsEAG78AG78AG78AG78AG78AG78AG78AG78IIsEx + R8upsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjreg6T84g + OMcIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEAG78AG78AG78AG78AG78AG78AG78AG78A + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADL0fKy + uuwzScwIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEz + ScyyuuzL0fIAAAAAAAAAAAAAAAAAAAAAAAAAAADd4PZlddhIW9EwRssoP8koP8koP8kgOMcIIsEAG78A + G78AG78AG78AG78AG78AG78AG78IIsEgOMcoP8koP8koP8kwRstIW9FkddfU1+wAAAAAAAAAAAAAAAAA + AAD29/3u8PvS1/TGzPHCyPC/xu/Axu/ByPCxuesgOMcAG78AG78AG78AG78AG78AG78AG78AG78gOMex + uOa8wNq2utO2utO2utO2utO+wdXZ2t/f3+IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADDyvAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m8wNpkZGRKSkpKSkpKSkpKSkpKSkpeXl7B + wsMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFy+8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKCgoKCgoKCgoKCgoKCgvLy9ZWVnKysoAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAADc3NzY2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgoKCgo + KCgoKCgoKCgoKChDQ0O/v7/U1NQAAAAAAAAAAAAAAAAAAAAAAAAAAADg4OB+fn5/f3/Dx+EoP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgvLy9DQ0NKSkpKSkpKSkpQUFBkZGR9fX3j4+MA + AAAAAAAAAAAAAAAAAADy8vLv7+/f39/Y2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChDQ0O9vb3Ly8vKysrJycnLy8vPz8/Z2dnx8fH39/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADEyu4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrLy8sAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAxu8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrKysoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCyPAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADL0fJIW9EoP8koP8koP8koP8koP8koP8koP8koP8lIW9G+wdVKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADX2/XL0fLEyvDEyu7L0Oy8wNq2utO2 + utO2utO2utO+wdW7u8FDQ0MoKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT1NpkZGRKSkpKSkpKSkpKSkpKSkpDQ0MvLy8oKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADS0tJKSkooKCgoKCgoKCgoKCgoKCgoKCgoKCgoKChKSkrLy8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0tJkZGRKSkpKSkpKSkpKSkpKSkpK + SkpKSkpKSkpkZGTS0tIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADv7+/k5OTd3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3k5OTv7+8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD/+f////D////AP///gB///wAP//wAA//4AAH/8AAA/8AAAD+AAAAfAAAAD/8A + AA//AAAH/AAAA/gAAAHwAAAA/wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8A + AP//AAD///AA///wAP//8AD///AA/w== +</value> + </data> + <data name="$this.Text" xml:space="preserve"> + <value>更新確認進捗ダイアログ</value> + </data> +</root> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.resx b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.resx new file mode 100644 index 000000000..0dd307fa4 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Form2.resx @@ -0,0 +1,271 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <data name="lblStatus.AutoSize" type="System.Boolean, mscorlib"> + <value>True</value> + </data> + <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> + <data name="lblStatus.Location" type="System.Drawing.Point, System.Drawing"> + <value>12, 51</value> + </data> + <data name="lblStatus.Size" type="System.Drawing.Size, System.Drawing"> + <value>37, 13</value> + </data> + <data name="lblStatus.TabIndex" type="System.Int32, mscorlib"> + <value>1</value> + </data> + <data name="lblStatus.Text" xml:space="preserve"> + <value>Status</value> + </data> + <data name=">>lblStatus.Name" xml:space="preserve"> + <value>lblStatus</value> + </data> + <data name=">>lblStatus.Type" xml:space="preserve"> + <value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>lblStatus.Parent" xml:space="preserve"> + <value>panel1</value> + </data> + <data name=">>lblStatus.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <data name="progressBar1.Location" type="System.Drawing.Point, System.Drawing"> + <value>14, 15</value> + </data> + <data name="progressBar1.Size" type="System.Drawing.Size, System.Drawing"> + <value>241, 25</value> + </data> + <data name="progressBar1.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name=">>progressBar1.Name" xml:space="preserve"> + <value>progressBar1</value> + </data> + <data name=">>progressBar1.Type" xml:space="preserve"> + <value>System.Windows.Forms.ProgressBar, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>progressBar1.Parent" xml:space="preserve"> + <value>panel1</value> + </data> + <data name=">>progressBar1.ZOrder" xml:space="preserve"> + <value>1</value> + </data> + <data name="panel1.Location" type="System.Drawing.Point, System.Drawing"> + <value>12, 13</value> + </data> + <data name="panel1.Size" type="System.Drawing.Size, System.Drawing"> + <value>273, 77</value> + </data> + <data name="panel1.TabIndex" type="System.Int32, mscorlib"> + <value>0</value> + </data> + <data name=">>panel1.Name" xml:space="preserve"> + <value>panel1</value> + </data> + <data name=">>panel1.Type" xml:space="preserve"> + <value>System.Windows.Forms.Panel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> + <data name=">>panel1.Parent" xml:space="preserve"> + <value>$this</value> + </data> + <data name=">>panel1.ZOrder" xml:space="preserve"> + <value>0</value> + </data> + <metadata name="$this.Language" type="System.Globalization.CultureInfo, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>ja-JP</value> + </metadata> + <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>True</value> + </metadata> + <data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing"> + <value>6, 13</value> + </data> + <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing"> + <value>295, 103</value> + </data> + <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value> + AAABAAEAICAAAAEAGACoDAAAFgAAACgAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS1/TS1/QAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAACirOg7T847T86irOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukySMwIIsEIIsEy + SMypsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACjreg6T84gOMcIIsEAG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEA + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAC4v+2psukxR8sIIsEAG78AG78AG78AG78AG78AG78AG78AG78IIsEx + R8upsum4v+0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjreg6T84g + OMcIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEgOMc6T86jregAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAChq+cySMwIIsEAG78AG78AG78AG78AG78AG78AG78AG78A + G78AG78AG78AG78AG78AG78IIsEySMyhq+cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADL0fKy + uuwzScwIIsEAG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78AG78IIsEz + ScyyuuzL0fIAAAAAAAAAAAAAAAAAAAAAAAAAAADd4PZlddhIW9EwRssoP8koP8koP8kgOMcIIsEAG78A + G78AG78AG78AG78AG78AG78AG78IIsEgOMcoP8koP8koP8kwRstIW9FkddfU1+wAAAAAAAAAAAAAAAAA + AAD29/3u8PvS1/TGzPHCyPC/xu/Axu/ByPCxuesgOMcAG78AG78AG78AG78AG78AG78AG78AG78gOMex + uOa8wNq2utO2utO2utO2utO+wdXZ2t/f3+IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADDyvAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m8wNpkZGRKSkpKSkpKSkpKSkpKSkpeXl7B + wsMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFy+8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKCgoKCgoKCgoKCgoKCgvLy9ZWVnKysoAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAADc3NzY2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgoKCgo + KCgoKCgoKCgoKChDQ0O/v7/U1NQAAAAAAAAAAAAAAAAAAAAAAAAAAADg4OB+fn5/f3/Dx+EoP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKCgvLy9DQ0NKSkpKSkpKSkpQUFBkZGR9fX3j4+MA + AAAAAAAAAAAAAAAAAADy8vLv7+/f39/Y2d/M0e0oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChDQ0O9vb3Ly8vKysrJycnLy8vPz8/Z2dnx8fH39/cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADEyu4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrLy8sAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAxu8oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrKysoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78A + G78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAC9xO4oP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9xO4oP8kAG78A + G78AG78AG78AG78AG78AG78AG78oP8m2utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCyPAoP8kAG78AG78AG78AG78AG78AG78AG78AG78oP8m2 + utNKSkooKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADL0fJIW9EoP8koP8koP8koP8koP8koP8koP8koP8lIW9G+wdVKSkooKChKSkrHx8cAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADX2/XL0fLEyvDEyu7L0Oy8wNq2utO2 + utO2utO2utO+wdW7u8FDQ0MoKChKSkrHx8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADT1NpkZGRKSkpKSkpKSkpKSkpKSkpDQ0MvLy8oKChKSkrH + x8cAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADS0tJKSkooKCgoKCgoKCgoKCgoKCgoKCgoKCgoKChKSkrLy8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADS0tJkZGRKSkpKSkpKSkpKSkpKSkpK + SkpKSkpKSkpkZGTS0tIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADv7+/k5OTd3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3k5OTv7+8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD/+f////D////AP///gB///wAP//wAA//4AAH/8AAA/8AAAD+AAAAfAAAAD/8A + AA//AAAH/AAAA/gAAAHwAAAA/wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8A + AP//AAD///AA///wAP//8AD///AA/w== +</value> + </data> + <data name="$this.Text" xml:space="preserve"> + <value>Update confirmation dialog progress</value> + </data> + <data name=">>$this.Name" xml:space="preserve"> + <value>Form2</value> + </data> + <data name=">>$this.Type" xml:space="preserve"> + <value>System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </data> +</root> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Log4DeployZipPackWithHTTP.xml b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Log4DeployZipPackWithHTTP.xml new file mode 100644 index 000000000..b443b2c36 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Log4DeployZipPackWithHTTP.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- log4net構成設定のセクション --> + +<log4net debug="true"> + + <!-- アペンダを選択することによって、ログの出力先を変更できる。 --> + + <!-- + アペンダの例 + + FileAppender :ファイルに出力。 + RollingFileAppender :ファイルに出力。ローリング機能付き。 + EventLogAppender :イベントビューアに出力(ローカルのPCのみ) + ConsoleAppender :コンソールに出力 + --> + + <!-- + PatternLayoutで指定できるパターン + パターン 説明 + %logger ログ出力が行われたlogger名 + %appdomain アプリケーションドメイン名 + ●%date 日時を出力。「%date{yyyy/MM/dd HH:mm:ss,fff}」といった詳細指定も可能。 + ●%level ログのレベル(Fatal/Errorなど) + ●%t ログを生成したスレッド + ●%message メッセージ + ●%newline 改行文字 + %literal{-} リテラル(%をそのまま出力する場合など) + %file ファイル名 + %class クラス名 + %method メソッド名 + %line 行番号 + %location ログ出力した際の関数名とファイルのフルパス + ※ %file ~ %locationは処理負荷が高くなるため必要な時以外は使用しない。 + http://d.hatena.ne.jp/shima111/20060703 + --> + + <!-- ローリング・ログファイル出力用アペンダ --> + <appender name="ACCESS" type="log4net.Appender.FileAppender"> + <param name="File" value="../Logs/ACCESS_2CS.log" /> + <!-- ローリングの設定 --> + <param name="StaticLogFileName" value="false" /> + <param name="RollingStyle" value="date " /> + <param name="DatePattern" value='"."yyyy-MM-dd".log"' /> + <!-- 書き込み時の設定 --> + <param name="AppendToFile" value="true" /> + <!-- メッセージのフォーマット --> + <layout type="log4net.Layout.PatternLayout"> + <param name="ConversionPattern" value="[%date{yyyy/MM/dd HH:mm:ss,fff}],[%-5level],[%thread],%message%newline" /> + </layout> + <!-- フィルタの設定 --> + <filter type="log4net.Filter.LevelRangeFilter"> + <levelMin value="DEBUG" /> + <levelMax value="FATAL" /> + </filter> + </appender> + + <!-- + ロガーを作成する。 + + Rootロガーには高い出力レベルを設定する。 + 個別のロガーには低い出力レベルを設定する。 + + その他、特定のレベルのログだけを出力したい + 場合にはFilterと呼ばれる機能を使用する。 + --> + <!-- + ↑出力レベル・高 + Fatal システム停止するような致命的な障害 + Error システム停止はしないが、問題となる障害 + Warn 障害ではない注意警告 + Info 操作ログなどの情報 + Debug 開発用のデバッグメッセージ + ↓出力レベル・低 + --> + + <!-- Rootロガーを作成する(出力レベルとアペンダを設定する)。 --> + + <!-- 個別のロガーを作成する(出力レベルとアペンダを設定する)。 --> + <logger name="ACCESS"> + <level value="DEBUG" /> + <appender-ref ref="ACCESS" /> + </logger> +</log4net> + diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/LogLevel.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/LogLevel.cs new file mode 100644 index 000000000..457d282d1 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/LogLevel.cs @@ -0,0 +1,44 @@ +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** + +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :LogLevel +//* クラス日本語名 :ログレベル +//* +//* 作成者 :生技 西野 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2011/xx/xx 西野 大介 新規作成 +//********************************************************************************** + +namespace DeployZipPackWithHTTP +{ + /// <summary>ログ・レベル</summary> + public enum LogLevel + { + DebugLog, + InfoLog, + WarnLog, + ErrorLog, + FatalLog + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/MSGDefinition.xml b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/MSGDefinition.xml new file mode 100644 index 000000000..8722362de --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/MSGDefinition.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE MSGD[ + <!ELEMENT MSGD (Message*)> + <!ELEMENT Message EMPTY> + <!ATTLIST Message + id ID #REQUIRED + description CDATA #REQUIRED> +]> +<!-- idの先頭には、数字を使用できない。 --> +<!-- 先頭Eは異常系、先頭Iは正常系など --> +<MSGD> + <Message id="I0000" description="★ progress update confirmation dialog ★"/> + <Message id="I0001" description="I am working on a [{0}]."/> + <Message id="I0002" description="Update is complete."/> + <Message id="I0003" description="I was newly added to the history [{0}]."/> + <Message id="I0004" description="I have been removed from the history [{0}]."/> + <Message id="I0005" description="I have updated the history of [{0}]."/> + + <Message id="I0006" description="Update [{0}] (no update date header)."/> + <Message id="I0007" description="[{0}] is up to date."/> + <Message id="I0008" description="Update the [{0}] (update)."/> + <Message id="I0009" description="Update the [{0}] (new)."/> + <Message id="I0010" description="I downloaded the [{0}]."/> + <Message id="I0011" description="Unzip and install [{0}] (update)."/> + <Message id="I0012" description="Because the / NB switch is specified, do not start the assembly."/> + + <!--####--> + + <Message id="E0001" description="EXE file to start [{0}] does not exist."/> + <Message id="E0002" description="EXE file [{0}] has already been started."/> + <Message id="E0003" description="Manifest file is invalid. {0}"/> + <Message id="E0004" description="Only ZIP file will be considered."/> + <Message id="E0005" description="MD5 Hash of [{0}] is a mismatch. {1}, {2}"/> + <Message id="E0006" description="You can not update for [{0}] file is open."/> + <Message id="E0007" description="[{0}] has not been entered."/> + <Message id="E0008" description="I will return to its previous state arrangement target all files."/> + <Message id="E0009" description="I failed to HEAD request to [{0}]."/> + + <!--####--> + + <Message id="M0001" description="Folder path"/> + <Message id="M0002" description="File Path"/> + <Message id="M0003" description="ZIP files"/> + <Message id="M0004" description="Installation directory"/> + <Message id="M0005" description="EXE name (path)"/> + <Message id="M0006" description="Installation directory has been changed {0}."/> +</MSGD> diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/MSGDefinition_ja-JP.xml b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/MSGDefinition_ja-JP.xml new file mode 100644 index 000000000..c20d2bcc8 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/MSGDefinition_ja-JP.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE MSGD[ + <!ELEMENT MSGD (Message*)> + <!ELEMENT Message EMPTY> + <!ATTLIST Message + id ID #REQUIRED + description CDATA #REQUIRED> +]> +<!-- idの先頭には、数字を使用できない。 --> +<!-- 先頭Eは異常系、先頭Iは正常系など --> +<MSGD> + <Message id="I0000" description="★更新確認進捗ダイアログ★"/> + + <Message id="I0001" description="[{0}]を処理しています。"/> + <Message id="I0002" description="更新が完了しました。"/> + + <Message id="I0003" description="[{0}]を履歴に新規追加しました。"/> + <Message id="I0004" description="[{0}]を履歴から削除しました。"/> + <Message id="I0005" description="[{0}]の履歴を更新しました。"/> + + <Message id="I0006" description="[{0}]を更新します(更新日付ヘッダなし)。"/> + <Message id="I0007" description="[{0}]は最新の状態です。"/> + <Message id="I0008" description="[{0}]を更新します(更新)。"/> + <Message id="I0009" description="[{0}]を更新します(新規)。"/> + <Message id="I0010" description="[{0}]をダウンロードしました。"/> + <Message id="I0011" description="[{0}]を解凍・インストールします(更新)。"/> + <Message id="I0012" description="/NB スイッチが指定されているため、アセンブリを起動しません。"/> + + <!--####--> + + <Message id="E0001" description="起動するEXEファイル[{0}]が存在しません。"/> + <Message id="E0002" description="EXEファイル[{0}]が既に起動されています。"/> + <Message id="E0003" description="マニュフェスト ファイルが不正です。{0}"/> + <Message id="E0004" description="ZIPファイルのみが対象になります。"/> + <Message id="E0005" description="[{0}]のMD5 Hashが不一致。{1}, {2}"/> + <Message id="E0006" description="[{0}]ファイルが開かれているため更新できません。"/> + <Message id="E0007" description="[{0}]が入力されていません。"/> + <Message id="E0008" description="全ての配置対象ファイルを直前の状態に戻します。"/> + <Message id="E0009" description="[{0}]へのHEADリクエストに失敗しました。"/> + + + <Message id="M0001" description="フォルダ パス"/> + <Message id="M0002" description="ファイル パス"/> + <Message id="M0003" description="ZIPファイル"/> + <Message id="M0004" description="インストール ディレクトリ"/> + <Message id="M0005" description="EXE名(パス)"/> + <Message id="M0006" description="インストール ディレクトリが変更されています{0}。"/> +</MSGD> diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/MyException.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/MyException.cs new file mode 100644 index 000000000..a188d4be7 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/MyException.cs @@ -0,0 +1,65 @@ +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** + +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :MyException +//* クラス日本語名 :独自エクセプション +//* +//* 作成者 :生技 西野 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2011/xx/xx 西野 大介 新規作成 +//* 2011/09/12 西野 大介 画面表示せず、ログ出力のみする例外処理方式を追加 +//********************************************************************************** + +using System; + +namespace DeployZipPackWithHTTP +{ + /// <summary>独自エクセプション</summary> + public class MyException : Exception + { + /// <summary> + /// ログ出力用 + /// </summary> + public string ToLog + { + private set; + get; + } + + /// <summary>コンストラクタ</summary> + /// <param name="message">メッセージ</param> + public MyException(string message) + : base(message) { } + + /// <summary>コンストラクタ</summary> + /// <param name="message">メッセージ</param> + /// <param name="toLog">ログ出力用</param> + public MyException(string message, string toLog) + : base(message) + { + // ログ出力用 + this.ToLog = toLog; + } + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Program.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Program.cs new file mode 100644 index 000000000..0b292f6e0 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Program.cs @@ -0,0 +1,2478 @@ +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** + +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :Program +//* クラス日本語名 :エントリポイント +//* +//* 作成者 :生技 西野 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2011/04/18 西野 大介 新規作成 +//* 2011/07/01 西野 大介 SelectionCriteriaDlgt2のSplit文字を修正 +//* 2011/07/01 西野 大介 プロキシ設定、プロキシ認証のコードを修正 +//* 2011/07/01 西野 大介 強制モードで、インストール ディレクトリ +//* の削除処理の前に存在チェックを追加した。 +//* 2011/07/01 西野 大介 マニュフェストの起動exeのチェックエラー処理に +//* MyExceptionが使用されていたところを修正。 +//* 2011/07/01 西野 大介 ZIP部位もマニュフェスト ファイル不正例外を使用 +//* 2011/07/01 西野 大介 コマンドライン引数のハッシュキーを全て大文字化 +//* 2011/07/04 西野 大介 インストール ディレクトリ変更は例外に +//* 2011/07/04 西野 大介 アンインストール相当の処理コマンドを追加した。 +//* (ZIPを全て消去する方法ではEXE起動で例外になるので) +//* 2011/07/04 西野 大介 マニュフェスト ファイルのZIPのラインに何も無いとき、 +//* 処理が中断してしまう件を、例外を発生するよう修正 +//* 2011/08/01 西野 大介 /QUIET クワイエット モードを追加した。 +//* 2011/08/01 西野 大介 進捗値の進み具合を調整した。 +//* 2011/08/30 西野 大介 /NB モードを追加した。 +//* 2011/08/30 西野 大介 異常終了時に退避ディレクトリからリカバリ。 +//* 2011/08/30 西野 大介 テンポラリの削除処理を追加した(例外処理を追加)。 +//* 2011/09/01 西野 大介 オープン状態の場合、MyExceptionに振り替える。 +//* 2011/09/01 西野 大介 モジュール比較を大文字化してからに変更。 +//* 2011/09/01 西野 大介 マニュフェストファイルのfinally、Close処理を追加 +//* 2011/09/01 西野 大介 サーバに接続できない場合の例外処理を追加した。 +//* 接続できない場合でEXE起動する場合はログを出力する。 +//* 2011/09/05 西野 大介 GCするコードを追加→修正(解凍ZIPがCloseされないため) +//* 2011/09/05 西野 大介 起動プロセスのウィンドウを最前面にする処理を追加 +//* 2011/09/08 西野 大介 リカバリ処理のログ出力位置の変更 +//* (リカバリしない時ログを出力しないよう変更)。 +//* 2011/09/09 西野 大介 先頭部分でインストール ディレクトリの +//* 読み取り専用属性を消去する処理を追加。 +//* 2011/09/12 西野 大介 画面表示せず、ログ出力のみする例外処理方式を追加 +//* 2014/04/26 Sai Replaced all the Japanese language in both UI and code with ResorceManager.GetString() method call +//* 2014/05/12 Sai Removed <start> and <End> tags, added check while reading FxBusinessMessageCulture from app.config file +//* 2016/01/07 Sandeep Comment out the DefaultWebProxy property, because there is no use of this property in the component +//********************************************************************************** + +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Collections.Generic; +using System.Threading; +using System.Diagnostics; +using System.Security.Cryptography; +using System.Runtime.InteropServices; +using System.Globalization; +using System.Resources; +using System.Windows.Forms; + +using Microsoft.VisualBasic.FileIO; +using Newtonsoft.Json; + + +using Touryo.Infrastructure.Business.RichClient.Asynchronous; +using Touryo.Infrastructure.Framework.Util; +using Touryo.Infrastructure.Public.IO; +using Touryo.Infrastructure.Public.Log; +using Touryo.Infrastructure.Public.Str; +using Touryo.Infrastructure.Public.Util; + + +namespace DeployZipPackWithHTTP +{ + /// <summary>メインと共通</summary> + static class Program + { + // DOBON.NET + // > ファイルをバイト型配列に読み込む、バイト型配列をファイルに書き込む + // http://dobon.net/vb/dotnet/file/filestream.html + // > 複数の配列をマージ(合併、連結、合体)する + // http://dobon.net/vb/dotnet/programing/arraymerge.html + // > WebRequest、WebResponseクラスを使ってファイルをダウンロードし保存する + // http://dobon.net/vb/dotnet/internet/webrequestsavefile.html + // > 二重起動を禁止する > Mutexを使用する方法 + // http://dobon.net/vb/dotnet/process/checkprevinstance.html + + /// <summary>二重起動禁止Mutex</summary> + private static System.Threading.Mutex _mutex; + + #region フラグ + + /// <summary>FORCE実行かどうか</summary> + private static bool IsForce = false; + + /// <summary>起動フラグ</summary> + private static bool IsBoot = true; + + #endregion + + #region 定数 + + /// <summary>カレントファイル</summary> + private static readonly string CurrentFileName = "\\current.json"; + /// <summary>履歴ファイル</summary> + private static readonly string HistoryFileName = "\\histories.json"; + + /// <summary>マニュフェスト一時ファイル</summary> + public static readonly string TempMftFileName = "\\temp.mft"; + /// <summary>ZIP一時ファイル</summary> + public static readonly string TempZipFileName = "\\temp.zip"; + + #endregion + + #region 初回・初期化 + + /// <summary>カレントディレクトリ</summary> + public static string OrgCurrentDirectory = ""; + + #endregion + + #region 都度・初期化 + + /// <summary>履歴情報</summary> + public static List<Entry> Histories = new List<Entry>(); + + /// <summary>バックアップ(インストール)の有・無</summary> + public static bool HaveBackup = false; + /// <summary>インストール ディレクトリを保存</summary> + public static string InstallDirectory = ""; + /// <summary>バックアップ ディレクトリを保存</summary> + public static string BackupDirectory = ""; + + /// <summary> + /// Getting ResourceManager instance from Resources to apply internationalization + /// </summary> + private static ResourceManager ResourceMgr + { + get + { + return Resources.Resource.ResourceManager; + } + } + + #endregion + + #region Win32 + + #region コンソール処理 + + /// <summary> + /// Allocates a new console for the calling process. + /// </summary> + [DllImport("kernel32.dll")] + private static extern Boolean AllocConsole(); + + /// <summary> + /// Attaches the calling process to the console of the specified process. + /// </summary> + /// <param name="dwProcessId"> + /// コンソール プロセスのID(-1の場合、親プロセス) + /// </param> + [DllImport("kernel32.dll")] + public static extern Boolean AttachConsole(int dwProcessId); + + /// <summary> + /// Detaches the calling process from its console. + /// </summary> + [DllImport("kernel32.dll")] + private static extern Boolean FreeConsole(); + + #endregion + + #region ウィンドウ制御 + + static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); + + // Z オーダーだけを目的に使う場合は + // SWP_NOMOVE と SWP_NOSIZE を指定することで + // (x, y), (cx, cy)を無視するようにする. + const uint SWP_NOSIZE = 0x0001; + const uint SWP_NOMOVE = 0x0002; + const uint TOPMOST_FLAGS = (SWP_NOSIZE | SWP_NOMOVE); + + /// <summary> + /// 子ウィンドウ、ポップアップウィンドウ、 + /// またはトップレベルウィンドウの + /// サイズ、位置、および Z オーダーを変更。 + /// これらのウィンドウは、その画面上 + /// での表示に従って順序が決められます。 + /// 最前面にあるウィンドウは最も高いランク + /// を与えられ、Z オーダーの先頭に置かれます。 + /// http://msdn.microsoft.com/ja-jp/library/cc411206.aspx + /// </summary> + /// <param name="hWnd">ウィンドウハンドル</param> + /// <param name="hWndInsertAfter"> + /// Z オーダーを決めるためのウィンドウハンドル + /// + /// ・HWND_BOTTOM + ///  ウィンドウを Z オーダーの最後に置きます。 + /// + /// ・hWnd + ///  パラメタで指定したウィンドウが最前面の場合、 + ///  このウィンドウは最前面ウィンドウではなくなり、 + ///  ほかのすべてのウィンドウの下に置かれます。 + /// + /// ・HWND_NOTOPMOST + ///  ウィンドウを最前面ウィンドウ以外のすべてのウィンドウの前 + ///  (つまり、すべての最前面ウィンドウの後ろ)に挿入します。 + ///   + ///  hWnd パラメータで指定したウィンドウが + ///  既に最前面ウィンドウではなかった場合、 + ///  このフラグは意味を持ちません。 + ///   + /// ・HWND_TOP + ///  ウィンドウを Z オーダーの先頭に置きます。 + ///   + /// ・HWND_TOPMOST + ///  ウィンドウを最前面ウィンドウではない + ///  すべてのウィンドウの前に挿入します。 + ///  このウィンドウは、アクティブでない + ///  ときにも最前面に表示されます。 + /// </param> + /// <param name="x">横方向の位置</param> + /// <param name="y">縦方向の位置</param> + /// <param name="cx">幅</param> + /// <param name="cy">高さ</param> + /// <param name="flags"> + /// ウィンドウ位置のオプション + /// (詳細は上記のURLを参照のこと) + /// </param> + /// <returns> + /// 成功:0 以外の値が返ります。 + /// 失敗:0 が返ります。 + /// 拡張エラー情報を取得するには、関数を使います。 + /// </returns> + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool SetWindowPos( + IntPtr hWnd, IntPtr hWndInsertAfter, + int x, int y, int cx, int cy, uint flags); + + #endregion + + #endregion + + /// <summary> + /// アプリケーションのメイン エントリ ポイントです。 + /// </summary> + [STAThread] + static void Main() + { +#if NETCOREAPP + // configの初期化 + GetConfigParameter.InitConfiguration("appsettings.json"); +#else +#endif + + // Add DefaultCulture key in app.Config file and take the culture value from app.Config file. + string culture = GetConfigParameter.GetConfigValue("DefaultCulture"); + if (!string.IsNullOrEmpty(culture)) + { + Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(culture); + Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(culture); + } + + // exe名 + string exeName = Process.GetCurrentProcess().MainModule.ModuleName; + + // Mutexクラスの作成(exe名を利用する) + Program._mutex = new Mutex(false, exeName); + + // ミューテックスの所有権を要求する + if (Program._mutex.WaitOne(0, false) == false) + { + // 二重起動 + return; + } + else + { + // 二重起動でない。 + + // カレントディレクトリの退避 + // ファイル選択ダイアログでカレントディレクトリが変わる + + // コマンドライン起動しても + // ローカル ディレクトリを使用するように変更 + string[] temp = Process.GetCurrentProcess().MainModule.FileName.Split('\\'); + + for (int i = 0; i < temp.Length - 1; i++) + { + if (i == 0) + { + Program.OrgCurrentDirectory = temp[i]; + } + else + { + Program.OrgCurrentDirectory += "\\" + temp[i]; + } + } + + // コマンドライン:値 + List<string> valsLst; + // コマンドライン:コマンド・値 + Dictionary<string, string> argsDic; + + // コマンドライン引数を取得する。 + StringVariableOperator.GetCommandArgs('/', out argsDic, out valsLst); + + // ヘルプ + if (argsDic.ContainsKey("/HELP")) + { + // コンソール アタッチ + Program.AttachConsole(-1); + + Console.WriteLine(""); + + //Console.WriteLine("/HELP HELPを表示します。"); + //Console.WriteLine("/CUI CUIで起動します。"); + //Console.WriteLine(""); + //Console.WriteLine("以下、CUI時のみ有効なオプション引数"); + //Console.WriteLine(""); + //Console.WriteLine("/FORCE 履歴ファイルを消去して強制更新します。"); + //Console.WriteLine("/QUIET クワイエット モードで実行します(メッセージを非表示)。"); + //Console.WriteLine("/SILENT サイレント モードで実行します(メッセージ、進捗を非表示)。"); + //Console.WriteLine("/NB マニフェストファイルで起動指示アセンブリが指定されていても無視します。"); + //Console.WriteLine(""); + //Console.WriteLine("/WWWURL \"http://xxxx\" WWWサーバ上のマニュフェスト ファイルへのURLを指定します。"); + //Console.WriteLine(""); + //Console.WriteLine("/WWWUID xxxx WWWサーバへアクセスする際のユーザIDを指定します。"); + //Console.WriteLine("/WWWPWD xxxx WWWサーバへアクセスする際のパスワードを指定します。"); + //Console.WriteLine("/WWWDomain xxxx WWWサーバへアクセスする際のドメインを指定します。"); + //Console.WriteLine(""); + //Console.WriteLine("/ProxyURL \"http://yyyy\" ProxyサーバへのURLを指定します。"); + //Console.WriteLine(" 指定の無い場合は、IE設定を適用します。"); + //Console.WriteLine(" [none]指定時はプロキシを使用しません。"); + //Console.WriteLine(""); + //Console.WriteLine("/ProxyUID yyyy Proxyサーバへアクセスする際のユーザIDを指定します。"); + //Console.WriteLine("/ProxyPWD yyyy Proxyサーバへアクセスする際のパスワードを指定します。"); + //Console.WriteLine("/ProxyDomain yyyy Proxyサーバへアクセスする際のドメインを指定します。"); + //Console.WriteLine(""); + //Console.WriteLine("/UnIns \"http://xxxx\" WWWサーバ上のマニュフェスト ファイルへのURLを指定します(アンインストール)。"); + + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + Console.WriteLine(ResourceMgr.GetString("A0001")); + Console.WriteLine(ResourceMgr.GetString("A0002")); + Console.WriteLine(""); + Console.WriteLine(ResourceMgr.GetString("A0003")); + Console.WriteLine(""); + Console.WriteLine(ResourceMgr.GetString("A0004")); + Console.WriteLine(ResourceMgr.GetString("A0005")); + Console.WriteLine(ResourceMgr.GetString("A0006")); + Console.WriteLine(ResourceMgr.GetString("A0007")); + Console.WriteLine(""); + Console.WriteLine(ResourceMgr.GetString("A0008")); + Console.WriteLine(""); + Console.WriteLine(ResourceMgr.GetString("A0009")); + Console.WriteLine(ResourceMgr.GetString("A0010")); + Console.WriteLine(ResourceMgr.GetString("A0011")); + Console.WriteLine(""); + Console.WriteLine(ResourceMgr.GetString("A0012")); + Console.WriteLine(ResourceMgr.GetString("A0013")); + Console.WriteLine(ResourceMgr.GetString("A0014")); + Console.WriteLine(""); + Console.WriteLine(ResourceMgr.GetString("A0015")); + Console.WriteLine(ResourceMgr.GetString("A0016")); + Console.WriteLine(ResourceMgr.GetString("A0017")); + Console.WriteLine(""); + Console.WriteLine(ResourceMgr.GetString("A0018")); + Console.WriteLine(""); + // マニュフェスト ファイルの生成(#528) + Console.WriteLine(ResourceMgr.GetString("A0019")); + Console.WriteLine(ResourceMgr.GetString("A0020")); + Console.WriteLine(ResourceMgr.GetString("A0021")); + Console.WriteLine(ResourceMgr.GetString("A0022")); + Console.WriteLine(""); + // ZIP の生成(#528) + Console.WriteLine(ResourceMgr.GetString("A0025")); + Console.WriteLine(ResourceMgr.GetString("A0026")); + Console.WriteLine(ResourceMgr.GetString("A0027")); + Console.WriteLine(ResourceMgr.GetString("A0028")); + Console.WriteLine(ResourceMgr.GetString("A0029")); + Console.WriteLine(ResourceMgr.GetString("A0030")); + Console.WriteLine(ResourceMgr.GetString("A0031")); + + // コンソール デタッチ + Program.FreeConsole(); + + return; // 終了 + } + + // ZIP の生成(#528) + if (argsDic.ContainsKey("/ZIPGEN")) + { + // コンソール アタッチ + Program.AttachConsole(-1); + + Environment.ExitCode = Program.CreateZip(argsDic); + return; // 終了 + } + + // マニュフェスト ファイルの生成(#528) + if (argsDic.ContainsKey("/MFTGEN")) + { + // コンソール アタッチ + Program.AttachConsole(-1); + + Environment.ExitCode = Program.CreateManifesto(argsDic); + return; // 終了 + } + + // アンインストール + if (argsDic.ContainsKey("/UNINS")) + { + string url = argsDic["/UNINS"]; + + // 履歴をロード + Program.LoadHistories(); + + // 履歴の検索 + Entry history = null; + foreach (Entry entry in Program.Histories) + { + if (entry.WWWURL == url) + { + history = entry; + } + } + + if (history != null) + { + // 履歴を更新 + Program.Histories.Remove(history); + + // 履歴を保存 + Program.SaveHistories(); + + // インストール ディレクトリを削除 + if (Directory.Exists(history.InstallDir)) + { + Directory.Delete(history.InstallDir, true); + } + } + + return; + } + + // 起動の切り替え + if (argsDic.ContainsKey("/CUI")) + { + // 強制更新 + if (argsDic.ContainsKey("/FORCE")) + { + Program.IsForce = true; + + // 履歴ファイルを消去して実行 + File.Delete(Program.OrgCurrentDirectory + Program.HistoryFileName); + } + + // 起動アセンブリフラグ + if (argsDic.ContainsKey("/NB")) + { + Program.IsBoot = false; + } + + // CUI起動 + + // コンソール アタッチ + Program.AttachConsole(-1); + + //Program.OutPutMessage("CUI起動", LogLevel.InfoLog); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + Program.OutPutMessage(ResourceMgr.GetString("M0006"), LogLevel.InfoLog); + + if (argsDic.ContainsKey("/SILENT")) + { + // 進捗ダイアログ&メッセージなし + Program.CheckUpdateAndInstall_Silent(valsLst, argsDic); + } + else + { + // 進捗ダイアログ&メッセージあり + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form2(valsLst, argsDic)); + } + + // コンソール デタッチ + Program.FreeConsole(); + } + else if (0 < argsDic.Count) + { + // **引数があるのに、どのモードにも当たらなかった。** + // + // ここで GUI を開いてはいけない(#528)。 + // 非対話で呼ばれた場合、画面が出たまま応答を待ち続け、 + // 呼び出し側(CI や 3_SmokeTest.ps1)が停止する。 + // 綴りの誤りや、古いビルドで未実装のスイッチを渡したときに起きる。 + Program.AttachConsole(-1); + + Console.WriteLine(string.Format( + ResourceMgr.GetString("A0034"), + string.Join(" ", new List<string>(argsDic.Keys).ToArray()))); + + Program.FreeConsole(); + + Environment.ExitCode = 1; + } + else + { + // GUI起動 + //Program.OutPutMessage("GUI起動", LogLevel.InfoLog); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + Program.OutPutMessage(ResourceMgr.GetString("M00007"), LogLevel.InfoLog); + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } + } + + /// <summary>更新チェック&インストール(サイレントモード)</summary> + /// <param name="valsLst">値</param> + /// <param name="argsDic">コマンド・値</param> + public static void CheckUpdateAndInstall_Silent(List<string> valsLst, Dictionary<string, string> argsDic) + { + try + { + // エントリを生成 + Entry entry = new Entry(); + + // コマンドラインから各値を取得する。 + entry.WWWURL = Program.NullToEmptyString(argsDic, "/WWWURL"); + entry.WWWUID = Program.NullToEmptyString(argsDic, "/WWWUID"); + entry.WWWPWD = Program.NullToEmptyString(argsDic, "/WWWPWD"); + entry.WWWDomain = Program.NullToEmptyString(argsDic, "/WWWDOMAIN"); + //--- + entry.ProxyURL = Program.NullToEmptyString(argsDic, "/PROXYURL"); + entry.ProxyUID = Program.NullToEmptyString(argsDic, "/PROXYUID"); + entry.ProxyPWD = Program.NullToEmptyString(argsDic, "/PROXYPWD"); + entry.ProxyDomain = Program.NullToEmptyString(argsDic, "/PROXYDOMAIN"); + + // エントリを保存 + Program.SaveCurrent(entry); + + // 履歴をロード + Program.LoadHistories(); + + // 更新処理の実行 + Program.ExecUpdate(entry); + + // 履歴を保存 + Program.SaveHistories(); + } + catch (MyException my_ex) + { + // 戻し + Program.Recover(); + + // メッセージ表示時 + string message = my_ex.Message; + + // ログ出力用のフィールドがあるか?ないか? + if (string.IsNullOrEmpty(my_ex.ToLog)) + { + Program.OutPutMessage(message, LogLevel.InfoLog); + } + else + { + Program.OutPutMessage(message + "\r\n" + my_ex.ToLog, LogLevel.InfoLog); + } + } + catch (Exception ex) + { + // 戻し + Program.Recover(); + + // 例外発生時 + string message = ""; + + //message += "<メッセージ>\r\n"; + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + message += ResourceMgr.GetString("M0002")+"\r\n"; + message += ex.Message; + message += "\r\n"; + + message += "\r\n"; + //message += "<スタック トレース>\r\n"; + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + message += ResourceMgr.GetString("M0003")+"\r\n"; + message += ex.StackTrace; + message += "\r\n"; + + if (ex.InnerException != null) + { + message += "\r\n"; + //message += "<内部例外>\r\n"; + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + message += ResourceMgr.GetString("M0004")+"\r\n"; + message += ex.InnerException.ToString(); + message += "\r\n"; + } + + Program.OutPutMessage(message, LogLevel.ErrorLog); + } + finally + { + // テンポラリの削除 + File.Delete(Program.OrgCurrentDirectory + Program.TempMftFileName); + + // GCでZIPが解放される可能性 + //GC.Collect(); + Program.system_gc_collecting(); + try + { + File.Delete(Program.OrgCurrentDirectory + Program.TempZipFileName); + } + catch (Exception ex) + { + // 例外を潰してログに出力 + //Program.OutPutMessage(Program.TempZipFileName + "削除例外:" + ex.ToString(), LogLevel.ErrorLog); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + Program.OutPutMessage(Program.TempZipFileName + ResourceMgr.GetString("M0008") + ex.ToString(), LogLevel.ErrorLog); + } + } + } + + /// <summary>nullは空文字列に変換する</summary> + /// <param name="dic">ディクショナリ</param> + /// <param name="key">キー</param> + /// <returns>出力文字列(nullを含まない)</returns> + #region ZIP の生成(CUI) + + /// <summary>CUI(非対話)でZIPを生成する</summary> + /// <param name="argsDic">コマンドライン引数</param> + /// <returns>終了コード(0:正常、1:引数の誤り、2:生成の失敗)</returns> + /// <remarks> + /// GUI の「圧縮」タブと同じ処理を行う(#528)。 + /// **Form1 は表示しない。** UIコントロールは初期化のみ行われる。 + /// + /// <書庫内ルートの指定> + /// /ROOTINZIP あり … 指定名を書庫内ルートにする(GUI の「個別のフォルダ圧縮」) + /// /ROOTINZIP なし … 書庫内ルートを作らない(GUI の「ルート フォルダからの圧縮」) + /// </remarks> + private static int CreateZip(Dictionary<string, string> argsDic) + { + string srcDir = Program.NullToEmptyString(argsDic, "/SRCDIR"); + string zipFile = Program.NullToEmptyString(argsDic, "/ZIPFILE"); + + if (string.IsNullOrEmpty(srcDir) || string.IsNullOrEmpty(zipFile)) + { + Console.WriteLine(ResourceMgr.GetString("A0032")); + return 1; + } + + string rootInZip = Program.NullToEmptyString(argsDic, "/ROOTINZIP"); + bool topOnly = argsDic.ContainsKey("/TOPONLY"); + + // 除外拡張子 + string[] excludeExts = null; + string exts = Program.NullToEmptyString(argsDic, "/EXCLUDEEXT"); + if (!string.IsNullOrEmpty(exts)) { excludeExts = exts.Split(','); } + + // 文字コード(省略時は既定) + Encoding enc = null; + string encStr = Program.NullToEmptyString(argsDic, "/ENC"); + if (!string.IsNullOrEmpty(encStr)) { enc = Encoding.GetEncoding(encStr); } + + try + { + ZipEncryptionAlgorithmV2 cyp = ZipEncryptionAlgorithmV2.None; + string cypStr = Program.NullToEmptyString(argsDic, "/CYP"); + if (!string.IsNullOrEmpty(cypStr)) + { + cyp = (ZipEncryptionAlgorithmV2)Enum.Parse( + typeof(ZipEncryptionAlgorithmV2), cypStr, true); + } + + ZipCompressionLevelV2 cmpLv = ZipCompressionLevelV2.Default; + string cmpStr = Program.NullToEmptyString(argsDic, "/CMPLV"); + if (!string.IsNullOrEmpty(cmpStr)) + { + cmpLv = (ZipCompressionLevelV2)Enum.Parse( + typeof(ZipCompressionLevelV2), cmpStr, true); + } + + // 生成処理の呼び出し + // ※ Form1 は表示しない。UIコントロールは初期化のみ行われる。 + Form1 form1 = new Form1(); + int count = form1.Compress( + zipFile, srcDir, excludeExts, topOnly, rootInZip, + enc, cyp, Program.NullToEmptyString(argsDic, "/PASS"), cmpLv); + + Console.WriteLine(string.Format( + ResourceMgr.GetString("A0033"), zipFile + ".zip", count)); + return 0; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + return 2; + } + } + + #endregion + + #region マニュフェスト ファイルの生成(CUI) + + /// <summary>CUI(非対話)でマニュフェスト ファイルを生成する</summary> + /// <param name="argsDic">コマンドライン引数</param> + /// <returns>終了コード(0:正常、1:引数の誤り、2:生成の失敗)</returns> + /// <remarks> + /// GUI の「声明文作成」タブと同じ処理を行う(#528)。 + /// **Form1 は表示しない。** UIコントロールは初期化のみ行われる。 + /// </remarks> + private static int CreateManifesto(Dictionary<string, string> argsDic) + { + string zipFiles = Program.NullToEmptyString(argsDic, "/ZIPFILES"); + string insDir = Program.NullToEmptyString(argsDic, "/INSDIR"); + string exeName = Program.NullToEmptyString(argsDic, "/EXENAME"); + string mftFile = Program.NullToEmptyString(argsDic, "/MFTFILE"); + + if (string.IsNullOrEmpty(zipFiles) || string.IsNullOrEmpty(insDir) + || string.IsNullOrEmpty(exeName) || string.IsNullOrEmpty(mftFile)) + { + Console.WriteLine(ResourceMgr.GetString("A0023")); + return 1; + } + + // カンマ区切りを分割する。**前後の空白は落とす。** + // 引数を "a.zip, b.zip" のように書けるようにするため。 + List<string> zipFileLst = new List<string>(); + foreach (string zipFile in zipFiles.Split(',')) + { + if (!string.IsNullOrEmpty(zipFile.Trim())) + { + zipFileLst.Add(zipFile.Trim()); + } + } + + try + { + // 生成処理の呼び出し + // ※ Form1 は表示しない。UIコントロールは初期化のみ行われる。 + Form1 form1 = new Form1(); + form1.CreateManifesto(zipFileLst.ToArray(), insDir, exeName, mftFile); + + Console.WriteLine(string.Format(ResourceMgr.GetString("A0024"), mftFile)); + return 0; + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + return 2; + } + } + + #endregion + + public static string NullToEmptyString(Dictionary<string, string> dic, string key) + { + if (dic.ContainsKey(key)) + { + return dic[key]; + } + else + { + return ""; + } + } + + #region 更新処理 + + /// <summary>非同期フレームワーク</summary> + /// <remarks>進捗・メッセージ表示などで使用する</remarks> + public static MyBaseAsyncFunc Af { set; get; } + + /// <summary>更新処理</summary> + /// <param name="o">エントリ, Form1</param> + /// <returns>空のオブジェクト</returns> + /// <remarks>非同期処理から実行する</remarks> + public static object ExecUpdate(object o) + { + // フラグをクリア + Program.HaveBackup = false; + Program.InstallDirectory = ""; + Program.BackupDirectory = ""; + + // ワーク + Process p = null; + + // エントリを初期化 + Entry entry = (Entry)o; + + // マニュフェスト ファイル上に + // 存在するZIPファイルのリスト + List<string> existZipList = new List<string>(); + + #region 履歴エントリを取得 + + // 履歴エントリを取得 + Entry history = null; + foreach (Entry temp in Program.Histories) + { + if (entry.WWWURL == temp.WWWURL) + { + history = temp; + break; + } + } + + #endregion + + #region 主処理 + + // HEAD(Last-Modifiedチェック) + bool lmcRet = false; + + try + { + lmcRet = Program.LastModifiedCheck_ByHead(entry, history, ""); + } + catch (WebException wex) + { + // WebExceptionで、 + if (history != null) + { + // 履歴あり + + // 更新されていない + lmcRet = false; + + // ログ出力して起動(正常終了する) + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("E0009"), entry.WWWURL) + + "\r\n" + wex.ToString(), LogLevel.InfoLog); + } + else + { + // 履歴なし + + //// リスロー + //throw; + + // 例外(MyException) + throw new MyException(string.Format( + GetMessage.GetMessageDescription("E0009"), + entry.WWWURL), wex.ToString()); + } + + #region 消し + + // SocketExceptionだけ + // ハンドルしようと考えていたが・・・ + + //if (wex.InnerException != null) + //{ + // // InnerException:!= null + + // if (wex.InnerException is SocketException) + // { + // // InnerException:ソケット例外 + // if (history != null) + // { + // // 履歴あり + // // 更新されていない + // lmcRet = false; + // } + // else + // { + // // 履歴なし + // // リスロー + // throw; + // } + // } + // else + // { + // // InnerException:その他 + // // リスロー + // throw; + // } + //} + //else + //{ + // // InnerException:== null + // // リスロー + // throw; + //} + + #endregion + } + + if (!lmcRet) + { + // 更新されていない + // 履歴エントリはそのまま + + #region 起動のチェック + + // → 起動exeのキック(historyから) + if (Program.IsBoot) + { + // /NB スイッチが指定されていない。 + if (Program.ExistProcess(history.InstallDir, history.StartExe, out p)) + { + // プロセスが起動されていない。 + + if (File.Exists(p.StartInfo.FileName)) + { + // ファイルが存在する。 + + // 起動する。 + p.Start(); + + // 最前面へ + Program.SetWindowPos( + p.MainWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS); + } + else + { + // ファイルが存在しない。 + throw new Exception(string.Format( + GetMessage.GetMessageDescription("E0001"), p.StartInfo.FileName)); + } + } + else + { + // プロセスが起動されている。 + throw new MyException(string.Format( + GetMessage.GetMessageDescription("E0002"), p.StartInfo.FileName)); + } + } + else + { + // /NB スイッチが指定されている。 + Program.OutPutMessage(GetMessage.GetMessageDescription("I0012"), LogLevel.InfoLog); + } + + #endregion + } + else + { + // 更新されている + + // 画面表示を更新 + if (Program.Af != null) + { + // 開始(進捗20%) + Program.Af.ExecChangeProgress(new ChangeProgressParameter( + string.Format(GetMessage.GetMessageDescription("I0001"), entry.WWWURL), 20)); + } + + // マニュフェスト ファイルを取得 + // GET、Content保存 + Program.GetAndSaveContent(entry, ""); + + // マニュフェスト ファイルを読む + FileStream fs = null; + StreamReader sr = null; + StringReader manifesto = null; + + try + { + fs = new FileStream( + Program.OrgCurrentDirectory + + Program.TempMftFileName, FileMode.Open); + + sr = new StreamReader(fs); + manifesto = new StringReader(sr.ReadToEnd()); + } + finally + { + if (sr != null) { sr.Close(); } + if (fs != null) { fs.Close(); } + } + + try + { + #region マニュフェスト ファイルの処理 + + // ZIPファイルを + // ・更新チェック + // ・ダウンロード + // ・インストール + string line = ""; + + // インストール ディレクトリ + line = manifesto.ReadLine().Trim(); + if (string.IsNullOrEmpty(line) || line.Length <= 4) + { + // マニュフェスト ファイルの不正 + throw new Exception(string.Format( + GetMessage.GetMessageDescription("E0003"), line)); + } + else + { + if (line.Substring(0, 3) == "ins") + { + // エントリに追加 + entry.InstallDir = StringVariableOperator. + BuiltStringIntoEnvironmentVariable(line.Substring(4)); + } + else + { + // マニュフェスト ファイルの不正 + throw new Exception(string.Format( + GetMessage.GetMessageDescription("E0003"), line)); + } + } + + // インストール ディレクトリの変更には対応しない。 + if (history != null) + { + if (history.InstallDir != entry.InstallDir) + { + //throw new Exception(string.Format( + // GetMessage.GetMessageDescription("E0003"), string.Format( + // "インストール ディレクトリが変更されています{0}。", line))); + + //For internationalization, Replaced all the Japanese language to GetMessage.GetMessageDescription() method call + throw new Exception(string.Format( + GetMessage.GetMessageDescription("E0003"), string.Format( + GetMessage.GetMessageDescription("M0006"), line))); + } + } + + // 起動exe + line = manifesto.ReadLine().Trim(); + if (string.IsNullOrEmpty(line) || line.Length <= 4) + { + // マニュフェスト ファイルの不正 + throw new Exception(string.Format( + GetMessage.GetMessageDescription("E0003"), line)); + } + else + { + if (line.Substring(0, 3) == "exe") + { + // エントリに追加 + entry.StartExe = line.Substring(4); + } + else + { + // マニュフェスト ファイルの不正 + throw new Exception(string.Format( + GetMessage.GetMessageDescription("E0003"), line)); + } + } + + #endregion + + #region 起動のチェック + + if (Program.ExistProcess(entry.InstallDir, entry.StartExe, out p)) + { + // プロセスが起動されていない。→ 処理続行 + } + else + { + // プロセスが起動されている。→ 処理中止 + throw new MyException(string.Format( + GetMessage.GetMessageDescription("E0002"), p.StartInfo.FileName)); + } + + #endregion + + // 読み取り専用属性の全削除 + Program.RemoveReadonlyAttribute( + new DirectoryInfo(entry.InstallDir)); + + // 強制モードでは一度削除してから + if (Program.IsForce) + { + // 存在チェックを追加 + if (Directory.Exists(entry.InstallDir)) + { + Directory.Delete(entry.InstallDir, true); + } + } + + #region ZIPファイルのDL & Ins + + // ZIPファイル + line = manifesto.ReadLine(); + if (!string.IsNullOrEmpty(line)) + { + line.Trim(); + } + + string zipFile = ""; + bool isUpdated = false; + + while (true) + { + if (string.IsNullOrEmpty(line)) + { + // 終了 + break; + } + else if (line.Length <= 4) + { + // マニュフェスト ファイルの不正 + throw new Exception(string.Format( + GetMessage.GetMessageDescription("E0003"), line)); + } + else + { + if (line.Substring(0, 3) == "zip") + { + zipFile = line.Substring(4); + + if (zipFile.Length > 4 && + zipFile.Substring(zipFile.Length - 4, 4) == ".zip") + { + // エントリに追加 + entry.ZipFiles.Add(zipFile); + + // マニュフェスト ファイル上に + // 存在するZIPファイルを保存 + existZipList.Add(zipFile); + + // 画面表示を更新 + if (Program.Af != null) + { + // ZIPを確認(進捗+8%) + Program.Af.ExecChangeProgress(new ChangeProgressParameter( + string.Format(GetMessage.GetMessageDescription("I0001"), zipFile), 8)); + } + + // HEAD(Last-Modifiedチェック) + if (Program.LastModifiedCheck_ByHead(entry, history, zipFile)) + { + // GET、Content保存 + Program.GetAndSaveContent(entry, zipFile); + + // ステータス変更 + isUpdated = true; + } + else + { + // ステータス変更 + isUpdated = false; + } + } + else + { + // 例外(.ZIPじゃない) + throw new Exception(GetMessage.GetMessageDescription("E0004") + zipFile); + } + } + else if (line.Substring(0, 3) == "md5") + { + // HEAD(Last-Modifiedチェック) + if (isUpdated) + { + string md5HashMft = line.Substring(4); + string md5HashCur = Program.GetMD5Hash( + Program.OrgCurrentDirectory + Program.TempZipFileName); + + if (md5HashMft == md5HashCur) + { + // 指定の位置にインストール + // (必要な履歴の情報を引き継ぐ) + Program.InstallZip(entry, zipFile, history, "utf-8"); + } + else + { + // 例外(MD5ハッシュの不一致) + throw new MyException(string.Format( + GetMessage.GetMessageDescription("E0005"), + zipFile, md5HashMft, md5HashCur)); + } + } + else + { + // 更新されていない + //(必要な履歴の情報を引き継ぐ) + entry.HttpZipLastModified[zipFile] = history.HttpZipLastModified[zipFile]; + entry.HttpZipContents[zipFile] = history.HttpZipContents[zipFile]; + // メッセージ(HeadAndLastModifiedで済み) + } + } + else + { + //// 終了 + //break; + + // マニュフェスト ファイルの不正 + throw new Exception(string.Format( + GetMessage.GetMessageDescription("E0003"), line)); + } + } + + // 次へ + line = manifesto.ReadLine(); + if (!string.IsNullOrEmpty(line)) + { + line.Trim(); + } + } + } + finally + { + // クローズ(エラーになるので) + manifesto.Close(); + } + + #endregion + + // 画面表示を更新 + if (Program.Af != null) + { + // 終了(進捗-%)→最後に強制的に100%になる。 + Program.Af.ExecChangeProgress( + new ChangeProgressParameter( + GetMessage.GetMessageDescription("I0002"), 1)); + } + + #region 履歴エントリを保存 + + // 履歴を置き換える。 + for (int i = 0; i < Program.Histories.Count; i++) + { + if (Program.Histories[i].WWWURL == entry.WWWURL) + { + Program.Histories[i] = entry; + } + } + + if (history == null) + { + // 新規のエントリの場合だけ、 + // エントリを履歴に追加する。 + Program.Histories.Add(entry); + + // メッセージ + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("I0003"), entry.WWWURL), LogLevel.InfoLog); + } + else + { + // 旧エントリの場合だけ、 + // 無くなったZIPファイルを削除する。 + foreach (string zip1 in history.ZipFiles) + { + // 使ってないフラグ + bool isUnused = true; + + // 使ってないチェック + foreach (string zip2 in existZipList) + { + if (zip1 == zip2) + { + // ZIPファイルを使いました。 + isUnused = false; + } + } + + // このZIPファイルを使っていない。 + if (isUnused) + { + // ZIPファイル内のコンテンツを削除 + Program.DeleteZipContents(zip1, history); + + // ZIPファイルの情報を消す。 + entry.ZipFiles.Remove(zip1); + entry.HttpZipContents.Remove(zip1); + entry.HttpZipLastModified.Remove(zip1); + + // メッセージ + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("I0004"), zip1), LogLevel.InfoLog); + } + } + + // メッセージ + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("I0005"), entry.WWWURL), LogLevel.InfoLog); + } + + #endregion + + #region 起動のチェック + + // → 起動exeのキック(entryから) + if (Program.IsBoot) + { + // /NB スイッチが指定されていない。 + if (Program.ExistProcess(entry.InstallDir, entry.StartExe, out p)) + { + // プロセスが起動されていない。 + + if (File.Exists(p.StartInfo.FileName)) + { + // ファイルが存在する。 + + // バックアップ・ディレクトリを削除 + Program.DeleteBackupDirectory(); + + // 起動する。 + p.Start(); + + // 最前面へ + Program.SetWindowPos( + p.MainWindowHandle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS); + } + else + { + // ファイルが存在しない。 + throw new Exception(string.Format( + GetMessage.GetMessageDescription("E0001"), p.StartInfo.FileName)); + } + } + else + { + // プロセスが起動されている。 + throw new MyException(string.Format( + GetMessage.GetMessageDescription("E0002"), p.StartInfo.FileName)); + } + } + else + { + // バックアップ・ディレクトリを削除 + Program.DeleteBackupDirectory(); + + // /NB スイッチが指定されている。 + Program.OutPutMessage(GetMessage.GetMessageDescription("I0012"), LogLevel.InfoLog); + } + + #endregion + } + + #endregion + + return new object(); + } + + /// <summary>バックアップ・ディレクトリを削除</summary> + private static void DeleteBackupDirectory() + { + if (Program.HaveBackup) + { + // インストール済み。 + Directory.Delete(Program.BackupDirectory, true); + } + } + + /// <summary>プロセススタートのためのオブジェクトを返す</summary> + /// <param name="installDir">インストール ディレクトリ</param> + /// <param name="exeFiles">起動EXE名のカンマ区切りリスト</param> + /// <param name="p">プロセス</param> + /// <returns> + /// 真:当該EXEは起動されていない。 + /// 偽:当該EXEは起動されている。 + /// </returns> + private static bool ExistProcess(string installDir, string exeFiles, out Process p) + { + // 分割する。 + string[] ary_exeFiles = exeFiles.Split(','); + + // パスに変換 + for (int i = 0; i < ary_exeFiles.Length; i++) + { + // プレーンな連結のみサポート + ary_exeFiles[i] = installDir + ary_exeFiles[i].Trim(); + } + + // プロセスを生成 + p = new Process(); + + // 二重起動のチェック + foreach (Process pp in System.Diagnostics.Process.GetProcesses()) + { + try + { + for (int i = 0; i < ary_exeFiles.Length; i++) + { + // ToUpper! + if (ary_exeFiles[i].ToUpper() == pp.MainModule.FileName.ToUpper()) + { + // 起動されている。 + p.StartInfo = new ProcessStartInfo(ary_exeFiles[i]); + return false; + } + } + } + catch + { + // アクセス違反をつぶす。 + } + } + + // 起動されていない。 + p.StartInfo = new ProcessStartInfo(ary_exeFiles[0]); + return true; + } + + #endregion + + #region 共通関数 + + #region ファイルIO + + #region セーブ + + /// <summary>ファイルにセーブ</summary> + /// <param name="obj">オブジェクト</param> + /// <param name="filePath">ファイル パス</param> + /// <remarks> + /// 2026/08/08 まで BinarySerialize(BinaryFormatter)を使っていた(#528)。 + /// **.NET 9 以降で BinaryFormatter が削除された**ため JSON に替えた + /// (Public_netcore100.csproj は IO\BinarySerialize.cs を Compile Remove している)。 + /// + /// 保存先は current.json / histories.json。**旧 .bin は読まない。** + /// 中身は画面の入力値と接続先の履歴だけで、失われても入れ直せばよいため。 + /// </remarks> + public static void SaveFile(object obj, string filePath) + { + File.WriteAllText(filePath, + JsonConvert.SerializeObject(obj, Formatting.Indented), Encoding.UTF8); + } + + /// <summary>ファイルからロード(JSON)</summary> + /// <typeparam name="T">オブジェクトの型</typeparam> + /// <param name="filePath">ファイル パス</param> + /// <returns>オブジェクト(ファイルが無ければ既定値)</returns> + public static T LoadJsonFile<T>(string filePath) + { + if (!File.Exists(filePath)) { return default(T); } + + string json = File.ReadAllText(filePath, Encoding.UTF8); + if (string.IsNullOrEmpty(json)) { return default(T); } + + return JsonConvert.DeserializeObject<T>(json); + } + + #endregion + + #region ロード + + /// <summary>ファイルをロード</summary> + /// <param name="filePath">ファイル パス</param> + /// <returns>バイト配列</returns> + public static byte[] LoadFile(string filePath) + { + byte[] ret = null; + FileStream fs = null; + MemoryStream ms = null; + + try + { + // ファイル入力をバイナリ デシリアライズ + if (File.Exists(filePath)) + { + fs = new FileStream(filePath, + FileMode.Open, FileAccess.Read); + + ms = new MemoryStream(); + byte[] buffer = new byte[0x1000]; // 4KB + + for (; ; ) + { + // ファイルの一部を読み込む + int readSize = fs.Read(buffer, 0, buffer.Length); + + // ファイルをすべて読み込んだときは終了する + if (readSize == 0) { break; } + + // マージ + // + // 2026/08/08 まで buffer.Length を渡していたため、 + // **最後のブロックで読めなかった分まで 0 で埋めていた**(#528)。 + // ファイル サイズが 4KB の倍数でないと、末尾に余計な 0 が付く。 + ms.Write(buffer, 0, readSize); + } + + // オブジェクト化して設定 + ret = ms.ToArray(); + } + } + finally + { + // 閉じる + if (ms != null) { ms.Close(); } + if (fs != null) { fs.Close(); } + } + + // 戻す。 + return ret; + } + + #endregion + + #region Current + + /// <summary>current.binのLoad処理</summary> + /// <returns>Entry(前回入力)</returns> + public static Entry LoadCurrent() + { + return Program.LoadJsonFile<Entry>( + Program.OrgCurrentDirectory + Program.CurrentFileName); + } + + /// <summary>current.binのSave処理</summary> + /// <param name="entry">Entry(現状入力)</param> + public static void SaveCurrent(Entry entry) + { + Program.SaveFile(entry, + Program.OrgCurrentDirectory + Program.CurrentFileName); + } + + #endregion + + #region Histories + + /// <summary>histories.binのLoad処理</summary> + /// <returns>List<Entry>(履歴)</returns> + public static List<Entry> LoadHistories() + { + Program.Histories = + Program.LoadJsonFile<List<Entry>>( + Program.OrgCurrentDirectory + Program.HistoryFileName) + ?? new List<Entry>(); + + // 設定しつつ戻す + return Program.Histories; + } + + /// <summary>histories.binのSave処理</summary> + public static void SaveHistories() + { + Program.SaveFile(Program.Histories, Program.OrgCurrentDirectory + Program.HistoryFileName); + } + + #endregion + + #region 読み取り専用属性の削除 + + /// <summary>削除処理の追加</summary> + /// <param name="di">DirectoryInfo</param> + /// <remarks> + /// DOBON.NET > ファイル、フォルダ + /// 読み取り専用ファイルがあるときでもフォルダを削除する + /// http://dobon.net/vb/dotnet/file/deletedirectory.html + /// </remarks> + public static void RemoveReadonlyAttribute(DirectoryInfo di) + { + if (di.Exists) + { + // 存在する場合 + + // 当該フォルダ(読み取り専用属性の削除) + if ((di.Attributes & FileAttributes.ReadOnly) + == FileAttributes.ReadOnly) + { + di.Attributes = FileAttributes.Normal; + } + + // フォルダ内のすべてのファイル + // (読み取り専用属性の削除) + foreach (FileInfo fi in di.GetFiles()) + { + if ((fi.Attributes & FileAttributes.ReadOnly) + == FileAttributes.ReadOnly) + { + fi.Attributes = FileAttributes.Normal; + } + } + + // 回帰 + foreach (DirectoryInfo child_di in di.GetDirectories()) + { + Program.RemoveReadonlyAttribute(child_di); + } + } + } + + #endregion + + #region ZIPファイル内のコンテンツの削除 + + /// <summary>ZIPファイル内のコンテンツの削除</summary> + /// <param name="zipFile">ZIPファイル名</param> + /// <param name="history">エントリ(履歴)</param> + private static void DeleteZipContents(string zipFile, Entry history) + { + if (history != null) + { + // 履歴情報があれば、過去の解凍コンテンツを削除する。 + if (history.HttpZipContents.ContainsKey(zipFile)) + { + // ファイルパスを取得してコンテンツを削除 + foreach (string contentFile in history.HttpZipContents[zipFile]) + { + // 存在チェック + if (File.Exists(contentFile)) + { + // 存在しなくても例外を返さない。 + // ・・・と言いつつパスが + // 存在しないと例外となる。 + // ※ オープン状態では例外になる。 + try + { + File.Delete(contentFile); + } + catch + { + // 例外(オープン状態) + throw new MyException(string.Format( + GetMessage.GetMessageDescription("E0006"), contentFile)); + } + } + } + } + } + } + + #endregion + + #region 戻し操作 + + /// <summary>戻し操作</summary> + public static void Recover() + { + // バックアップが存在すれば、戻し操作を実行。 + if (Program.HaveBackup) + { + // 戻しを実行 + Program.OutPutMessage( + GetMessage.GetMessageDescription("E0008"), LogLevel.InfoLog); + + // 消す + Program.DeleteAllFile( + Program.InstallDirectory); + + // 戻す + Program.CreateMirror( + Program.BackupDirectory, + Program.InstallDirectory); + + // 退避ディレクトリを消去 + Program.DeleteBackupDirectory(); + } + } + + /// <summary> + /// すべてのファイルを消去する。 + /// ディレクトリは残して、例外はつぶす。 + /// </summary> + /// <param name="path">パス</param> + private static void DeleteAllFile(string path) + { + // パスの存在チェック + if (Directory.Exists(path)) + { + // ファイルを全消しして + string[] files = Directory.GetFiles(path); + foreach (string file in files) + { + try + { + File.Delete(file); + } + catch + { + // 例外は潰す + } + } + + // ディレクトリを再起処理 + string[] directories = Directory.GetDirectories(path); + foreach (string directory in directories) + { + Program.DeleteAllFile(directory); + } + } + } + + /// <summary>ミラーを作成する。</summary> + /// <param name="src">退避したディレクトリ</param> + /// <param name="dst">インストール ディレクトリ</param> + private static void CreateMirror(string src, string dst) + { + // パスの存在チェック + if (Directory.Exists(src)) + { + // ファイルをコピー + string[] files = Directory.GetFiles(src); + + // コピー先のディレクトリがなければ作成 + if (!Directory.Exists(dst)) + { + Directory.CreateDirectory(dst); + } + + // コピー + foreach (string file in files) + { + try + { + string[] temp = file.Split('\\'); + string fileName = temp[temp.Length - 1]; + + string dstFile = ""; + if (dst[dst.Length - 1] == '\\') + { + dstFile = dst + fileName; + } + else + { + dstFile = dst + "\\" + fileName; + } + + File.Copy(file, dstFile); + } + catch + { + // 例外は潰す + } + } + + // ディレクトリを再起処理 + string[] directories = Directory.GetDirectories(src); + foreach (string directory in directories) + { + Program.CreateMirror(directory, directory.Replace(src, dst)); + } + } + } + + #endregion + + #endregion + + #region MD5ハッシュ + + /// <summary>MD5ハッシュ値のBase64文字列を取得する。</summary> + /// <param name="FilePath">ファイル パス</param> + /// <returns>MD5ハッシュ値のBase64文字列</returns> + public static string GetMD5Hash(string FilePath) + { + // 暗号化サービスプロバイダ + // MD5CryptoServiceProviderサービスプロバイダ + HashAlgorithm ha = new MD5CryptoServiceProvider(); + + // ハッシュ値を計算する + return CustomEncode.ToBase64String( + ha.ComputeHash(Program.LoadFile(FilePath))); + } + + #endregion + + #region HTTP系メソッド + + #region HEAD + + /// <summary>HEAD(Last-Modifiedチェック)</summary> + /// <param name="entry">エントリ</param> + /// <param name="history">エントリ(履歴)</param> + /// <param name="zipFile">ZIPファイル</param> + /// <returns> + /// true:更新あり、DLへ(インスコ) + /// false:更新なし、次へ(パス) + /// </returns> + public static bool LastModifiedCheck_ByHead(Entry entry, Entry history, string zipFile) + { + HttpWebRequest hwReq = null; + HttpWebResponse hwRes = null; + + try + { + hwReq = Program.GetHttpWebRequest(entry, zipFile); + hwReq.Timeout = 5000; + hwReq.Method = "HEAD"; + hwRes = (HttpWebResponse)hwReq.GetResponse(); + + // 更新日付のチェック + string httpLastModifiedHis = ""; + string httpLastModifiedWeb = hwRes.LastModified.ToString( + "yyyy-MM-dd HH:mm:ss:fff"); //.Headers["Last-Modified"]; + + if (httpLastModifiedWeb == null && httpLastModifiedWeb == "") + { + // 更新日付ヘッダなし + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("I0006"), hwReq.RequestUri.AbsoluteUri), LogLevel.InfoLog); + } + else + { + // 更新日付の更新 + if (string.IsNullOrEmpty(zipFile)) + { + // マニュフェスト ファイルの場合 + entry.HttpLastModified = httpLastModifiedWeb; + } + else + { + // ZIPファイルの場合 + entry.HttpZipLastModified[zipFile] = httpLastModifiedWeb; + } + + // 履歴エントリの更新日付の履歴をチェックする。 + if (history != null) + { + // 履歴あり + + if (string.IsNullOrEmpty(zipFile)) + { + // マニュフェスト ファイルの場合 + httpLastModifiedHis = history.HttpLastModified; + } + else + { + // ZIPファイルの場合 + // 無い場合があるので + if (history.HttpZipLastModified.ContainsKey(zipFile)) + { + httpLastModifiedHis = history.HttpZipLastModified[zipFile]; + } + else + { + // NullOrEmptyにしない + //(↓の更新日付ヘッダの不一致へ) + httpLastModifiedHis = "xxx"; + } + } + + // 更新日付の履歴あり + if (!string.IsNullOrEmpty(httpLastModifiedHis)) + { + if (httpLastModifiedHis == httpLastModifiedWeb) + { + // 更新日付ヘッダの一致 + + // メッセージ + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("I0007"), hwReq.RequestUri.AbsoluteUri), LogLevel.InfoLog); + + // → パス + return false; + } + else + { + // 更新日付ヘッダの不一致(大小の評価ではない!) + + // メッセージ + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("I0008"), hwReq.RequestUri.AbsoluteUri), LogLevel.InfoLog); + } + } + } + else + { + // 履歴なし + + // メッセージ + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("I0009"), hwReq.RequestUri.AbsoluteUri), LogLevel.InfoLog); + } + } + + // → インスコ + return true; + } + finally + { + // 閉じる(これが無いと2回目実行できない。) + if (hwRes != null) { hwRes.Close(); } + if (hwReq != null) { hwReq.Abort(); } + } + } + + #endregion + + #region GET + + /// <summary>ファイルを取得</summary> + /// <param name="entry">エントリ</param> + /// <param name="zipFile">ZIPファイル</param> + public static void GetAndSaveContent(Entry entry, string zipFile) + { + HttpWebRequest hwReq = null; + HttpWebResponse hwRes = null; + + try + { + hwReq = Program.GetHttpWebRequest(entry, zipFile); + hwReq.Timeout = 5000; + hwReq.Method = "GET"; + hwRes = (HttpWebResponse)hwReq.GetResponse(); + + if (hwRes.ContentLength != -1) + { + Stream sm = null; + FileStream fs = null; + + try + { + // 応答データを受信するためのStreamを取得 + sm = hwRes.GetResponseStream(); + + // ファイルに書き込むためのFileStreamを作成 + string saveFileName = ""; + + if (string.IsNullOrEmpty(zipFile)) + { + // マニュフェスト + saveFileName = Program.TempMftFileName; + } + else + { + // ZIPファイル + saveFileName = Program.TempZipFileName; + } + + fs = new FileStream( + Program.OrgCurrentDirectory + saveFileName, FileMode.Create, FileAccess.Write); + + // 応答データをファイルに書き込む + int b; + while ((b = sm.ReadByte()) != -1) + { + fs.WriteByte(Convert.ToByte(b)); + } + + // メッセージ + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("I0010"), hwReq.RequestUri.AbsoluteUri), LogLevel.InfoLog); + } + finally + { + // 閉じる + if (fs != null) { fs.Close(); } + if (sm != null) { sm.Close(); } + } + } + } + finally + { + // 閉じる(これが無いと2回目実行できない。) + if (hwRes != null) { hwRes.Close(); } + if (hwReq != null) { hwReq.Abort(); } + } + } + + #endregion + + #region new HttpWebRequest + + /// <summary>HttpWebRequestを取得する。</summary> + /// <param name="entry">エントリ</param> + /// <param name="zipFile">ZIPファイル名</param> + /// <returns>HttpWebRequest</returns> + public static HttpWebRequest GetHttpWebRequest(Entry entry, string zipFile) + { + string zipURL = entry.WWWURL; + HttpWebRequest hwReq = null; + + if (!string.IsNullOrEmpty(zipFile)) + { + // ファイル指定がされている場合。 + // マニュフェスト ファイルを・・・ + string[] temp = zipURL.Split('/'); + for (int i = 0; i < temp.Length - 1; i++) + { + if (i == 0) + { + zipURL = temp[i]; + } + else + { + zipURL += "/" + temp[i]; + } + } + + // ZIPファイルに置き換える。 + zipURL += "/" + zipFile; + } + + // リクエストを生成する。 + hwReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(zipURL)); + + // WWWサーバのNetworkCredential + if (entry.WWWUID == null && entry.WWWUID == "") + { + // NetworkCredentialなし(デフォルト) + //hwReq.UseDefaultCredentials = true;// ★要・検討 + } + else + { + // NetworkCredentialあり + if (entry.WWWDomain == null || entry.WWWDomain == "") + { + // UID、PWD + hwReq.Credentials = new NetworkCredential( + entry.WWWUID, entry.WWWPWD); + } + else + { + // UID、PWD、Domain + hwReq.Credentials = new NetworkCredential( + entry.WWWUID, entry.WWWPWD, entry.WWWDomain); + } + } + + // プロキシ使うか? + WebProxy proxy = null; + + // Proxyサーバ + if (entry.ProxyURL.ToLower() == "none") + { + // Proxyサーバなし(null) + hwReq.Proxy = null; + + // ※ GlobalProxySelection.GetEmptyWebProxy()は古い形式 + } + else if (entry.ProxyURL == null || entry.ProxyURL == "") + { + // proxy = (WebProxy)WebProxy.GetDefaultProxy();// 古い形式 + // 何もしない → DefaultWebProxyプロパティの値を使用する。 + } + else + { + // Proxyサーバあり + proxy = new WebProxy(new Uri(entry.ProxyURL)); + } + + // Proxyサーバがあれば + if (proxy != null) + { + // NetworkCredentialがあれば + if (entry.ProxyUID == null || entry.ProxyUID == "") + { + // NetworkCredentialなし(デフォルト) + proxy.UseDefaultCredentials = true;// ★要・検討 + } + else + { + // NetworkCredentialあり + if (entry.ProxyDomain == null || entry.ProxyDomain == "") + { + // UID、PWD + proxy.Credentials = new NetworkCredential( + entry.ProxyUID, entry.ProxyPWD); + } + else + { + // UID、PWD、Domain + proxy.Credentials = new NetworkCredential( + entry.ProxyUID, entry.ProxyPWD, entry.ProxyDomain); + } + } + + // プロキシ設定 + hwReq.Proxy = proxy; + } + + return hwReq; + } + + #endregion + + #endregion + + #region インストール + + /// <summary>ZIPファイルをインストール</summary> + /// <param name="entry">エントリ</param> + /// <param name="zipFile">ZIPファイル名</param> + /// <param name="history">エントリ(履歴)</param> + /// <param name="encStr">エンコーディング</param> + public static void InstallZip(Entry entry, string zipFile, Entry history, string encStr) + { + if (Program.HaveBackup) + { + // バックアップ済み。 + } + else + { + if (Directory.Exists(entry.InstallDir)) + { + // インストール先を指定 + Program.InstallDirectory = entry.InstallDir; + + // バックアップ先を指定 + string guid = Guid.NewGuid().ToString(); + if (entry.InstallDir[entry.InstallDir.Length - 1] == '\\') + { + Program.BackupDirectory = + entry.InstallDir.Substring( + 0, entry.InstallDir.Length - 1) + "_" + guid; + } + else + { + Program.BackupDirectory = entry.InstallDir + "_" + guid; + } + + // バックアップする。 + Program.HaveBackup = true; + FileSystem.CopyDirectory(entry.InstallDir, BackupDirectory, UIOption.OnlyErrorDialogs, UICancelOption.DoNothing); + } + } + + // ZIPファイル内のコンテンツを削除 + Program.DeleteZipContents(zipFile, history); + + // 環境変数に対応 + string InsDir = StringVariableOperator. + BuiltStringIntoEnvironmentVariable(entry.InstallDir); + + // 解凍 + + // 解凍部品 + UnZipperV2 uz = new UnZipperV2(); + + // 選択基準なしで + string[] exts = null; + ZipBaseV2.SelectionDelegate scd = null; + + //if (this.txtExt.Enabled) + //{ + // exts = this.txtExt.Text.Split(','); + // scd = SelectionCriteriaDlgt2; + //} + + // 解凍時、上書き制御 + uz.ExtractProgress = Program.MyExtractProgressEventHandler; + + // 解凍:デリゲートでフィルタ + uz.ExtractFileFromZip( + Program.OrgCurrentDirectory + Program.TempZipFileName, + StringVariableOperator.BuiltStringIntoEnvironmentVariable(entry.InstallDir), + scd, exts, ExtractExistingFileActionV2.OverwriteSilently, + Encoding.GetEncoding(encStr), ""); + + // メッセージ + Program.OutPutMessage(string.Format( + GetMessage.GetMessageDescription("I0011"), zipFile), LogLevel.InfoLog); + + // 解凍先のファイルのパスを保存する(次回の削除処理に使用)。 + // + // 2026/08/08 まで、DotNetZip が吐くログ(StatusMSG)の + // extract file <パス>[...] + // という行を文字列で切り出して集めていた(#528)。 + // ログの文言に依存しており、ライブラリを替えると必ず壊れる作りだった。 + // UnZipperV2 は解凍したパスをそのまま返すため、解析は要らない。 + entry.HttpZipContents[zipFile] = uz.ExtractedFiles; + } + + #endregion + + #region デリゲート + + #region 選択基準デリゲート + + /// <summary>選択基準を実装するデリゲート</summary> + /// <param name="o">ファイル・エントリ情報</param> + /// <param name="info">選択規準情報</param> + /// <returns> + /// 真:ファイルを書庫に追加する。 + /// 偽:ファイルを書庫に追加しない。 + /// </returns> + /// <summary>選択基準を実装するデリゲート(直下のファイルだけ+除外拡張子)</summary> + /// <param name="o">ファイル(FileInfo)</param> + /// <param name="info">object[] { 対象フォルダ, 除外拡張子(string[] または null) }</param> + /// <returns>圧縮するならtrue</returns> + /// <remarks> + /// `/ZIPGEN /TOPONLY` 用(#528)。 + /// **ZipperV2 は再帰を止められない。** 走査自体は行われるので、 + /// 「対象フォルダの直下にあるか」で選び分けて、実質的に再帰を無効にする。 + /// </remarks> + public static bool SelectionCriteriaDlgt3(object o, object info) + { + FileInfo f = (FileInfo)o; + + object[] ary = (object[])info; + string dir = (string)ary[0]; + string[] exts = (string[])ary[1]; + + // 直下でなければ対象外 + if (!string.Equals( + Path.GetFullPath(f.DirectoryName).TrimEnd(Path.DirectorySeparatorChar), + Path.GetFullPath(dir).TrimEnd(Path.DirectorySeparatorChar), + StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + // 除外拡張子 + return Program.SelectionCriteriaDlgt1(f, exts); + } + + public static bool SelectionCriteriaDlgt1(object o, object info) + { + FileInfo f = (FileInfo)o; + + // 選択規準情報(文字列配列)の + // 指定が無い場合は、全て[true] + + if (info == null) + { + return true; + } + + // 選択規準情報(文字列配列)の + // 指定がある場合は、[true], [false]か判別 + + string[] exts = (string[])info; + foreach (string ext in exts) + { + if (f.Extension == "." + ext.Trim()) + { + return false; + } + } + + return true; + } + + /// <summary>選択基準を実装するデリゲート</summary> + /// <param name="o">ファイル・エントリ情報</param> + /// <param name="info">選択規準情報</param> + /// <returns> + /// 真:ファイルを書庫に追加する。 + /// 偽:ファイルを書庫に追加しない。 + /// </returns> + public static bool SelectionCriteriaDlgt2(object o, object info) + { + string fileName = (string)o; + + // 選択規準情報(文字列配列)の + // 指定が無い場合は、全て[true] + + if (info == null) + { + return true; + } + + // 選択規準情報(文字列配列)の + // 指定がある場合は、[true], [false]か判別 + + string[] exts = (string[])info; + foreach (string ext in exts) + { + string[] aryStr = fileName.Split('.'); // 修正 + if (aryStr[aryStr.Length - 1] == ext.Trim()) + { + return false; + } + } + + return true; + } + + #endregion + + #region 組込デリゲート + + /// <summary>セーブ処理の進捗表示デリゲート</summary> + public static void MySaveProgressEventHandler(Object sender, ZipProgressEventArgsV2 e) + { + if (e.EventType == ZipProgressEventTypeV2.Saving_Started) + { + // 書庫の作成を開始 + //Debug.WriteLine(string.Format("{0} の作成開始", e.ArchiveName)); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + Debug.WriteLine(string.Format(ResourceMgr.GetString("I0001"), e.ArchiveName)); + } + else if (e.EventType == ZipProgressEventTypeV2.Saving_BeforeWriteEntry) + { + // エントリの書き込み開始 + //Debug.WriteLine(string.Format("{0} の書き込み開始", e.CurrentEntryName)); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + Debug.WriteLine(string.Format(ResourceMgr.GetString("I0002"), e.CurrentEntryName)); + } + else if (e.EventType == ZipProgressEventTypeV2.Saving_EntryBytesRead) + { + // エントリを書き込み中 + //Debug.WriteLine(string.Format("{0}/{1} バイト 書き込みました", e.BytesTransferred, e.TotalBytesToTransfer)); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + Debug.WriteLine(string.Format(ResourceMgr.GetString("I0003"), e.BytesTransferred, e.TotalBytesToTransfer)); + } + else if (e.EventType == ZipProgressEventTypeV2.Saving_AfterWriteEntry) + { + // エントリの書き込み終了 + //Debug.WriteLine(string.Format("{0} の書き込み終了", e.CurrentEntryName)); + //Debug.WriteLine(string.Format("{0} 個中 {1} 個のエントリの書き込みが完了しました", e.EntriesTotal, e.EntriesProcessed)); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + Debug.WriteLine(string.Format(ResourceMgr.GetString("I0004"), e.CurrentEntryName)); + Debug.WriteLine(string.Format(ResourceMgr.GetString("I0005"), e.EntriesTotal, e.EntriesProcessed)); + + } + else if (e.EventType == ZipProgressEventTypeV2.Saving_Completed) + { + // 書庫の作成が完了 + //Debug.WriteLine(string.Format("{0} の作成終了", e.ArchiveName)); + + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + Debug.WriteLine(string.Format(ResourceMgr.GetString("I0006"), e.ArchiveName)); + } + } + + /// <summary>上書き確認デリゲート</summary> + public static void MyExtractProgressEventHandler(Object sender, ZipProgressEventArgsV2 e) + { + if (e.EventType == ZipProgressEventTypeV2.Extracting_ExtractEntryWouldOverwrite) + { + // 問い合わせでなければ、既に「上書きしない」と決まっている(通知のみ)。 + if (!e.IsQuery) { return; } + + // 展開するファイル名 + string filePath = Path.Combine( + e.ExtractLocation, e.CurrentEntryName.Replace('/', '\\')); + + // ダイアログを表示する + //DialogResult res = MessageBox.Show( + // "'" + filePath + "'はすでに存在します。\r\n" + + // "'はい'で上書き 'いいえ'で何もしない 'キャンセル'で中止", + // "上書きの確認", + // MessageBoxButtons.YesNoCancel, + // MessageBoxIcon.Question); + + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + DialogResult res = MessageBox.Show( + "'" + filePath + ResourceMgr.GetString("M0009")+ "\r\n" + + ResourceMgr.GetString("M0010"), + ResourceMgr.GetString("M0011"), + MessageBoxButtons.YesNoCancel, + MessageBoxIcon.Question); + + if (res == DialogResult.Yes) + { + // 上書きする + e.ExtractExistingFile = + ExtractExistingFileActionV2.OverwriteSilently; + } + else if (res == DialogResult.No) + { + // 上書きしない + e.ExtractExistingFile = + ExtractExistingFileActionV2.DoNotOverwrite; + } + else if (res == DialogResult.Cancel) + { + // 展開を中止する + e.Cancel = true; + } + } + } + + #endregion + + #endregion + + #region メッセージ表示 + + /// <summary>メッセージを表示する。</summary> + /// <param name="message">メッセージ</param> + /// <param name="lb">ログ・レベル</param> + public static void OutPutMessage(string message, LogLevel lb) + { + Debug.WriteLine(message); + Console.WriteLine(message); + + switch (lb) + { + case LogLevel.DebugLog: + LogIF.DebugLog("ACCESS", message); + break; + case LogLevel.InfoLog: + LogIF.InfoLog("ACCESS", message); + break; + case LogLevel.WarnLog: + LogIF.WarnLog("ACCESS", message); + break; + case LogLevel.ErrorLog: + LogIF.ErrorLog("ACCESS", message); + break; + case LogLevel.FatalLog: + LogIF.FatalLog("ACCESS", message); + break; + } + } + + /// <summary>コマンドの確認</summary> + /// <param name="valsLst">値</param> + /// <param name="argsDic">コマンド・値</param> + public static void ConfirmCommand(List<string> valsLst, Dictionary<string, string> argsDic) + { + // 整形 + StringBuilder sb = new StringBuilder(); + + sb.AppendLine(""); + + // カレント ディレクトリ + //sb.AppendLine("カレント ディレクトリ"); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + sb.AppendLine(ResourceMgr.GetString("M0012")); + sb.AppendLine(Program.OrgCurrentDirectory); + + sb.AppendLine(""); + + // 起動条件 + //sb.AppendLine("起動条件"); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + sb.AppendLine(ResourceMgr.GetString("M0013")); + + sb.AppendLine(""); + + // 値 + //sb.AppendLine("値"); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + sb.AppendLine(ResourceMgr.GetString("M0014")); + foreach (string vals in valsLst) + { + sb.AppendLine(vals); + } + + sb.AppendLine(""); + + // コマンド・値 + //sb.AppendLine("コマンド・値"); + //For internationalization, Replaced all the Japanese language to ResourceMgr.GetString() method call + sb.AppendLine(ResourceMgr.GetString("M0015")); + foreach (string key in argsDic.Keys) + { + sb.AppendLine(string.Format("{0} : {1}", key, argsDic[key])); + } + + // 出力 + Program.OutPutMessage(sb.ToString(), LogLevel.DebugLog); + } + + #endregion + + #endregion + + /// <summary> + /// GCする際のお作法 + /// WaitForPendingFinalizersで待機 + /// → 解凍ZIPファイルをCloseさせる + /// </summary> + public static void system_gc_collecting() + { + try + { + System.GC.Collect(); + System.GC.WaitForPendingFinalizers(); + System.GC.Collect(); + } +#pragma warning disable + catch (Exception ex) +#pragma warning restore + { + // ・・・ + } + } + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Properties/AssemblyInfo.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..de66f144a --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Properties/AssemblyInfo.cs @@ -0,0 +1,64 @@ +//********************************************************************************** +//* Copyright (C) 2007,2016 Hitachi Solutions,Ltd. +//********************************************************************************** + +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :AssemblyInfo +//* クラス日本語名 :AssemblyInfo設定 +//* +//* 作成者 :生技 西野 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX 新規作成 +//********************************************************************************** + +using System.Reflection; +using System.Runtime.InteropServices; + +// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 +// アセンブリに関連付けられている情報を変更するには、 +// これらの属性値を変更してください。 +[assembly: AssemblyTitle("DeployZipPackWithHTTP")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Hitachi Solutions")] +[assembly: AssemblyProduct("DeployZipPackWithHTTP")] +[assembly: AssemblyCopyright("Copyright (C) 2007,2016 Hitachi Solutions,Ltd.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントには +// 参照不可能になります。COM からこのアセンブリ内の型にアクセスする場合は、 +// その型の ComVisible 属性を true に設定してください。 +[assembly: ComVisible(false)] + +// 次の GUID は、このプロジェクトが COM に公開される場合の、typelib の ID です +[assembly: Guid("24f1957f-ecac-47ef-9331-9ac987a82e8e")] + +// アセンブリのバージョン情報は、以下の 4 つの値で構成されています: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/README.md b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/README.md new file mode 100644 index 000000000..b2816716d --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/README.md @@ -0,0 +1,669 @@ +# DeployZipPackWithHTTP(ZIP パッケージの HTTP 配布ツール) + +WWW サーバに置いた ZIP を HTTP で取得し、クライアントへ展開するツール。 +**マニフェスト ファイル(`*.mft`)が配布の単位**で、そこに配置先・起動 EXE・ +ZIP の一覧と MD5 を書く。 + +GUI と CUI の両方を持ち、**CUI は非対話**なのでエージェントから実行できる。 + +本書は**エージェントが実行するため**の情報を記す。 +**引数の一覧は書かない。** `/HELP` を実行すれば得られ、二重管理になるため。 + +--- + +## 1. ヘルプの実行(まずこれを見る) + +```powershell +# net48 +cd root\programs\CS\Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug +.\OpenTouryo.DeployZipPackWithHTTP.exe /HELP + +# .NET 10 +cd root\programs\CS\Frameworks\Tools\DeployZipPackWithHTTP\bin\Debug\net10.0-windows7.0 +.\OpenTouryo.DeployZipPackWithHTTP.exe /HELP +``` + +`/HELP` が**引数仕様の一次情報**。次が得られる。 + +- 起動の切り替え(引数なし=GUI、`/HELP`、`/CUI`) +- CUI のオプション(強制更新・出力抑止・起動抑止) +- WWW / Proxy の認証情報 +- アンインストール + +**`/HELP` は GUI アプリのままコンソールへ書く**(`AttachConsole`)。 +標準出力を取るには次節のリダイレクトが要る。 + +--- + +## 2. 標準出力は `Start-Process` で受ける + +**パイプで受けてはいけない。** WinForms アプリ(`WinExe`)であり、 +`AttachConsole` で親コンソールに書くため、`|` では取りこぼす。 + +```powershell +$exe = "...\bin\Debug\OpenTouryo.DeployZipPackWithHTTP.exe" +$out = "$env:TEMP\dz_out.txt" + +Start-Process $exe -ArgumentList "/CUI","/NB","/WWWURL","http://localhost:51099/FormAppRoot.mft" ` + -NoNewWindow -Wait -WorkingDirectory (Split-Path $exe) ` + -RedirectStandardOutput $out + +Get-Content $out -Encoding UTF8 | Where-Object { $_ -notmatch "^log4net" } +``` + +**log4net の内部トレースが大量に混ざる**ので、読むときは落とすとよい。 + +--- + +## 3. エージェントが踏みやすい罠 + +### 3.1 `/NB` を付けないと EXE が起動する + +マニフェストの `exe` 行の**先頭**のアセンブリを、**配置後に `Process.Start` する。** + +```csharp +if (Program.IsBoot) // /NB が指定されていない +{ + ... + p.Start(); // 配置した EXE を実行する +} +``` + +**中身を確かめていない配布物に対しては、必ず `/NB` を付ける。** +起動されると GUI が開き、非対話の実行が止まる。 + +> `/NB` が抑止するのは**起動だけ**。`exe` 行を使った +> 「動いていたら配置を中止する」判定は、`/NB` を付けても働く(4 節)。 + +### 3.2 配置先はマニフェストが決める。環境変数が使える + +`ins` 行の値がそのまま配置先になる。**引数で上書きできない。** +別の場所へ入れたいならマニフェストを作り直す。 + +**`%変数%` は展開される。** + +```csharp +string InsDir = StringVariableOperator.BuiltStringIntoEnvironmentVariable(entry.InstallDir); +``` + +``` +ins %TEMP%\FormAppRoot\ ← 環境に依存しない +ins C:\Users\xxxx\...\FormAppRoot\ ← 特定の環境でしか動かない +``` + +**手で書くマニフェストは環境変数を使うこと。** 絶対パスを直書きすると、 +別の環境やサービス アカウントで動かしたときに配置先が無い。 + +> 展開するのは `ins` 行だけではない。`StringVariableOperator` を通す箇所は +> 同じ書式(`%` で囲む)を受け付ける。 + +### 3.5 引数があるときは GUI を開かない + +**引数なし=GUI、引数あり=CUI** である。 +引数を付けたのにどのモードにも当たらない場合は、**エラーで終わる**(終了コード 1)。 + +``` +認識できない引数です : /NOSUCHSWITCH 使い方は /HELP を参照してください。 +``` + +2026/08/08 まで、この場合も GUI を開いていた(#528)。 +**非対話で呼ぶと画面が出たまま応答を待ち続け、呼び出し側が停止する。** +綴りの誤りだけでなく、**古いビルドに新しいスイッチを渡したとき**にも起きる +(`/ZIPGEN` を実装する前のビルドで実際に踏んだ)。 + +### 3.3 設定と履歴は EXE の隣に置かれる + +| ファイル | 内容 | +|---|---| +| `current.json` | 前回入力(URL・ユーザー・プロキシ等) | +| `histories.json` | 接続先の履歴。**アンインストール時の削除対象一覧を持つ** | + +**2026/08/08 まで `current.bin` / `histories.bin`(BinaryFormatter)だった**(#528)。 +`BinaryFormatter` が .NET 9 以降で削除されたため JSON に替えた。 +**旧 `.bin` は読まない。** 履歴が一度空になるだけで、URL を入れ直せばよい。 + +`/FORCE` は履歴を消して強制的に取り直す。**試行錯誤のときはこれを使う。** +### 3.6 `/FORCE` は配置先を丸ごと消してから配る + +```csharp +// 強制モードでは一度削除してから +if (Program.IsForce) +{ + if (Directory.Exists(entry.InstallDir)) + { + Directory.Delete(entry.InstallDir, true); // ← 丸ごと削除 + } +} +``` + +**「入れ直す」モードである。** 差分でも通常の上書きでもない。 + +削除が途中で失敗すると、**消しかけの状態で止まる。** +この削除はバックアップより前に行われる(バックアップは ZIP を展開する直前で取る)ため、 +**この失敗はロールバックの対象にならない。** + +実測では、配置先の `bbb\top2.dll` を掴んだ状態で `/FORCE` を実行し、 +21 ファイルが 1 ファイルまで消えた。 + +``` +別のプロセスで使用されているため、プロセスはファイル 'top2.dll' にアクセスできません。 + 場所 System.IO.Directory.Delete(...) + 場所 DeployZipPackWithHTTP.Program.ExecUpdate(...) 行 1096 +``` + +**復旧は難しくない。** 掴んでいるプロセスを終わらせて、**もう一度 `/FORCE`** でよい +(実測でも 21 ファイルに戻った)。配置物はサーバから作り直せるものなので、 +消えて困る情報は無い。 + +> **前チェックは万能ではない。** あれは `exe` 行のアセンブリが動いているかを見るだけで、 +> **EXE 以外のファイルが掴まれている場合は素通りする。** + +**本当に戻らないのは、配布物でないファイルを配置先に置いていた場合。** +`/FORCE` は配置先を**中身ごと**消すため、アプリが書いた設定やログも消える。 +これは失敗したときに限らず、**成功しても同じ**である。 + +| | `/FORCE` なし | `/FORCE` あり | +|---|---|---| +| 展開の失敗 | ロールバックされる(下記) | ― | +| 削除の失敗 | 起きない | 消しかけで止まる。**再度 `/FORCE` で復旧** | +| 配布物でないファイル | 残る | **成否によらず消える** | + +> **常用しない。** 差分が効かなくなり(履歴を消すため)、毎回すべて取り直しになる。 + +### 3.4 引数の渡し方(`/MFTGEN` で必ず踏む) + +コマンドライン解析(`StringVariableOperator.GetCommandArgs`)に癖がある。 + +**① `\` はエスケープ文字として食べられる** + +``` +NG : /MFTFILE "C:\temp\a.mft" ← \ が消えて C:tempa.mft になる +OK : /MFTFILE "C:/temp/a.mft" ← / なら素通り +OK : /MFTFILE "C:\\temp\\a.mft" ← \\ で \ 1 個 +``` + +**② ただし `/INSDIR` だけは `\` を残すこと** + +`ins` 行の値は**そのまま配置先になる**。`/` のままだと配置に失敗し、 +**それまでの配置物ごとロールバックされる。** `\\` でエスケープする。 + +``` +OK : /INSDIR "c:\\FormAppRoot\\" → ins c:\FormAppRoot\ +NG : /INSDIR "c:/FormAppRoot/" → 配置時に失敗してロールバック +``` + +**③ 空白を含む値は、自分で引用符を付ける** + +PowerShell の `Start-Process -ArgumentList` は**空白を含む要素に引用符を付けない**。 +付けないと空白で切れる。 + +```powershell +NG : "/EXENAME", "top.exe, top1.exe" → exe top.exe, で切れる +OK : "/EXENAME", '"top.exe, top1.exe"' → 引用符を値に埋め込む +``` + +> **終了コードでは検出できないものがある。** ①③は `0` を返しつつ内容が壊れる。 +> **生成物を必ず開いて確かめること。** + +--- + +## 4. マニフェスト(`*.mft`) + +``` +ins c:\FormAppRoot\ +exe top.exe, top1.exe, top2.exe, top3.exe +zip aaa.zip +md5 O3HVJ9PGdCYEn0bQHCnvYg== +zip bbb.zip +md5 jSKAbZeoGgjIPJek53/kAA== +``` + +| 行 | 意味 | +|---|---| +| `ins` | 配置先フォルダ | +| `exe` | **アプリを構成する EXE をすべて**(カンマ区切り)。下記 | +| `zip` | 取得する ZIP。**`.zip` 以外は無視される** | +| `md5` | 直前の `zip` の MD5(Base64)。**一致しないと配置しない** | + +ZIP は**マニフェストと同じ場所**から取りに行く(URL のフォルダを基準にする)。 + +### `exe` は「起動する EXE」ではない + +**起動されるのは先頭の 1 つだけ。** 2 番目以降は起動には使われない。 +にもかかわらず全て挙げるのは、**配置してよいかの判定に使う**ため。 + +```csharp +foreach (Process pp in Process.GetProcesses()) +{ + for (int i = 0; i < ary_exeFiles.Length; i++) // ← 列挙した全件を突き合わせる + { + if (ary_exeFiles[i].ToUpper() == pp.MainModule.FileName.ToUpper()) + { + p.StartInfo = new ProcessStartInfo(ary_exeFiles[i]); + return false; // 1 つでも動いていれば false + } + } +} + +p.StartInfo = new ProcessStartInfo(ary_exeFiles[0]); // ← 起動は先頭だけ +return true; +``` + +呼び出しは 3 箇所あり、**2 箇所は起動しない。** + +| 箇所 | 用途 | 起動するか | +|---|---|---| +| 配置の**前**チェック | **1 つでも動いていたら配置を中止**する(`E0002`) | しない | +| 配置の後(2 箇所) | 先頭を起動する。`/NB` で抑止できる | する | + +**使用中のファイルを上書きしないための番人**である。 +`top.exe` が止まっていても `top2.exe` が動いていれば、`bbb.zip` の展開で失敗する。 +だから**アプリを構成する EXE をすべて挙げる。** + +例外メッセージにも効く。**先頭ではなく「実際に動いていた EXE 名」**が出るため、 +利用者は何を終了すればよいか分かる。 + +> 挙げ漏らすと、**配置の途中で失敗してロールバックされる**(それ自体は安全側)。 +> ただし原因が「別の EXE が動いていた」ことだと分かりにくい。 + +### 失敗したときの守り(2 段) + +**第 1 段 : 配置に入る前に止める** + +`exe` 行のアセンブリが 1 つでも動いていれば、**ZIP を 1 つも取得せずに中止**する。 + +``` +[FormAppRoot.mft]をダウンロードしました。 +EXEファイル[...\aaa\top1.exe]が既に起動されています。 +``` + +**先頭ではなく、実際に動いていたものが示される。** +`exe` 行を相対パスで正しく書いていないと、この検出が効かない。 + +**第 2 段 : 途中で失敗したら元に戻す** + +展開に失敗すると、**その回に触ったものをすべて直前の状態へ戻す。** + +``` +[aaa.zip]は最新の状態です。 +[bbb.zip]を更新します(更新)。 +[bbb.zip]をダウンロードしました。 +全ての配置対象ファイルを直前の状態に戻します。 +[...\bbb\data2.txt]ファイルが開かれているため更新できません。 +``` + +実測では、**先に成功していた `root.zip` の内容まで戻り**、ファイル数も変わらなかった。 + +> **`/FORCE` を付けるとこの守りが働かない場面がある。** 3.6 節を読むこと。 + +### ZIP の作成(`/ZIPGEN`) + +GUI の「圧縮」タブと同じものを CUI で作れる(#528)。 + +#### 2 つの圧縮方式 + +**違いは「書庫内にルート フォルダを作るか」だけ**である。 +GUI のチェック ボックスが、そのまま `/ROOTINZIP` の有無に対応する。 + +| | 個別のフォルダ圧縮 | ルート フォルダからの圧縮 | +|---|---|---| +| GUI | チェック**無し** | チェック**有り** | +| CUI | `/ROOTINZIP <名前>` | 省略 | +| 書庫内ルート | `<名前>/` を作る | 作らない | +| 書庫の中身 | `aaa/top1.exe` | `top1.exe` | +| 展開結果 | `<ins>\aaa\top1.exe` | `<ins>\top1.exe` | + +**圧縮の対象(`/SRCDIR`)と組み合わせて考える。** + +```powershell +# 個別のフォルダ圧縮 : FormAppRoot\aaa を、書庫内 aaa/ に入れる +/ZIPGEN /SRCDIR "C:/…/FormAppRoot/aaa" /ZIPFILE "C:/…/web/aaa" /ROOTINZIP aaa + → aaa.zip の中身 : aaa/top1.exe, aaa/data1.csv, ... + → 展開 : <ins>\aaa\top1.exe + +# ルート フォルダからの圧縮 : FormAppRoot をまるごと、書庫内ルート無しで +/ZIPGEN /SRCDIR "C:/…/FormAppRoot" /ZIPFILE "C:/…/web/all" + → all.zip の中身 : top.exe, aaa/top1.exe, bbb/top2.exe, ... + → 展開 : <ins>\top.exe, <ins>\aaa\top1.exe +``` + +**どちらも展開結果は同じにできる。** 違うのは**配布物の分け方**であり、 +それが次項の差分配布に効く。 + +#### `/TOPONLY`(CUI だけ) + +**直下のファイルだけ**を対象にし、サブフォルダを含めない。 + +```powershell +/ZIPGEN /SRCDIR "C:/…/FormAppRoot" /ZIPFILE "C:/…/web/root" /TOPONLY + → root.zip の中身 : top.exe, readme.txt, ...(aaa/ 等は入らない) +``` + +`CreateZipFromFolder` は再帰するため、ルートを対象にするとサブフォルダまで入る。 +実装は選択デリゲート(`SelectionCriteriaDlgt3`)で、**`ZipperV2` は変えていない。** + +> **これは近道であって、GUI にできないことではない。** +> **`/TOPONLY` は CUI だけにあり、これが無い GUI ではステージングが要る。** +> 直下のファイルを別フォルダへ集め、そこを圧縮すれば同じ ZIP になる。 +> +> ```powershell +> # GUI と同じ経路(/TOPONLY を使わない)でも、結果は一致する +> Get-ChildItem $src -File | Copy-Item -Destination "$t\stage" +> /ZIPGEN /SRCDIR "$t/stage" /ZIPFILE "$t/out/byStage" +> ``` +> +> 実測で、`/TOPONLY` で作ったものと**エントリが完全に一致**した。 + +> **除外拡張子では代替できないことがある。** 同じ拡張子がルートとサブフォルダの +> 両方にあると絞り込めない(同梱サンプルは `.txt` がルートと `ccc` の双方にある)。 +> **ステージングの方が確実。** + +暗号化・圧縮レベル・文字コードも指定できる(`/CYP` `/PASS` `/CMPLV` `/ENC`)。 +除外拡張子は `/EXCLUDEEXT "txt,csv"`。 + +#### CUI 専用は `/TOPONLY` だけ + +他の引数は、すべて GUI の入力に対応する。 + +| CUI | GUI | +|---|---| +| `/SRCDIR` / `/ZIPFILE` | フォルダ / ファイル名 | +| `/ROOTINZIP` の有無 | チェック ボックス | +| `/EXCLUDEEXT` | 除外拡張子 | +| `/CYP` `/PASS` `/CMPLV` `/ENC` | 各コンボ ボックス | +| **`/TOPONLY`** | **無し**(ステージングで代替) | + +--- + +### 差分配布(ZIP を分ける理由) + +**このツールは ZIP 単位で差分を取る。** 分け方が更新の粒度になる。 + +#### 差分は 2 段構え + +**マニフェストが先に効く。** ZIP 単位の判定はその後である。 + +| 段 | 対象 | 変わっていなければ | +|---|---|---| +| **第 1 段** | `*.mft` の `Last-Modified` | **ZIP を 1 つも見に行かない**(HEAD すら送らない) | +| **第 2 段** | 各 `*.zip` の `Last-Modified` | その ZIP だけ飛ばす | + +第 1 段が効くと、**HTTP 要求は HEAD 1 回で終わる。** + +``` +[.../FormAppRoot.mft]は最新の状態です。 ← これ 1 行で完了 +``` + +**マニフェストを作り直すと第 1 段は破れる。** `/MFTGEN` は毎回書き出すため、 +`Last-Modified` が変わる。ZIP を 1 つでも作り直したらマニフェストも作り直しになるので、 +**実運用では「第 1 段は初回以外の無変更時に効く」**と考えるとよい。 + +#### 判定の実装 + +配布側は、マニフェストの `zip` 行ごとに **HEAD 要求で `Last-Modified` を見る。** + +```csharp +// HEAD(Last-Modifiedチェック) +if (Program.LastModifiedCheck_ByHead(entry, history, zipFile)) +{ + Program.GetAndSaveContent(entry, zipFile); // 変わっていた → GET して展開 + isUpdated = true; +} +else +{ + isUpdated = false; // 変わっていない → 何もしない +} +``` + +比較相手は**履歴(`histories.json`)に残した前回の `Last-Modified`** である。 + +```csharp +httpLastModifiedHis = history.HttpZipLastModified[zipFile]; +... +if (httpLastModifiedHis == httpLastModifiedWeb) { return false; } // 一致 → 飛ばす +``` + +> **大小ではなく一致で判定する。** サーバ側を古いものに戻した場合も「変わった」と見なす。 +> 履歴に無い ZIP(初回・追加された ZIP)は必ず取得する。 + +#### 実測(`FormAppRoot` を 4 分割、`/FORCE` なし) + +| 回 | 状況 | 結果 | +|---|---|---| +| 1 回目 | 初回 | 4 つとも取得・展開 | +| 2 回目 | 変更なし | **第 1 段で完了**。ZIP は見に行かない | +| 3 回目 | `aaa` だけ変更 | `.mft` と **`aaa.zip` だけ**取得。他 3 つは「最新の状態です」 | + +``` +[aaa.zip]を更新します(更新)。 +[aaa.zip]を解凍・インストールします(更新)。 +[bbb.zip]は最新の状態です。 +[ccc.zip]は最新の状態です。 +[root.zip]は最新の状態です。 +``` + +配置結果も、**変更は反映され、他は触られず、ファイル数は変わらない。** + +#### だから「個別のフォルダ圧縮」を使う + +| 方式 | ZIP の数 | `aaa` の 1 ファイルを直したとき | +|---|---|---| +| **個別のフォルダ圧縮** | フォルダごと | **`aaa.zip` だけ**を取り直す | +| ルート フォルダからの圧縮 | 1 つ | **全体**を取り直す | + +同梱の `FormAppRootWeb` は**個別のフォルダ圧縮**で作っている +(`root.zip` + `aaa.zip` / `bbb.zip` / `ccc.zip`)。 +**ルート直下のファイルも 1 つの単位**として切り出す必要があるため、 +そこだけ `/TOPONLY` を使う。 + +```powershell +/ZIPGEN /SRCDIR "$src" /ZIPFILE "$w/root" /TOPONLY # ルート直下 +/ZIPGEN /SRCDIR "$src/aaa" /ZIPFILE "$w/aaa" /ROOTINZIP aaa # 以下、フォルダごと +/ZIPGEN /SRCDIR "$src/bbb" /ZIPFILE "$w/bbb" /ROOTINZIP bbb +/ZIPGEN /SRCDIR "$src/ccc" /ZIPFILE "$w/ccc" /ROOTINZIP ccc +``` + +#### 「ルート フォルダからの圧縮」でも分けられる + +**`/SRCDIR` はルートのまま、対象を絞って複数回**実行する。 +書庫内のパスがルートからの相対になるため、**どの ZIP も正しい位置に展開される。** + +```powershell +# 実行ファイルの類だけ +/ZIPGEN /SRCDIR "$src" /ZIPFILE "$w/bin" /EXCLUDEEXT "txt,csv,bin" + +# データだけ(上と補い合う組み合わせにする) +/ZIPGEN /SRCDIR "$src" /ZIPFILE "$w/data" /EXCLUDEEXT "exe,dll,json" +``` + +こちらは**フォルダの区切りに縛られない**ので、 +「実行ファイルは滅多に変わらないが、データは頻繁に変わる」といった +**更新頻度で分ける**使い方に向く。 + +> **重複と抜けに気を付ける。** 絞り込みは除外指定なので、 +> 組み合わせを誤ると**同じファイルが 2 つの ZIP に入る**(後勝ちで上書きされる)か、 +> **どの ZIP にも入らない**(配置されない)。 +> 分けたら**合計が元のファイル数と一致するか**を確かめること。 + +| 分け方 | 向く場面 | +|---|---| +| **個別のフォルダ圧縮** | フォルダが機能の単位になっている。分け方が自明 | +| **ルート フォルダからの圧縮**(+絞り込みで複数回) | 更新頻度や種類で分けたい。フォルダをまたぐ | +| ルート フォルダからの圧縮(1 つだけ) | 分けない。配布物が小さい、更新が常に全体に及ぶ | + +#### 差分を効かせるときの注意 + +- **`/FORCE` を付けると差分が効かない。** 履歴を消すため、**両段とも**素通りして + 毎回すべて取り直す。試行錯誤には便利だが、**差分の確認にはならない。** +- **ZIP を作り直すと `Last-Modified` が変わる。** 中身が同じでも取り直しになる。 + 変わっていないフォルダは、**ZIP も作り直さない**こと。 +- **MD5 が一致しなければ配置しない。** 差分で取得した ZIP も検証される。 +- **履歴は EXE の隣(`histories.json`)にある。** 消すと差分が効かなくなる。 + 配置先を消しても履歴は残るため、**「配置先は空なのに最新の状態です」**になり得る。 + その場合は `/FORCE` で取り直す。 + +### MFT の作成(`/MFTGEN`) + +GUI の「声明文作成」タブと同じものを CUI で作れる(#528)。 + +```powershell +$zips = ((Get-ChildItem $web -Filter *.zip | ForEach-Object { $_.FullName.Replace("\","/") }) -join ",") + +Start-Process $exe -ArgumentList ` + "/MFTGEN", ` + "/ZIPFILES", $zips, ` + "/INSDIR", "c:\\FormAppRoot\\", ` + "/EXENAME", '"top.exe, top1.exe, top2.exe, top3.exe"', ` + "/MFTFILE", "$env:TEMP/FormAppRoot.mft" ` + -NoNewWindow -Wait -WorkingDirectory (Split-Path $exe) +``` + +**引数の渡し方に 3 つの癖がある**(3.4 節)。上の例はそれを踏まえた形。 + +> **MD5 は「実ファイルの MD5」である。** +> 2026/08/08 まで `Program.LoadFile` が**最終ブロックを前ブロックの残骸で埋めていた**ため、 +> それ以前に作られたマニフェストの値は実ファイルの MD5 と異なる(#528 で修正)。 +> **古いマニフェストは検証に失敗する**ので、作り直すこと。 + +--- + +## 5. 疎通確認の手順(IIS Express で完結する) + +IIS を立てなくてよい。**IIS Express で静的配信すれば足りる**(管理者権限も不要)。 + +```powershell +# 1) 配信フォルダを用意し、FormAppRoot から ZIP を作る +# **FormAppRootWeb は追跡していない。** 毎回ここで作る(後述)。 +$w = "$env:TEMP\dzweb" +New-Item -ItemType Directory -Force $w | Out-Null + +$src = "...\Sample\FormAppRoot".Replace("\", "/") +& $exe /ZIPGEN /SRCDIR $src /ZIPFILE "$w/root".Replace("\","/") /TOPONLY +& $exe /ZIPGEN /SRCDIR "$src/aaa" /ZIPFILE "$w/aaa".Replace("\","/") /ROOTINZIP aaa +& $exe /ZIPGEN /SRCDIR "$src/bbb" /ZIPFILE "$w/bbb".Replace("\","/") /ROOTINZIP bbb +& $exe /ZIPGEN /SRCDIR "$src/ccc" /ZIPFILE "$w/ccc".Replace("\","/") /ROOTINZIP ccc + +# 2) .mft の MIME を登録する(未登録だと 404.3 になる) +@' +<?xml version="1.0" encoding="utf-8"?> +<configuration> + <system.webServer> + <staticContent> + <remove fileExtension=".mft" /> + <mimeMap fileExtension=".mft" mimeType="text/plain" /> + </staticContent> + </system.webServer> +</configuration> +'@ | Set-Content "$w\web.config" -Encoding UTF8 + +# 3) 配信する +Start-Process "${env:ProgramFiles}\IIS Express\iisexpress.exe" ` + -ArgumentList "/path:$w","/port:51099","/systray:false" -WindowStyle Hidden +``` + +あとは 2 節の形で `/CUI /NB /WWWURL http://localhost:51099/FormAppRoot.mft` を実行する。 + +### 同梱のサンプル + +``` +Sample/ + SampleConsoleApp/ … 配布する EXE のソース(net10.0 のコンソール アプリ) + FormAppRoot/ … 配布物(21 ファイル)。**追跡している** + FormAppRootWeb/ … 個別のフォルダ圧縮で作った ZIP 一式。**追跡しない(生成物)** + FormAppRootWeb2/ … ルート フォルダからの圧縮で作った ZIP 一式。**同上** +``` + +**`FormAppRootWeb` と `FormAppRootWeb2` は、同じ `FormAppRoot` を別の方式で分けたもの。** +どちらを配布しても、展開結果は同じ 21 ファイルになる。 + +| | 分け方 | ZIP | +|---|---|---| +| `FormAppRootWeb` | **フォルダごと**(`/ROOTINZIP`)+ルート直下(`/TOPONLY`) | `root` `aaa` `bbb` `ccc` | +| `FormAppRootWeb2` | **ルートから+種類で分割**(`/EXCLUDEEXT`) | `app`(実行ファイル一式)`data`(データ) | + +```powershell +# FormAppRootWeb2 の作り方(除外指定は補い合う組み合わせにする) +/ZIPGEN /SRCDIR "$src" /ZIPFILE "$w2/app" /EXCLUDEEXT "txt,csv,bin" → 12 件 +/ZIPGEN /SRCDIR "$src" /ZIPFILE "$w2/data" /EXCLUDEEXT "exe,dll,json" → 9 件 + 合計 21 件(重複 0) +``` + +`FormAppRoot` の EXE は `SampleConsoleApp` を**アセンブリ名だけ変えてビルド**したもの。 + +```powershell +dotnet build ...\Sample\SampleConsoleApp -c Release -p:AssemblyName=top -o <一時> +dotnet build ...\Sample\SampleConsoleApp -c Release -p:AssemblyName=top1 -o <一時> +dotnet build ...\Sample\SampleConsoleApp -c Release -p:AssemblyName=top2 -o <一時> +``` + +`.pdb` を除いた 4 ファイル(`.exe` `.dll` `.deps.json` `.runtimeconfig.json`)を +`FormAppRoot` / `aaa` / `bbb` へ置く。**中身は同じで、名前だけ違う。** +配置後に起動すると、自分の居場所と同じ場所のファイル一覧を出す。 + +> **`FormAppRootWeb` を追跡しないのは、作り直し漏れを防ぐため。** +> `FormAppRoot` を直したのに ZIP を作り直さないと、MD5 が合わず配布が失敗する。 +> 追跡していると、その状態のままコミットできてしまう。 + +### 確認できること + +**配置結果を、配布前のフォルダと突き合わせられる。** + +```powershell +# 21 ファイルが一致するはず +$src = "...\Sample\FormAppRoot"; $dst = "C:\FormAppRoot" +$md5 = [System.Security.Cryptography.MD5]::Create() +foreach ($f in Get-ChildItem $src -Recurse -File) { + $rel = $f.FullName.Substring($src.Length + 1) + $a = [Convert]::ToBase64String($md5.ComputeHash([IO.File]::ReadAllBytes($f.FullName))) + $b = [Convert]::ToBase64String($md5.ComputeHash([IO.File]::ReadAllBytes((Join-Path $dst $rel)))) + if ($a -ne $b) { "相違 : $rel" } +} +``` + +### 後始末 + +**`C:\FormAppRoot` と IIS Express のプロセスが残る。** 消してよいか判断してから消すこと。 +`/UnIns "<マニフェストの URL>"` で、履歴に記録された配置物を削除できる。 + +--- + +## 6. ビルド + +``` +CS\4_Build_Framework_Tool.bat … net48 +CS\4_Build_Framework_ToolCore.bat … .NET 10 +``` + +いずれも `1_BuildAll.ps1` の `Framework_Tool` / `Framework_ToolCore` から呼ばれる。 +**ステップとしては独立していない**ので、サマリでは他のツールとまとめて 1 行になる。 + +--- + +## 7. ZIP 部品との関係 + +**本ツールは `ZipperV2` / `UnZipperV2`(`Public.IO`)の唯一の利用者。** + +``` +Public/IO/ZipperV2.cs / UnZipperV2.cs ← SharpZipLib(#524) +``` + +**ZIP 部品を変えたら、本ツールのビルドと疎通を必ず確かめること。** +単体テスト(`TestCode/TestZipV2.cs`)は部品の振る舞いを見るが、 +**配布フロー全体を通すのは本ツールだけ**である。 + +DotNetZip(非推奨・既知脆弱性 `GHSA-xhg6-9j5j-w4vf`)から移行した際、 +次を落としている(#528)。 + +| 落としたもの | 理由 | +|---|---| +| 自己解凍書庫(`SaveSelfExtractor`) | SharpZipLib に相当が無い。**配布フローは `.zip` しか扱わず、消費経路が無かった** | +| 選択条件の文字列(`"name != *.txt"`) | DotNetZip 独自の DSL。選択デリゲートに一本化した | + +--- + +## 8. 制約 + +- **GUI の確認は手作業**(`RELEASE.md` 4 節)。CUI は `/MFTGEN` と `/CUI` で + 生成から配置まで通せるため、疎通確認に載せられる +- 文言は `Resources\Resource.resx` / `Resource.ja-JP.resx` に置く。**直書きしない** + (例外メッセージは `MSGDefinition.xml` / `MSGDefinition_ja-JP.xml` 側) diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Resources/Resource.Designer.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Resources/Resource.Designer.cs new file mode 100644 index 000000000..9fabf1844 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Resources/Resource.Designer.cs @@ -0,0 +1,657 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// このコードはツールによって生成されました。 +// ランタイム バージョン:4.0.30319.42000 +// +// このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 +// コードが再生成されるときに損失したりします。 +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace DeployZipPackWithHTTP.Resources { + using System; + + + /// <summary> + /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。 + /// </summary> + // このクラスは StronglyTypedResourceBuilder クラスが ResGen + // または Visual Studio のようなツールを使用して自動生成されました。 + // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に + // ResGen を実行し直すか、または VS プロジェクトをビルドし直します。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource() { + } + + /// <summary> + /// このクラスで使用されているキャッシュされた ResourceManager インスタンスを返します。 + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DeployZipPackWithHTTP.Resources.Resource", typeof(Resource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// すべてについて、現在のスレッドの CurrentUICulture プロパティをオーバーライドします + /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。 + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// <summary> + /// /HELP Show me the HELP. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0001 { + get { + return ResourceManager.GetString("A0001", resourceCulture); + } + } + + /// <summary> + /// /CUI I will start in CUI CUI. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0002 { + get { + return ResourceManager.GetString("A0002", resourceCulture); + } + } + + /// <summary> + /// Below, valid options argument only when CUI に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0003 { + get { + return ResourceManager.GetString("A0003", resourceCulture); + } + } + + /// <summary> + /// / Force update to erase the FORCE history file. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0004 { + get { + return ResourceManager.GetString("A0004", resourceCulture); + } + } + + /// <summary> + /// /QUIET (Hide the message) that you can run in quiet mode . に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0005 { + get { + return ResourceManager.GetString("A0005", resourceCulture); + } + } + + /// <summary> + /// /SILENT (Hide message, the progress) that will run in silent mode. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0006 { + get { + return ResourceManager.GetString("A0006", resourceCulture); + } + } + + /// <summary> + /// /NB Ignore start instruction assembly even if they are specified in the manifest file. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0007 { + get { + return ResourceManager.GetString("A0007", resourceCulture); + } + } + + /// <summary> + /// /WWWURL I Specifies the URL to the manifest file of \ "http://xxxx \" WWW server. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0008 { + get { + return ResourceManager.GetString("A0008", resourceCulture); + } + } + + /// <summary> + /// /WWWUID xxxx WWW Specifies the user ID when accessing the server. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0009 { + get { + return ResourceManager.GetString("A0009", resourceCulture); + } + } + + /// <summary> + /// /WWWPWD xxxx WWW Specifies the password used to access the server. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0010 { + get { + return ResourceManager.GetString("A0010", resourceCulture); + } + } + + /// <summary> + /// /WWWDomain xxxx WWW You specify the domain when accessing to the server. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0011 { + get { + return ResourceManager.GetString("A0011", resourceCulture); + } + } + + /// <summary> + /// /ProxyURL \"http://yyyy\" Proxy I specify the URL to the server. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0012 { + get { + return ResourceManager.GetString("A0012", resourceCulture); + } + } + + /// <summary> + /// If it is not specified, and then apply the IE setting. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0013 { + get { + return ResourceManager.GetString("A0013", resourceCulture); + } + } + + /// <summary> + /// It does not use a proxy [none] is specified. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0014 { + get { + return ResourceManager.GetString("A0014", resourceCulture); + } + } + + /// <summary> + /// /ProxyUID yyyy Proxy Specifies the user ID when accessing the server. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0015 { + get { + return ResourceManager.GetString("A0015", resourceCulture); + } + } + + /// <summary> + /// /ProxyPWD yyyy Proxy Specifies the password used to access the server. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0016 { + get { + return ResourceManager.GetString("A0016", resourceCulture); + } + } + + /// <summary> + /// /ProxyDomain yyyy Proxy You specify the domain when accessing to the server. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0017 { + get { + return ResourceManager.GetString("A0017", resourceCulture); + } + } + + /// <summary> + /// /UnIns \"http://xxxx\" WWW Specify the URL to the manifest file on the server (uninstall). に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0018 { + get { + return ResourceManager.GetString("A0018", resourceCulture); + } + } + + /// <summary> + /// /MFTGEN Creates a manifest file. The following arguments are required. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0019 { + get { + return ResourceManager.GetString("A0019", resourceCulture); + } + } + + /// <summary> + /// /ZIPFILES ... Specifies the ZIP files (comma separated). に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0020 { + get { + return ResourceManager.GetString("A0020", resourceCulture); + } + } + + /// <summary> + /// /INSDIR ... /EXENAME ... に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0021 { + get { + return ResourceManager.GetString("A0021", resourceCulture); + } + } + + /// <summary> + /// /MFTFILE ... Specifies the manifest file to create. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0022 { + get { + return ResourceManager.GetString("A0022", resourceCulture); + } + } + + /// <summary> + /// /MFTGEN requires /ZIPFILES, /INSDIR, /EXENAME and /MFTFILE. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0023 { + get { + return ResourceManager.GetString("A0023", resourceCulture); + } + } + + /// <summary> + /// The manifest file was created. [{0}] に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0024 { + get { + return ResourceManager.GetString("A0024", resourceCulture); + } + } + + /// <summary> + /// /ZIPGEN Creates a ZIP file. /SRCDIR and /ZIPFILE are require に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0025 { + get { + return ResourceManager.GetString("A0025", resourceCulture); + } + } + + /// <summary> + /// /SRCDIR xxxx Specifies the folder to compress. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0026 { + get { + return ResourceManager.GetString("A0026", resourceCulture); + } + } + + /// <summary> + /// /ZIPFILE xxxx Specifies the ZIP to create (without extension に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0027 { + get { + return ResourceManager.GetString("A0027", resourceCulture); + } + } + + /// <summary> + /// /ROOTINZIP xxxx Specifies the root folder in the archive. If に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0028 { + get { + return ResourceManager.GetString("A0028", resourceCulture); + } + } + + /// <summary> + /// /TOPONLY Compresses only the files directly under /SRCDIR (n に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0029 { + get { + return ResourceManager.GetString("A0029", resourceCulture); + } + } + + /// <summary> + /// /EXCLUDEEXT \"txt,csv\" Specifies the extensions to exclude に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0030 { + get { + return ResourceManager.GetString("A0030", resourceCulture); + } + } + + /// <summary> + /// /CYP xxxx Encryption (None, PkzipWeak, WinZipAes128, WinZipA に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0031 { + get { + return ResourceManager.GetString("A0031", resourceCulture); + } + } + + /// <summary> + /// /ZIPGEN requires /SRCDIR and /ZIPFILE. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0032 { + get { + return ResourceManager.GetString("A0032", resourceCulture); + } + } + + /// <summary> + /// The ZIP file was created. [{0}] {1} file(s). に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0033 { + get { + return ResourceManager.GetString("A0033", resourceCulture); + } + } + + /// <summary> + /// Unknown argument(s) に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string A0034 { + get { + return ResourceManager.GetString("A0034", resourceCulture); + } + } + + /// <summary> + /// An error has occurred. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string E0001 { + get { + return ResourceManager.GetString("E0001", resourceCulture); + } + } + + /// <summary> + /// Delete Exception: に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string E0002 { + get { + return ResourceManager.GetString("E0002", resourceCulture); + } + } + + /// <summary> + /// Error に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string Error0001 { + get { + return ResourceManager.GetString("Error0001", resourceCulture); + } + } + + /// <summary> + /// Summary (compression) に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string Error0002 { + get { + return ResourceManager.GetString("Error0002", resourceCulture); + } + } + + /// <summary> + /// Summary (De) に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string Error0003 { + get { + return ResourceManager.GetString("Error0003", resourceCulture); + } + } + + /// <summary> + /// ZIP file |*.Zip に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string EXT0001 { + get { + return ResourceManager.GetString("EXT0001", resourceCulture); + } + } + + /// <summary> + /// Production start of {0} に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string I0001 { + get { + return ResourceManager.GetString("I0001", resourceCulture); + } + } + + /// <summary> + /// Write start of {0} に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string I0002 { + get { + return ResourceManager.GetString("I0002", resourceCulture); + } + } + + /// <summary> + /// I wrote {0} / {1} bytes に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string I0003 { + get { + return ResourceManager.GetString("I0003", resourceCulture); + } + } + + /// <summary> + /// Write end of {0} に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string I0004 { + get { + return ResourceManager.GetString("I0004", resourceCulture); + } + } + + /// <summary> + /// Writing of entry for {1} (s) has (have) completed {0} or in に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string I0005 { + get { + return ResourceManager.GetString("I0005", resourceCulture); + } + } + + /// <summary> + /// Creation end of {0} に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string I0006 { + get { + return ResourceManager.GetString("I0006", resourceCulture); + } + } + + /// <summary> + /// {0} file(s) were compressed. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string I0007 { + get { + return ResourceManager.GetString("I0007", resourceCulture); + } + } + + /// <summary> + /// {0} file(s) were extracted. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string I0008 { + get { + return ResourceManager.GetString("I0008", resourceCulture); + } + } + + /// <summary> + /// Message に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0001 { + get { + return ResourceManager.GetString("M0001", resourceCulture); + } + } + + /// <summary> + /// <Message> に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0002 { + get { + return ResourceManager.GetString("M0002", resourceCulture); + } + } + + /// <summary> + /// <Stack trace> に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0003 { + get { + return ResourceManager.GetString("M0003", resourceCulture); + } + } + + /// <summary> + /// <Internal exception> に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0004 { + get { + return ResourceManager.GetString("M0004", resourceCulture); + } + } + + /// <summary> + /// Message に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0005 { + get { + return ResourceManager.GetString("M0005", resourceCulture); + } + } + + /// <summary> + /// CUI start に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0006 { + get { + return ResourceManager.GetString("M0006", resourceCulture); + } + } + + /// <summary> + /// GUI boot に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0007 { + get { + return ResourceManager.GetString("M0007", resourceCulture); + } + } + + /// <summary> + /// Delete Exception: に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0008 { + get { + return ResourceManager.GetString("M0008", resourceCulture); + } + } + + /// <summary> + /// 'Already exists. に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0009 { + get { + return ResourceManager.GetString("M0009", resourceCulture); + } + } + + /// <summary> + /// You do not do anything with 'no' overwrite with 'yes' stop 'Cancel' に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0010 { + get { + return ResourceManager.GetString("M0010", resourceCulture); + } + } + + /// <summary> + /// Overwrite Confirmation に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0011 { + get { + return ResourceManager.GetString("M0011", resourceCulture); + } + } + + /// <summary> + /// Current directory に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0012 { + get { + return ResourceManager.GetString("M0012", resourceCulture); + } + } + + /// <summary> + /// Start-up conditions に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0013 { + get { + return ResourceManager.GetString("M0013", resourceCulture); + } + } + + /// <summary> + /// Value に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0014 { + get { + return ResourceManager.GetString("M0014", resourceCulture); + } + } + + /// <summary> + /// Command value に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string M0015 { + get { + return ResourceManager.GetString("M0015", resourceCulture); + } + } + + /// <summary> + /// Successful completion に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string S0001 { + get { + return ResourceManager.GetString("S0001", resourceCulture); + } + } + + /// <summary> + /// Abnormal termination に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string S0002 { + get { + return ResourceManager.GetString("S0002", resourceCulture); + } + } + + /// <summary> + /// Compression に類似しているローカライズされた文字列を検索します。 + /// </summary> + internal static string T0001 { + get { + return ResourceManager.GetString("T0001", resourceCulture); + } + } + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Resources/Resource.ja-JP.resx b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Resources/Resource.ja-JP.resx new file mode 100644 index 000000000..b9cff720f --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Resources/Resource.ja-JP.resx @@ -0,0 +1,318 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="A0001" xml:space="preserve"> + <value>/HELP HELPを表示します。</value> + </data> + <data name="A0002" xml:space="preserve"> + <value>/CUI CUIで起動します。</value> + </data> + <data name="A0003" xml:space="preserve"> + <value>以下、CUI時のみ有効なオプション引数</value> + </data> + <data name="A0004" xml:space="preserve"> + <value>/FORCE 履歴ファイルを消去して強制更新します。</value> + </data> + <data name="A0005" xml:space="preserve"> + <value>/QUIET クワイエット モードで実行します(メッセージを非表示)。</value> + </data> + <data name="A0006" xml:space="preserve"> + <value>/SILENT サイレント モードで実行します(メッセージ、進捗を非表示)。</value> + </data> + <data name="A0007" xml:space="preserve"> + <value>/NB マニフェストファイルで起動指示アセンブリが指定されていても無視します。</value> + </data> + <data name="A0008" xml:space="preserve"> + <value>/WWWURL \"http://xxxx\" WWWサーバ上のマニュフェスト ファイルへのURLを指定します。</value> + </data> + <data name="A0009" xml:space="preserve"> + <value>/WWWUID xxxx WWWサーバへアクセスする際のユーザIDを指定します。</value> + </data> + <data name="A0010" xml:space="preserve"> + <value>/WWWPWD xxxx WWWサーバへアクセスする際のパスワードを指定します。</value> + </data> + <data name="A0011" xml:space="preserve"> + <value>/WWWDomain xxxx WWWサーバへアクセスする際のドメインを指定します。</value> + </data> + <data name="A0012" xml:space="preserve"> + <value>/ProxyURL \"http://yyyy\" ProxyサーバへのURLを指定します。</value> + </data> + <data name="A0013" xml:space="preserve"> + <value>指定の無い場合は、IE設定を適用します。</value> + </data> + <data name="A0014" xml:space="preserve"> + <value>[none]指定時はプロキシを使用しません。</value> + </data> + <data name="A0015" xml:space="preserve"> + <value>/ProxyUID yyyy Proxyサーバへアクセスする際のユーザIDを指定します。</value> + </data> + <data name="A0016" xml:space="preserve"> + <value>/ProxyPWD yyyy Proxyサーバへアクセスする際のパスワードを指定します。</value> + </data> + <data name="A0017" xml:space="preserve"> + <value>/ProxyDomain yyyy Proxyサーバへアクセスする際のドメインを指定します。</value> + </data> + <data name="A0018" xml:space="preserve"> + <value>/UnIns \"http://xxxx\" WWWサーバ上のマニュフェスト ファイルへのURLを指定します(アンインストール)。</value> + </data> + <data name="E0001" xml:space="preserve"> + <value>エラーが発生しました。</value> + </data> + <data name="E0002" xml:space="preserve"> + <value>削除例外:</value> + </data> + <data name="Error0001" xml:space="preserve"> + <value>エラー</value> + </data> + <data name="Error0002" xml:space="preserve"> + <value>サマリ(圧縮)</value> + </data> + <data name="Error0003" xml:space="preserve"> + <value>サマリ(解凍)</value> + </data> + <data name="EXT0001" xml:space="preserve"> + <value>ZIPファイル|*.zip</value> + </data> + <data name="I0001" xml:space="preserve"> + <value>{0} の作成開始</value> + </data> + <data name="I0002" xml:space="preserve"> + <value>{0} の書き込み開始</value> + </data> + <data name="I0003" xml:space="preserve"> + <value>{0}/{1} バイト 書き込みました</value> + </data> + <data name="I0004" xml:space="preserve"> + <value>{0} の書き込み終了</value> + </data> + <data name="I0005" xml:space="preserve"> + <value>{0} 個中 {1} 個のエントリの書き込みが完了しました</value> + </data> + <data name="I0006" xml:space="preserve"> + <value>{0} の作成終了</value> + </data> + <data name="M0001" xml:space="preserve"> + <value>メッセージ</value> + </data> + <data name="M0002" xml:space="preserve"> + <value><メッセージ></value> + </data> + <data name="M0003" xml:space="preserve"> + <value><スタック トレース></value> + </data> + <data name="M0004" xml:space="preserve"> + <value><内部例外></value> + </data> + <data name="M0005" xml:space="preserve"> + <value>メッセージ</value> + </data> + <data name="M0006" xml:space="preserve"> + <value>CUI起動</value> + </data> + <data name="M0007" xml:space="preserve"> + <value>GUI起動</value> + </data> + <data name="M0008" xml:space="preserve"> + <value>削除例外:</value> + </data> + <data name="M0009" xml:space="preserve"> + <value>'はすでに存在します。</value> + </data> + <data name="M0010" xml:space="preserve"> + <value>'はい'で上書き 'いいえ'で何もしない 'キャンセル'で中止</value> + </data> + <data name="M0011" xml:space="preserve"> + <value>上書きの確認</value> + </data> + <data name="M0012" xml:space="preserve"> + <value>カレント ディレクトリ</value> + </data> + <data name="M0013" xml:space="preserve"> + <value>起動条件</value> + </data> + <data name="M0014" xml:space="preserve"> + <value>値</value> + </data> + <data name="M0015" xml:space="preserve"> + <value>コマンド・値</value> + </data> + <data name="S0001" xml:space="preserve"> + <value>正常終了</value> + </data> + <data name="S0002" xml:space="preserve"> + <value>異常終了</value> + </data> + <data name="T0001" xml:space="preserve"> + <value>圧縮</value> + </data> + <data name="I0007" xml:space="preserve"> + <value>{0} 件のファイルを圧縮しました。</value> + </data> + <data name="I0008" xml:space="preserve"> + <value>{0} 件のファイルを解凍しました。</value> + </data> + <data name="A0019" xml:space="preserve"> + <value>/MFTGEN マニュフェスト ファイルを生成します。以下の引数が必須です。</value> + </data> + <data name="A0020" xml:space="preserve"> + <value>/ZIPFILES \"a.zip,b.zip\" 対象のZIPファイルを指定します(カンマ区切り)。</value> + </data> + <data name="A0021" xml:space="preserve"> + <value>/INSDIR xxxx インストール先ディレクトリを指定します。 /EXENAME xxxx 起動アセンブリを指定します(カンマ区切り)。</value> + </data> + <data name="A0022" xml:space="preserve"> + <value>/MFTFILE xxxx 生成するマニュフェスト ファイルを指定します。</value> + </data> + <data name="A0023" xml:space="preserve"> + <value>/MFTGEN には /ZIPFILES /INSDIR /EXENAME /MFTFILE が必要です。</value> + </data> + <data name="A0024" xml:space="preserve"> + <value>マニュフェスト ファイルを生成しました。[{0}]</value> + </data> + <data name="A0025" xml:space="preserve"> + <value>/ZIPGEN ZIPファイルを生成します。/SRCDIR と /ZIPFILE が必須です。</value> + </data> + <data name="A0026" xml:space="preserve"> + <value>/SRCDIR xxxx 圧縮対象のフォルダを指定します。</value> + </data> + <data name="A0027" xml:space="preserve"> + <value>/ZIPFILE xxxx 生成するZIPを指定します(拡張子は付けない)。</value> + </data> + <data name="A0028" xml:space="preserve"> + <value>/ROOTINZIP xxxx 書庫内ルート フォルダを指定します。省略時は書庫内ルートを作りません。</value> + </data> + <data name="A0029" xml:space="preserve"> + <value>/TOPONLY /SRCDIR 直下のファイルだけを圧縮します(サブフォルダを再帰しない)。</value> + </data> + <data name="A0030" xml:space="preserve"> + <value>/EXCLUDEEXT \"txt,csv\" 除外する拡張子を指定します(カンマ区切り)。</value> + </data> + <data name="A0031" xml:space="preserve"> + <value>/CYP xxxx 暗号化(None, PkzipWeak, WinZipAes128, WinZipAes256)。 /PASS xxxx パスワード。 /CMPLV xxxx 圧縮レベル(None, BestSpeed, Default, BestCompression)。 /ENC xxxx 文字コード。</value> + </data> + <data name="A0032" xml:space="preserve"> + <value>/ZIPGEN には /SRCDIR と /ZIPFILE が必要です。</value> + </data> + <data name="A0033" xml:space="preserve"> + <value>ZIPファイルを生成しました。[{0}] {1} 件。</value> + </data> + <data name="A0034" xml:space="preserve"> + <value>認識できない引数です : {0} 使い方は /HELP を参照してください。(引数がある場合、GUI は起動しません)</value> + </data> +</root> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Resources/Resource.resx b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Resources/Resource.resx new file mode 100644 index 000000000..716c03a23 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Resources/Resource.resx @@ -0,0 +1,318 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="A0001" xml:space="preserve"> + <value>/HELP Show me the HELP.</value> + </data> + <data name="A0002" xml:space="preserve"> + <value>/CUI I will start in CUI CUI.</value> + </data> + <data name="A0003" xml:space="preserve"> + <value>Below, valid options argument only when CUI</value> + </data> + <data name="A0004" xml:space="preserve"> + <value>/ Force update to erase the FORCE history file.</value> + </data> + <data name="A0005" xml:space="preserve"> + <value>/QUIET (Hide the message) that you can run in quiet mode .</value> + </data> + <data name="A0006" xml:space="preserve"> + <value>/SILENT (Hide message, the progress) that will run in silent mode.</value> + </data> + <data name="A0007" xml:space="preserve"> + <value>/NB Ignore start instruction assembly even if they are specified in the manifest file.</value> + </data> + <data name="A0008" xml:space="preserve"> + <value>/WWWURL I Specifies the URL to the manifest file of \ "http://xxxx \" WWW server.</value> + </data> + <data name="A0009" xml:space="preserve"> + <value>/WWWUID xxxx WWW Specifies the user ID when accessing the server.</value> + </data> + <data name="A0010" xml:space="preserve"> + <value>/WWWPWD xxxx WWW Specifies the password used to access the server.</value> + </data> + <data name="A0011" xml:space="preserve"> + <value>/WWWDomain xxxx WWW You specify the domain when accessing to the server.</value> + </data> + <data name="A0012" xml:space="preserve"> + <value>/ProxyURL \"http://yyyy\" Proxy I specify the URL to the server.</value> + </data> + <data name="A0013" xml:space="preserve"> + <value>If it is not specified, and then apply the IE setting.</value> + </data> + <data name="A0014" xml:space="preserve"> + <value>It does not use a proxy [none] is specified.</value> + </data> + <data name="A0015" xml:space="preserve"> + <value>/ProxyUID yyyy Proxy Specifies the user ID when accessing the server.</value> + </data> + <data name="A0016" xml:space="preserve"> + <value>/ProxyPWD yyyy Proxy Specifies the password used to access the server.</value> + </data> + <data name="A0017" xml:space="preserve"> + <value>/ProxyDomain yyyy Proxy You specify the domain when accessing to the server.</value> + </data> + <data name="A0018" xml:space="preserve"> + <value>/UnIns \"http://xxxx\" WWW Specify the URL to the manifest file on the server (uninstall).</value> + </data> + <data name="E0001" xml:space="preserve"> + <value>An error has occurred.</value> + </data> + <data name="E0002" xml:space="preserve"> + <value>Delete Exception:</value> + </data> + <data name="Error0001" xml:space="preserve"> + <value>Error</value> + </data> + <data name="Error0002" xml:space="preserve"> + <value>Summary (compression)</value> + </data> + <data name="Error0003" xml:space="preserve"> + <value>Summary (De)</value> + </data> + <data name="EXT0001" xml:space="preserve"> + <value>ZIP file |*.Zip</value> + </data> + <data name="I0001" xml:space="preserve"> + <value>Production start of {0}</value> + </data> + <data name="I0002" xml:space="preserve"> + <value>Write start of {0}</value> + </data> + <data name="I0003" xml:space="preserve"> + <value>I wrote {0} / {1} bytes</value> + </data> + <data name="I0004" xml:space="preserve"> + <value>Write end of {0}</value> + </data> + <data name="I0005" xml:space="preserve"> + <value>Writing of entry for {1} (s) has (have) completed {0} or in</value> + </data> + <data name="I0006" xml:space="preserve"> + <value>Creation end of {0}</value> + </data> + <data name="M0001" xml:space="preserve"> + <value>Message</value> + </data> + <data name="M0002" xml:space="preserve"> + <value><Message></value> + </data> + <data name="M0003" xml:space="preserve"> + <value><Stack trace></value> + </data> + <data name="M0004" xml:space="preserve"> + <value><Internal exception></value> + </data> + <data name="M0005" xml:space="preserve"> + <value>Message</value> + </data> + <data name="M0006" xml:space="preserve"> + <value>CUI start</value> + </data> + <data name="M0007" xml:space="preserve"> + <value>GUI boot</value> + </data> + <data name="M0008" xml:space="preserve"> + <value>Delete Exception:</value> + </data> + <data name="M0009" xml:space="preserve"> + <value>'Already exists.</value> + </data> + <data name="M0010" xml:space="preserve"> + <value>You do not do anything with 'no' overwrite with 'yes' stop 'Cancel'</value> + </data> + <data name="M0011" xml:space="preserve"> + <value>Overwrite Confirmation</value> + </data> + <data name="M0012" xml:space="preserve"> + <value>Current directory</value> + </data> + <data name="M0013" xml:space="preserve"> + <value>Start-up conditions</value> + </data> + <data name="M0014" xml:space="preserve"> + <value>Value</value> + </data> + <data name="M0015" xml:space="preserve"> + <value>Command value</value> + </data> + <data name="S0001" xml:space="preserve"> + <value>Successful completion</value> + </data> + <data name="S0002" xml:space="preserve"> + <value>Abnormal termination</value> + </data> + <data name="T0001" xml:space="preserve"> + <value>Compression</value> + </data> + <data name="I0007" xml:space="preserve"> + <value>{0} file(s) were compressed.</value> + </data> + <data name="I0008" xml:space="preserve"> + <value>{0} file(s) were extracted.</value> + </data> + <data name="A0019" xml:space="preserve"> + <value>/MFTGEN Creates a manifest file. The following arguments are required.</value> + </data> + <data name="A0020" xml:space="preserve"> + <value>/ZIPFILES \"a.zip,b.zip\" Specifies the ZIP files (comma separated).</value> + </data> + <data name="A0021" xml:space="preserve"> + <value>/INSDIR xxxx Specifies the installation directory. /EXENAME xxxx Specifies the assemblies to start (comma separated).</value> + </data> + <data name="A0022" xml:space="preserve"> + <value>/MFTFILE xxxx Specifies the manifest file to create.</value> + </data> + <data name="A0023" xml:space="preserve"> + <value>/MFTGEN requires /ZIPFILES, /INSDIR, /EXENAME and /MFTFILE.</value> + </data> + <data name="A0024" xml:space="preserve"> + <value>The manifest file was created. [{0}]</value> + </data> + <data name="A0025" xml:space="preserve"> + <value>/ZIPGEN Creates a ZIP file. /SRCDIR and /ZIPFILE are required.</value> + </data> + <data name="A0026" xml:space="preserve"> + <value>/SRCDIR xxxx Specifies the folder to compress.</value> + </data> + <data name="A0027" xml:space="preserve"> + <value>/ZIPFILE xxxx Specifies the ZIP to create (without extension).</value> + </data> + <data name="A0028" xml:space="preserve"> + <value>/ROOTINZIP xxxx Specifies the root folder in the archive. If omitted, no root folder is created.</value> + </data> + <data name="A0029" xml:space="preserve"> + <value>/TOPONLY Compresses only the files directly under /SRCDIR (no recursion).</value> + </data> + <data name="A0030" xml:space="preserve"> + <value>/EXCLUDEEXT \"txt,csv\" Specifies the extensions to exclude (comma separated).</value> + </data> + <data name="A0031" xml:space="preserve"> + <value>/CYP xxxx Encryption (None, PkzipWeak, WinZipAes128, WinZipAes256). /PASS xxxx Password. /CMPLV xxxx Compression level (None, BestSpeed, Default, BestCompression). /ENC xxxx Encoding.</value> + </data> + <data name="A0032" xml:space="preserve"> + <value>/ZIPGEN requires /SRCDIR and /ZIPFILE.</value> + </data> + <data name="A0033" xml:space="preserve"> + <value>The ZIP file was created. [{0}] {1} file(s).</value> + </data> + <data name="A0034" xml:space="preserve"> + <value>Unknown argument(s): {0} Run /HELP to see the usage. (The GUI is not opened when arguments are given.)</value> + </data> +</root> \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/data1.csv b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/data1.csv new file mode 100644 index 000000000..8bee5e353 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/data1.csv @@ -0,0 +1,3 @@ +id,name,value +1,あいうえお,100 +2,かきくけこ,200 diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.deps.json b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.deps.json new file mode 100644 index 000000000..f950613a3 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.deps.json @@ -0,0 +1,23 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v10.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v10.0": { + "top1/1.0.0": { + "runtime": { + "top1.dll": {} + } + } + } + }, + "libraries": { + "top1/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.dll b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.dll new file mode 100644 index 000000000..a5fd2214e Binary files /dev/null and b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.dll differ diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.exe b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.exe new file mode 100644 index 000000000..93a3cc6f1 Binary files /dev/null and b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.exe differ diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.runtimeconfig.json b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.runtimeconfig.json new file mode 100644 index 000000000..f730443cc --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/top1.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net10.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "10.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git "a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/\343\202\265\343\203\226 \343\203\225\343\202\251\343\203\253\343\203\200/deep.txt" "b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/\343\202\265\343\203\226 \343\203\225\343\202\251\343\203\253\343\203\200/deep.txt" new file mode 100644 index 000000000..b5d6c65e1 --- /dev/null +++ "b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/aaa/\343\202\265\343\203\226 \343\203\225\343\202\251\343\203\253\343\203\200/deep.txt" @@ -0,0 +1 @@ +2 階層目のファイルです(フォルダ名に日本語と空白を含む)。 diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/data2.txt b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/data2.txt new file mode 100644 index 000000000..87437a963 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/data2.txt @@ -0,0 +1 @@ +bbb のデータ ファイルです。 diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.deps.json b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.deps.json new file mode 100644 index 000000000..0939987fd --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.deps.json @@ -0,0 +1,23 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v10.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v10.0": { + "top2/1.0.0": { + "runtime": { + "top2.dll": {} + } + } + } + }, + "libraries": { + "top2/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.dll b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.dll new file mode 100644 index 000000000..bd0e7ad0f Binary files /dev/null and b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.dll differ diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.exe b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.exe new file mode 100644 index 000000000..887f5b3e8 Binary files /dev/null and b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.exe differ diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.runtimeconfig.json b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.runtimeconfig.json new file mode 100644 index 000000000..f730443cc --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/bbb/top2.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net10.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "10.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/ccc/doc1.txt b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/ccc/doc1.txt new file mode 100644 index 000000000..3b0c9a7e9 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/ccc/doc1.txt @@ -0,0 +1 @@ +ccc のドキュメント 1 です。 diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/ccc/doc2.txt b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/ccc/doc2.txt new file mode 100644 index 000000000..4e54c1cf2 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/ccc/doc2.txt @@ -0,0 +1 @@ +ccc のドキュメント 2 です。 diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/ccc/doc3.txt b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/ccc/doc3.txt new file mode 100644 index 000000000..23cdecc4b --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/ccc/doc3.txt @@ -0,0 +1 @@ +ccc のドキュメント 3 です。 diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/data.bin b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/data.bin new file mode 100644 index 000000000..8fe6fddda Binary files /dev/null and b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/data.bin differ diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/readme.txt b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/readme.txt new file mode 100644 index 000000000..a52562d6f --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/readme.txt @@ -0,0 +1,2 @@ +DeployZipPackWithHTTP の配布確認用サンプルです。 +top.exe を実行すると、自分の居場所と同梱ファイルを表示します。 diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.deps.json b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.deps.json new file mode 100644 index 000000000..53a1e4e53 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.deps.json @@ -0,0 +1,23 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v10.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v10.0": { + "top/1.0.0": { + "runtime": { + "top.dll": {} + } + } + } + }, + "libraries": { + "top/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.dll b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.dll new file mode 100644 index 000000000..0d485d7a7 Binary files /dev/null and b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.dll differ diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.exe b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.exe new file mode 100644 index 000000000..79f43da36 Binary files /dev/null and b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.exe differ diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.runtimeconfig.json b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.runtimeconfig.json new file mode 100644 index 000000000..f730443cc --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/top.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net10.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "10.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git "a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/\350\250\255\345\256\232\343\203\225\343\202\241\343\202\244\343\203\253.txt" "b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/\350\250\255\345\256\232\343\203\225\343\202\241\343\202\244\343\203\253.txt" new file mode 100644 index 000000000..b743bcabe --- /dev/null +++ "b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/FormAppRoot/\350\250\255\345\256\232\343\203\225\343\202\241\343\202\244\343\203\253.txt" @@ -0,0 +1 @@ +日本語のファイル名を含めています(文字コードの確認用)。 diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/SampleConsoleApp/Program.cs b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/SampleConsoleApp/Program.cs new file mode 100644 index 000000000..96c612973 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/SampleConsoleApp/Program.cs @@ -0,0 +1,107 @@ +#region Apache License +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#endregion + +//********************************************************************************** +//* クラス名 :Program +//* クラス日本語名 :配布確認用のコンソール アプリケーション +//* +//* 作成者 :玄人 幸道 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 2026/08/08 玄人 幸道 新規作成(#528) +//********************************************************************************** + +using System; +using System.IO; + +namespace SampleConsoleApp +{ + /// <summary>配布確認用のコンソール アプリケーション</summary> + /// <remarks> + /// DeployZipPackWithHTTP で配布したものが、 + /// **配置先で動くこと**を目で確かめるためのサンプル(#528)。 + /// + /// 自分が置かれたディレクトリとその中身を出して、キー入力で終わる。 + /// 配置先が意図した場所か、同梱ファイルが揃っているかが、これで分かる。 + /// </remarks> + public class Program + { + /// <summary>Main</summary> + /// <param name="args">string[]</param> + public static void Main(string[] args) + { + // 実行ファイルの場所 + // + // **カレント ディレクトリを見てはいけない。** 呼び出し側の作業ディレクトリになり、 + // 配布ツールが起動した場合はツール側のカレントを引き継いでしまう。 + // 「配置先で動いているか」を見たいので、自分の居場所を採る。 + string baseDir = AppContext.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar); + + Console.WriteLine("実行ファイルの場所"); + Console.WriteLine(" " + baseDir); + Console.WriteLine(""); + + #region 実行ファイルの場所の一覧 + + Console.WriteLine("同じ場所にあるファイルの一覧"); + + try + { + string[] dirs = Directory.GetDirectories(baseDir); + Array.Sort(dirs, StringComparer.Ordinal); + + foreach (string dir in dirs) + { + Console.WriteLine(" [D] " + Path.GetFileName(dir)); + } + + string[] files = Directory.GetFiles(baseDir); + Array.Sort(files, StringComparer.Ordinal); + + foreach (string file in files) + { + FileInfo f = new FileInfo(file); + Console.WriteLine(string.Format(" [F] {0} ({1:N0} バイト)", f.Name, f.Length)); + } + + Console.WriteLine(""); + Console.WriteLine(string.Format( + " フォルダ {0} 件 / ファイル {1} 件", dirs.Length, files.Length)); + } + catch (Exception ex) + { + // メッセージは環境の言語で変わるため、型名も出す。 + Console.WriteLine(" 一覧を取得できませんでした : " + ex.GetType().FullName); + Console.WriteLine(" " + ex.Message); + } + + #endregion + + Console.WriteLine(""); + Console.WriteLine("何かキーを押すと終了します。"); + + // **リダイレクト時は例外になる。** 標準入力が無い状態で ReadKey を呼ぶため。 + // 非対話で実行されることもあるので、握り潰して終わる。 + try + { + Console.ReadKey(); + } + catch { } + } + } +} diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/SampleConsoleApp/SampleConsoleApp.csproj b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/SampleConsoleApp/SampleConsoleApp.csproj new file mode 100644 index 000000000..e96fa393a --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/Sample/SampleConsoleApp/SampleConsoleApp.csproj @@ -0,0 +1,12 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>net10.0</TargetFramework> + <RootNamespace>SampleConsoleApp</RootNamespace> + <AssemblyName>SampleConsoleApp</AssemblyName> + <ImplicitUsings>disable</ImplicitUsings> + <Nullable>disable</Nullable> + </PropertyGroup> + +</Project> diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/app.config b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/app.config new file mode 100644 index 000000000..2524d1712 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/app.config @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<configuration> + <appSettings> + <!-- リソース ファイルの場合 --> + <!--<add key="FxXMLMSGDefinition" value="MSGDefinition.xml"/>--> + <add key="FxLog4NetConfFile" value="Log4DeployZipPackWithHTTP.xml"/> + <!-- 埋め込まれたリソースの場合 --> + <add key="FxXMLMSGDefinition" value="DeployZipPackWithHTTP.MSGDefinition.xml"/> + <!--add key="FxLog4NetConfFile" value="DeployZipPackWithHTTP.Log4DeployZipPackWithHTTP.xml" /--> + <!--非同期呼び出し処理の多重度(2以上の設定が必須)--> + <add key="FxMaxThreadCount" value="3"/> + <!--プログレスダイアログが閉じるまでの待機設定(秒)--> + <add key="PDWSleepSec" value="1"/> + <add key="DefaultCulture" value="ja-JP"/> + <!--add key="FxBusinessMessageCulture" value="en-US"/--> + <add key="ClientSettingsProvider.ServiceUri" value=""/> + </appSettings> +</configuration> diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/app.ico b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/app.ico new file mode 100644 index 000000000..c96147f2d Binary files /dev/null and b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/app.ico differ diff --git a/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/appsettings.json b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/appsettings.json new file mode 100644 index 000000000..6de259a69 --- /dev/null +++ b/root/programs/CS/Frameworks/Tools/DeployZipPackWithHTTP/appsettings.json @@ -0,0 +1,18 @@ +{ + // appSettings section + "appSettings": { + // リソース ファイルの場合 + //"FxXMLMSGDefinition": "MSGDefinition.xml", + "FxLog4NetConfFile": "Log4DeployZipPackWithHTTP.xml", + // 埋め込まれたリソースの場合 + "FxXMLMSGDefinition": "DeployZipPackWithHTTP.MSGDefinition.xml", + //"FxLog4NetConfFile": "DeployZipPackWithHTTP.Log4DeployZipPackWithHTTP.xml", + // 非同期呼び出し処理の多重度(2以上の設定が必須) + "FxMaxThreadCount": "3", + // プログレスダイアログが閉じるまでの待機設定(秒) + "PDWSleepSec": "1", + "DefaultCulture": "ja-JP", + // "FxBusinessMessageCulture": "en-US", + "ClientSettingsProvider.ServiceUri": "" + } +} \ No newline at end of file diff --git a/root/programs/CS/NuGet/README.md b/root/programs/CS/NuGet/README.md new file mode 100644 index 000000000..4e3c7f611 --- /dev/null +++ b/root/programs/CS/NuGet/README.md @@ -0,0 +1,679 @@ +# NuGet パッケージの作成と公開 + +パッケージの作成と公開の手順。 +**シンボル サーバー(`.snupkg`)とソース サーバー(Source Link)を機能させる**ところまでを含む。 + +> **一次情報は本書ではない部分がある。** +> +> | 内容 | 一次情報 | +> |---|---| +> | リリース時の作業全体 | [`RELEASE.md`](../../RELEASE.md) | +> | ビルド構成・バージョン管理 | [`Frameworks/ANALYSIS.md`](../Frameworks/ANALYSIS.md) 7 章 | +> | リリース・エンジニアリング | [Open 棟梁 Wiki](https://opentouryo.osscons.jp/index.php?%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%83%BB%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0) | +> | パッケージ作成 | [Wiki : HowToCreateOpenTouryoNuGetPackages.ja](https://github.com/OpenTouryoProject/OpenTouryo/wiki/HowToCreateOpenTouryoNuGetPackages.ja) | +> +> 上 2 つの Wiki とは重複があるので、最終的には統合する。 + +--- + +## 1. 本番手順 + +**α・β版などを使用して、2 回以上繰り返す**(プレ、本番)。 + +### (0)どのコミットから詰めるかを決める + +**`_NuGetPack.bat` は `git rev-parse HEAD` の値を nuspec と PDB に埋め込む。** +以後、そのパッケージは**そのコミットに固定される**(詳細は 7 節)。 + +したがって、**正式版は master へマージし、タグを打った後に詰める。** + +``` +1. develop → master へマージ(--no-ff) +2. タグ(03-30 など)をプッシュ +3. master(=タグのコミット)で(2)以降を行う +``` + +こうすると**タグ・コミット・パッケージの 3 つが一致する。** + +develop 段階で先に詰めると、次の 2 点で困る。 + +- **同じバージョンは一度しか公開できない。** nuget.org は再アップロードを受け付けず、 + 取り消しも unlist(一覧から隠す)だけである。公開後にマージ時の修正が入っても、 + **公開済みの `3.3.0` は永久に古いまま**になる +- 公開後に develop へコミットが載ると、**タグとパッケージが別のコミットを指す。** + `<repository commit>` は nuget.org 上に表示されるため、外から食い違いが分かる + +**develop 段階で試したい場合はプレリリース版を使う**(`3.3.0-alpha1` など)。 +それがこの節の冒頭「2 回以上繰り返す」の意味である。 +**`3.3.0` という番号は、タグ付きコミットのために取っておく。** + +### (1)リリース・エンジニアリングの手順を実施する + +[`RELEASE.md`](../../RELEASE.md) に従い、検証 3 本を通しておく。 + +### (2)ビルドを行う + +``` +root\programs\CS\0_Release4Nuget.bat +``` + +**`DebugType` を手で書き換える必要は無い**(#531)。 +このバッチが次の 2 つを指定し、`z_Common.bat` は +**呼び出し側が設定済みならその値を尊重する。** + +| 変数 | 渡す値 | 既定(通常のビルド) | +|---|---|---| +| `DEBUG_TYPE` | `portable` | `full` | +| `CI_BUILD` | `true` → `/p:ContinuousIntegrationBuild=true` + `/p:DeterministicSourcePaths=true` | `false` | + +`ContinuousIntegrationBuild` は、**PDB に記録されるソースのパスを `/_/...` に正規化する。** + +``` +無効 C:\OpenTouryo\root\programs\CS\Frameworks\Infrastructure\Public\Db\DamODBC.cs +有効 /_/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamODBC.cs +``` + +これが要る理由は 2 つある。 + +- **公開物に、ビルドしたマシンのローカル パスが埋まらない** +- **Visual Studio は「PDB のパスにファイルが在れば、それを開く」。** + 絶対パスのままだと、**ビルドしたマシンでは Source Link を通らない**ため、 + 4 節の確認が「ローカルのソースが開いただけ」になり、検証にならない + +> **`DeterministicSourcePaths` も渡す必要がある。** +> `ContinuousIntegrationBuild` から `DeterministicSourcePaths` への変換は +> `Microsoft.NET.Sdk` のターゲットが行うため、**旧形式 csproj には効かない。** +> 渡さないと **net48 側だけ絶対パスのまま残る**(Source Link の自動組み込みが +> 効かないのと同じ構図。5 節を参照)。 + +### (3)パッケージングを行う + +``` +root\programs\CS\NuGet\_NuGetPack.bat +``` + +このバッチが次を行う。 + +- バージョンを `Directory.Build.props` から読む +- **net48 の `AssemblyVersion` が、それと一致するかを検査する**(後述) +- `Build_*` から `in\` へ dll / pdb / xml を複製する +- **コミット ハッシュを git から読み、nuspec の `<repository>` へ渡す** +- `.nupkg` と `.snupkg` を `out\sp` に出す + +#### net48 の版の検査 + +**`Directory.Build.props` は旧形式 csproj に効かない。** +net48 の版は各プロジェクトの `Properties\AssemblyInfo.cs` が持つ。 + +`OpenTouryoVersion` だけ上げて追随を忘れると、**同じパッケージの中で +net48 と net10.0 のアセンブリの版が食い違う。公開後には直せない。** + +そこで、パッケージ化の前に 6 本を照合し、ずれていれば停止する。 + +``` + OK Public : 3.0.0 + NG Framework : 3.0.0 expected 3.1.0 +[ERROR] The net48 AssemblyVersion does not match OpenTouryoVersion = 3.1.0 +``` + +対象は**パッケージに入る 6 本**(`DamPstGrS` は net48 が無い。 +`Business` は非パッケージかつ意図的に別系統の `1.0.0`)。 + +#### 詰めたアセンブリの検査 + +**上の検査は、ソースどうしを突き合わせているだけである。** +`Directory.Build.props` と `AssemblyInfo.cs` の両方を更新してあれば通る。 +**ビルドを飛ばしたことは、原理的に検出できない。** + +``` +0_SetVersion.ps1 3.4.0 →(0_Release4Nuget.bat を飛ばす)→ _NuGetPack.bat + ソースは 3.4.0 Build_* は 3.3.0 のまま + → ソース側の検査は OK → 中身が 3.3.0 のパッケージが 3.4.0 として出る +``` + +そこで、`in\` へ複製した**後**、`nuget pack` の**前**に、 +**実際の DLL の `AssemblyVersion`** を照合する。 + +``` +Checking the packaged assemblies against 3.4.0. + NG in\net48\OpenTouryo.Public.dll : 3.3.0.0 expected 3.4.0.x +[ERROR] The packaged assemblies do not carry 3.4.0 + so the rebuild was skipped. Run CS\0_Release4Nuget.bat, +``` + +**対象は nuspec の `<file>` から取っている**ので、パッケージを増やしても +このバッチを直さなくてよい。`OpenTouryo.Business.dll` はどの nuspec にも +無いため対象外である(意図的に別系統の `1.0.0`)。 + +> `symbol_template.nuspec` は除外している。 +> **Windows のグロブは大文字小文字を区別しない**ため、`Symbol_*.nuspec` が +> テンプレートにも一致し、プレースホルダ(`OpenTouryo.xxxx.dll`)を +> 「見つからない」と報告してしまう。 + +| 検査 | 捕まえる間違い | +|---|---| +| **ソース側** | `AssemblyInfo.cs` の追随忘れ。**ビルド前に止まる**ので、無駄なビルドをしない | +| **DLL 側** | **リビルド忘れ**。ソース側では検出できない | + +**`_T_NuGetPack.bat` には、どちらの検査も無い。** +テスト用パッケージは版を**引数で受け取り**、`OpenTouryoVersion` を読まない。 +版はパッケージに名前を付けるだけで**アセンブリには書き込まれない**ため、 +**照合すべき期待値が無い。** + +> **補足 : パッケージの版とアセンブリの版は、一致しなくてよい。** +> +> NuGet の制約ではなく慣習である。実際、テスト公開した +> `Erutcurtsarfni.Oyruot.Public 3.3.0-alpha2` の中身はこうなっている。 +> +> ``` +> パッケージの版 3.3.0-alpha2 +> lib/net48 の DLL AssemblyVersion = 3.0.0.0 +> lib/net10.0 の DLL AssemblyVersion = 3.0.0.0 +> ``` +> +> これで正常にインストールでき、ステップインもできる。 +> **テスト用パッケージが引数の版で成立するのは、これが理由。** +> +> **検査が見ているのは、パッケージの版とアセンブリの版の一致ではない。** +> 同じパッケージに入る **net48 と net10.0 のアセンブリどうしが揃っているか**である。 +> 上の例では両方 `3.0.0.0` で揃っている。`OpenTouryoVersion` だけ上げると +> net10.0 側だけが動き、ここが崩れる。 + +**プッシュの前に 2 節の確認を行うこと。** + +### (4)NuGet にプッシュする + +API キーを NuGet サイトから取得し、**環境変数で渡してから**実行する。 + +``` +set NUGET_API_KEY=<nuget.org で発行したキー> +root\programs\CS\NuGet\out\sp\_NuGetPush.bat +``` + +**最新では `sp` の方だけでよい。** `pp` の方はシンボルを登録しないケースで利用可。 + +**キーを bat に直書きしてはならない**(#531)。理由は 8 節。 + +キーは**スコープ(対象パッケージ)と有効期限を絞り、使用後に nuget.org 側で削除**する。 + +> **Trusted Publishing は使えない。** +> nuget.org は API キーより Trusted Publishing を推奨しているが、 +> これは **GitHub Actions からの公開にのみ対応**する仕組みである。 +> 本手順は人がコマンドラインから実行するため、対象外(nuget.org の案内にも +> 「コマンドラインからの公開……APIキーは引き続き使用できます」とある)。 +> Actions へ移すなら別途検討する。 + +### (5)後始末 + +**revert するものは無い**(#531)。 + +| | | +|---|---| +| API キー | **環境変数なので、コンソールを閉じれば消える** | +| `z_Common.bat` の `DEBUG_TYPE` | **もう書き換えないので不要** | + +### (6)テスト プロジェクトで確認する + +シンボル サーバー、ソース サーバーが機能するかどうかを確認する(4 節)。 + +--- + +## 2. 公開前の確認 + +**プッシュは取り消しが困難**なので、(3)の後・(4)の前に確認する。 + +### 確認 1 : `.nupkg` と `.snupkg` が対で出ていること + +`out\sp` に、同じ名前・同じバージョンで両方があること。 +**`.nupkg` に `.pdb` が入っていないこと**(`nuget.exe` が `.snupkg` 側へ振り分ける)。 + +### 確認 2 : PDB が portable であること + +`.snupkg` 内の `.pdb` の**先頭 4 バイトが `BSJB`** であること。 + +``` +BSJB → portable PDB(正しい) +Micr → Windows PDB(nuget.org は受け付けない) +``` + +`Micr` なら `DEBUG_TYPE` が `portable` になっていない。(2)をやり直す。 + +### 確認 3 : Source Link の情報が入っていること + +`.pdb` の中に次の形の URL があること。 + +``` +https://raw.githubusercontent.com/OpenTouryoProject/OpenTouryo/<commit>/* +``` + +**net48 と net10.0 の両方を見ること。** +net10.0 は .NET 8 以降の SDK が自動で入れるが、 +**net48(旧形式 csproj)は `Microsoft.SourceLink.GitHub` を明示的に参照している。** +参照が外れると **net48 側だけ静かに機能しなくなる。** + +```powershell +Add-Type -AssemblyName System.IO.Compression.FileSystem +$a = [IO.Compression.ZipFile]::OpenRead("out\sp\Touryo.Infrastructure.Public.3.0.0.snupkg") +foreach ($e in $a.Entries | Where-Object { $_.Name -like "*.pdb" }) { + $tf = Join-Path $env:TEMP ($e.FullName -replace "/","_") + [IO.Compression.ZipFileExtensions]::ExtractToFile($e, $tf, $true) + $by = [IO.File]::ReadAllBytes($tf) + $txt = [Text.Encoding]::ASCII.GetString($by) + "{0,-46} {1,-9} SourceLink={2}" -f $e.FullName, + $(if ([Text.Encoding]::ASCII.GetString($by[0..3]) -eq "BSJB") { "portable" } else { "Windows" }), + $(if ($txt -match "raw\.githubusercontent") { "あり" } else { "なし" }) +} +$a.Dispose() +``` + +### 確認 4 : `<repository>` にコミットが入っていること + +`.nupkg` 内の `.nuspec` に次があること。 + +```xml +<repository type="git" url="https://github.com/OpenTouryoProject/OpenTouryo" commit="<40 桁>" /> +``` + +空なら、git からハッシュを取得できていない。 + +> **Source Link 自体は PDB の情報で動く**ので、ここが空でもデバッグはできる。 +> nuget.org 上で辿りやすくするための情報。 + +**確認 3 で見た PDB のコミットと、一致していること。** 出どころが違う。 + +| | コミットが決まる時点 | +|---|---| +| nuspec の `<repository>` | **`_NuGetPack.bat` の実行時**(`-Properties commit=`) | +| **PDB の Source Link** | **`0_Release4Nuget.bat` の実行時**(SourceLink がコンパイル時に git を読む) | + +**詰め直すだけでは PDB のコミットは変わらない。** +ビルド後にコミットしてから詰めると、nuspec だけが新しくなって食い違う。 +**(2)から通しでやり直すこと。** + +### 確認 5 : そのコミットが GitHub 上にあること + +**Source Link はコミットを SHA で指すため、未プッシュのまま公開すると 404 になる。** +公開後には直せない(7 節)。 + +確認 3 で得た URL を実際に叩く。 + +```powershell +$c = "<確認 3 で得た 40 桁>" +$f = "root/programs/CS/Frameworks/Infrastructure/Public/Util/ArrayOperator.cs" +(Invoke-WebRequest "https://raw.githubusercontent.com/OpenTouryoProject/OpenTouryo/$c/$f" -Method Head).StatusCode +``` + +`200` であること。 + +**あわせて、ワーキング ツリーが綺麗であること**(`git status`)。 +未コミットの変更があると、PDB のチェックサムと GitHub 上のソースが食い違い、 +Visual Studio がソースを開かない。 + +> 追跡外のファイルは `EmbedUntrackedSources` により PDB へ埋め込まれるため影響しない。 + +--- + +## 3. 利用側(Visual Studio)の設定 + +**パッケージ側が正しくても、利用側の設定が要る。** + +| 場所 | 設定 | +|---|---| +| 「ツール」→「オプション」→「デバッグ」→「全般」 | **「マイ コードのみを有効にする」のチェックを外す** | +| 同上 | **「Source Link サポートを有効にする」にチェックを入れる** | +| 「ツール」→「オプション」→「デバッグ」→「シンボル」 | **「NuGet.org シンボル サーバー」にチェックを入れる** | + +これで、F11 でステップインすると該当コミットのソースが取得される。 + +--- + +## 4. テスト手順 + +- 本番手順のうち、(テストを意味する)**`T_` プレフィックス**のあるファイルを使用する +- 対象は、`Touryo.Infrastructure.Public`(`OpenTouryo.Public`)のみ +- **`Erutcurtsarfni.Oyruot.Public`** と言う偽名を使用したα版として登録 +- これを使用して、シンボル サーバー、ソース サーバーが機能するかどうかを確認する + +> シンボル サーバー、ソース サーバーが機能する手順を確立したら移行テストは不要。 + +**ローカル フィードでは代替できない。** +Source Link は確認できるが、**`.snupkg` は nuget.org が展開する**ため、 +シンボル サーバーの確認にはならない。 + +### 手順 + +#### (1)ビルドを行う + +``` +root\programs\CS\0_Release4Nuget.bat +``` + +**本番手順と同じものを使う。** ここを省いてはならない。 + +`1_BuildAll.ps1` や Visual Studio で建てた直後の `Build_*` は +**`DebugType=full`(Windows PDB)**になっており、そのまま詰めると +確認 2 で失格になる。**成果物は共通の `Build_*` に出るため、後から上書きされる。** + +#### (2)パッケージングを行う + +**版を引数で渡す。** + +``` +root\programs\CS\NuGet\_T_NuGetPack.bat 3.3.0-alpha1 +``` + +本番用(`Symbol_*.nuspec`)は `Directory.Build.props` の +`OpenTouryoVersion` を使うが、**テスト用は本番の版とは無関係に付ける**ため、 +`T_Symbol_Public.nuspec` の `<version>` は `$version$` のままにして +バッチの引数から渡している。 + +**公開済みより大きい版でなければ nuget.org は受け付けない。** +公開済みの一覧は次で分かる。 + +```powershell +(Invoke-RestMethod "https://api.nuget.org/v3-flatcontainer/erutcurtsarfni.oyruot.public/index.json").versions +``` + +#### (3)公開前の確認を行う + +**2 節の確認 5 点を、本番と同じように行う。** + +`T_` 系は本番用と**別のファイル**であり、**ずれやすい。** +現在は揃っているが、本番側に手を入れたら `T_` 側も見ること。 + +| 本番 | テスト | 意図的な差 | +|---|---|---| +| `Symbol_Public.nuspec` | `T_Symbol_Public.nuspec` | `<id>` / `<title>` が偽名 | +| `_NuGetPack.bat` | `_T_NuGetPack.bat` | 版の出どころ(`Directory.Build.props` / **引数**) | +| `out\sp\_NuGetPush.bat` | `out\sp\_T_NuGetPush.bat` | push 対象のワイルドカード | + +**これ以外は同じであるべき。** +`<repository>` の有無、`-Properties` で渡す `version` / `commit`、 +API キーの渡し方(8 節)は、本番・テストで揃っている。 + +> #531 では、本番側にだけ `<repository>` と `-Properties` を入れて +> `T_` 系を取りこぼした。`Symbol_*.nuspec` という**ワイルドカードで一括置換したため、 +> `T_` で始まるファイルが対象から漏れた**。 +> テスト用パッケージを詰めて初めて分かる類の漏れなので、確認 5 点は省かない。 + +#### (4)プッシュする + +本番と同じく、**環境変数で渡す**。 + +``` +set NUGET_API_KEY=<nuget.org で発行したキー> +root\programs\CS\NuGet\out\sp\_T_NuGetPush.bat +``` + +テスト用のキーは **`Erutcurtsarfni.Oyruot.*` にスコープを絞る**とよい。 + +**プッシュ対象はワイルドカード(`Erutcurtsarfni.Oyruot.Public.*.nupkg`)である。** +`out\sp` に古い版が残っていると**それも公開される**ので、 +実行前にフォルダの中身を見ること。 + +#### (5)後始末 + +**revert するものは無い**(本番手順の(5)と同じ)。 + +#### (6)確認する + +3 節の設定を行った上で、テスト プロジェクトから +`Erutcurtsarfni.Oyruot.Public` を参照し、**F11 でステップイン**できることを見る。 + +### 作業ブランチ上で行ってよい + +テストは作業ブランチ上で、プレリリース版(`3.3.0-alpha1` など)として行ってよい。 +**master へのマージやタグは要らない**(本番手順の(0)とは異なる)。 + +ただし **7 節に従い、詰めた時のコミットを消さないこと。** +消すと、公開済みのテスト用パッケージの Source Link が壊れる。 + +> 壊してしまった場合は、生き残ったコミットから `3.3.0-alpha2` を詰め直せば復旧できる。 +> **プレリリースなので番号を消費してよい。** + +--- + +## 5. 仕組みの要点(#531) + +### シンボル サーバー(`.snupkg`) + +PDB を別パッケージにして公開する。利用者は明示的に取得しなくてよい。 +**portable PDB でなければ受け付けられない。** + +### ソース サーバー(Source Link) + +PDB の中に「このソースはどの URL から取れるか」を書いておく仕組み。 +ビルド時に git のリモート URL とコミットから生成される。 + +| | Source Link | +|---|---| +| **net10.0** | .NET 8 以降の SDK が**自動で組み込む** | +| **net48** | 旧形式 csproj は自動にならないため、**`Microsoft.SourceLink.GitHub` を `PackageReference` で入れている**(`PrivateAssets=all` なので、利用者の依存関係には現れない) | + +### 押さえるべき設定 + +| ファイル | 設定 | +|---|---| +| `*_net48.csproj`(6 本) | `PublishRepositoryUrl` / `EmbedUntrackedSources` + `Microsoft.SourceLink.GitHub` | +| `0_Release4Nuget.bat` | `DEBUG_TYPE=portable` + `CI_BUILD=true` | +| `z_Common.bat` | `CI_BUILD` を `ContinuousIntegrationBuild` と **`DeterministicSourcePaths` の両方**へ渡す | +| `_NuGetPack.bat` | `version` と `commit` を nuspec へ渡す | +| `Symbol_*.nuspec` | `<repository ... commit="$commit$" />` | + +net48 で Source Link を入れているのは次の 6 本 +(`DamPstGrS` は net48 が無いため対象外)。 + +``` +Public / Public.Security / Framework / Framework.RichClient +DamManagedOdp / DamMySQL +``` + +--- + +## 6. 生成物は追跡しない + +`in\` と `out\` の中身は `_NuGetPack.bat` が毎回作り直すため、`.gitignore` で除外している。 + +**フォルダごとではなく、生成物の種類で除外している。** +各フォルダの説明用 `.txt` と `_NuGetPush.bat` は**追跡し続ける必要がある**ため。 + +### 詰める前に消す — `_Cleanup.bat` + +**`_NuGetPack.bat` / `_T_NuGetPack.bat` は、`xcopy` の前に `_Cleanup.bat` を呼ぶ**(#531)。 +後始末ではなく前始末である。残っていて困るのは「次に詰めるとき」だからである。 + +``` +_Cleanup.bat in\ と out\ の全パッケージ +_Cleanup.bat <パッケージ ID の接頭辞> in\ と、その接頭辞のパッケージだけ +``` + +`/NOPAUSE` を付けると最後の `pause` を省く(**どちらの位置でもよい**)。 +単独で実行すれば、手作業での全消去にも使える。 + +| 対象 | 消す理由 | +|---|---| +| `in\<tfm>\` の `*.dll` `*.pdb` `*.xml` `*.config` `*.json` とサブフォルダ | **`xcopy /E /Y` は上書きするだけで、削除しない。** ビルドが出さなくなったファイルが残り続け、nuspec が拾い得る。実際 `in\net48` には、過去の依存が持ち込んだサテライト アセンブリが 14 言語分溜まっていた | +| `out\{sp,pp}\` の `.nupkg` / `.snupkg` | **`_NuGetPush.bat` はワイルドカードで push する。** 古い版が残っていると一緒に公開され、**未公開のプレリリース版が意図せず出る** | + +**パック バッチは、自分の成果物だけを消す。** + +``` +_NuGetPack.bat → _Cleanup.bat Touryo.Infrastructure /NOPAUSE +_T_NuGetPack.bat → _Cleanup.bat Erutcurtsarfni.Oyruot.Public /NOPAUSE +``` + +**push のワイルドカードと範囲を一致させてある**ので、互いの成果物を巻き込まない。 +引数なしで単独実行したときだけ、両方が消える。 + +**説明用の `.txt` と `_NuGetPush.bat` は消さない。** フォルダごと消すのではなく、 +`.gitignore` と同じ範囲(生成物の種類とサブフォルダ)だけを消している。 + +--- + +## 7. 詰めたコミットを消してはならない + +**公開したパッケージは、詰めた時のコミットに永久に固定される。** + +`_NuGetPack.bat` / `_T_NuGetPack.bat` は `git rev-parse HEAD` の値を、 +nuspec の `<repository commit>` と PDB の Source Link に埋め込む。 +Source Link はソースを次の URL から取得する。 + +``` +https://raw.githubusercontent.com/OpenTouryoProject/OpenTouryo/<SHA>/<パス> +``` + +### ブランチ名もタグも関係ない + +**SHA 指定なので、どのブランチで詰めたかは問われない。** +そのコミットが**リモートの何らかの ref から到達可能でありさえすれば**引ける。 +`develop` に入っていなくても、作業ブランチに残っていれば機能する。 + +**守るべきなのはブランチ名ではなく、コミットが GitHub 上に残り続けることである。** + +### 消えるケース + +| 操作 | 詰めたコミットは残るか | +|---|---| +| `--no-ff` マージ/通常のマージ/fast-forward | **残る** | +| **squash merge** | **消える**(新しい 1 コミットに潰れ、元は到達不能になる) | +| **rebase して push** | **消える**(SHA が変わる) | +| force-push でその履歴を巻き戻す | **消える** | +| そのコミットを含む唯一のブランチを削除 | **消える** | + +> 到達不能になったコミットも GitHub 上でしばらく引ける場合があるが、 +> **保証されないので当てにしない。** + +**したがって、詰めたコミットは `--no-ff` で develop → master へ流して残す。** +master は履歴を書き換えないため、これが最も確実である。 + +### 「先頭コミット」ではない + +守るべきは**詰めた時点の HEAD** であり、そのブランチの先端であり続ける必要はない。 +後からコミットが載れば先端ではなくなるが、**祖先であれば到達可能なので問題ない。** + +### 壊れた場合 + +**公開後には直せない。** 同じバージョンの再アップロードはできず、 +取り消しも unlist(一覧から隠す)だけである。**次のバージョンを出すしかない。** + +だからこそ、公開前に確認 5 を行う。 + +--- + +## 8. API キーは環境変数で渡す(#531) + +`_NuGetPush.bat` / `_T_NuGetPush.bat` は `NUGET_API_KEY` から読む。 +未設定なら**エラーで止まる**(キー無しで push を試みない)。 + +``` +set NUGET_API_KEY=<nuget.org で発行したキー> +``` + +### `-ApiKey` と `-SymbolApiKey` の両方を渡す + +**`nuget.exe` はシンボル サーバーには `-SymbolApiKey` を使う。`-ApiKey` は効かない。** + +``` +nuget.exe push xxx.nupkg -ApiKey %KEY% -SymbolApiKey %KEY% -source https://api.nuget.org/v3/index.json +``` + +`-SymbolApiKey` を省くと、**`.nupkg` は通るが `.snupkg` だけが 403 になる。** + +``` +Pushing Erutcurtsarfni.Oyruot.Public.3.3.0-alpha1.snupkg to 'https://www.nuget.org/api/v2/symbolpackage'... + Forbidden https://www.nuget.org/api/v2/symbolpackage/ +403 (The specified API key is invalid, has expired, or does not have permission + to access the specified package.) +``` + +**メッセージはキーが無効であるかのように読めるが、実際には +「シンボル用のキーが渡されていない」**という意味である。 + +> 旧方式(`nuget.exe SetApiKey`)でこれが問題にならなかったのは、 +> キーが `NuGet.Config` に保存され、**シンボル側も同じ保存値を拾っていた**ため。 +> 環境変数方式に変えるなら、**両方のオプションを明示する必要がある。** + +### なぜ `SetApiKey` をやめたか + +以前は bat 内に `nuget.exe SetApiKey [ApiKey]` と書き、 +実行前に実キーへ差し替え、実行後にプレースホルダへ戻す運用だった。 +**戻し忘れが 2 か所で漏洩につながる。** + +| | 問題 | +|---|---| +| **bat ファイル** | **Git で追跡されている。** キーを直書きしたままコミットすると、公開リポジトリに載る | +| **`NuGet.Config`** | `SetApiKey` はキーを `%AppData%\NuGet\NuGet.Config` の `<apikeys>` へ**永続化する**。bat を戻しても消えない | + +環境変数なら**コンソールを閉じれば消える**ため、後始末が要らない。 + +> 過去に `SetApiKey` を実行していた場合、`%AppData%\NuGet\NuGet.Config` に +> キーが残っている。`nuget.exe 6.13` の `setApiKey` に削除オプションは無いので、 +> **`<apikeys>` の該当する `<add>` 行を手で削除する。** + +### キーの発行と、次回への回し方 + +https://www.nuget.org/account/apikeys + +**パッケージ系統ごとに 1 本作り、`Regenerate` と `Revoke` で回す。** + +``` +作成(スコープを設定)→ Regenerate → 公開に使う → Revoke → 次回は Regenerate → ... +``` + +**`Delete` しない限り、スコープの設定は残り続ける。** + +``` +Glob pattern: Touryo.Infrastructure.* ← 本番 +Glob pattern: Erutcurtsarfni.Oyruot.* ← テスト(4 節) +``` + +| 作るとき | | +|---|---| +| **スコープ** | 対象パッケージをグロブで限定する | +| **有効期限** | **最短にする**(数時間で十分) | + +| 使い終わったら | | +|---|---| +| **`Revoke`** | **即座に無効化する。行は `Revoked` として残り、`Regenerate` で再び使える**(実測確認済み)。**これを既定にする** | +| 放置する | 期限が切れれば無害になる。設定も残るので、これでもよい | +| `Delete` | **キーの定義ごと消える。** スコープの設定も失われ、次回は作り直しになる。**その系統をもう使わないときだけ** | + +``` +Touryo.Infrastructure + Revoked Push new packages and package versions, Unlist or relist package versions + Glob pattern: Touryo.Infrastructure.* + Copy Edit Regenerate Delete ← Regenerate が残る +``` + +`Revoke` すると `support@nuget.org` から通知が届く。 + +> **`Delete` を既定にしない。** +> 「使ったら消す」は**有効期限を設定しない運用の話**である。 +> スコープを設定したキーは、**定義を残して値だけ回す**方がよい。 + +> `Regenerate` は**値だけを新しくする**(キーは有効になる)。 +> 使い終わったキーを無効化する目的では使えない。**無効化は `Revoke`。** + +--- + +## 9. よく踏む落とし穴 + +**いずれも「気付かないまま公開してしまう」類。** 詳細は右端の節を読むこと。 + +| 症状 | 原因 | 詳細 | +|---|---|---| +| `.nupkg` は通るが **`.snupkg` だけ 403** | `-ApiKey` はシンボル サーバーに使われない。**`-SymbolApiKey` も渡す** | 8 節 | +| **F11 でローカルのソースが開く** | PDB に絶対パスが残っている。**Source Link を通っていない** | 1 節(2) | +| nuspec と PDB のコミットが食い違う | PDB は**ビルド時**、nuspec は**パック時**に決まる。間でコミットしない | 2 節 確認 4 | +| 中身が古いのに新しい版で出る | リビルドを飛ばした。`_NuGetPack.bat` が DLL を検査して止める | 1 節(3) | +| net48 側だけ Source Link / パス正規化が効かない | 旧形式 csproj は SDK の自動処理が効かない。明示指定が要る | 5 節 | +| 公開したコミットが消えた | rebase / squash / ブランチ削除。**公開後は直せない** | 7 節 | + +**上 5 つは公開前に机上で分かる。** 2 節の確認 5 点を省かないこと。 +最後の 1 つだけは、公開後に他人の操作で起こり得る。 + +> **`MSB4226`(`Microsoft.WebApplication.targets` が見つからない)** は +> パッケージ作成ではなくビルドの問題。 +> nuget が別製品(SQL Server Management Studio 等)同梱の MSBuild を拾っている。 +> `nuget.exe restore ... %NUGET_MSBUILD%` を渡す +> ([`Frameworks/ANALYSIS.md`](../Frameworks/ANALYSIS.md) 7 章)。 \ No newline at end of file diff --git a/root/programs/CS/NuGet/Symbol_DamManagedOdp.nuspec b/root/programs/CS/NuGet/Symbol_DamManagedOdp.nuspec index 694e72056..f70384695 100644 --- a/root/programs/CS/NuGet/Symbol_DamManagedOdp.nuspec +++ b/root/programs/CS/NuGet/Symbol_DamManagedOdp.nuspec @@ -1,9 +1,9 @@ -<?xml version="1.0"?> +<?xml version="1.0"?> <package > <metadata> <id>Touryo.Infrastructure.Public.Db.DamManagedOdp</id> <title>OpenTouryo.DamManagedOdp - 3.0.0 + $version$ OSS Consortium .net subcommittee daisukenishino77 Apache-2.0 @@ -15,13 +15,17 @@ https://github.com/OpenTouryoProject/OpenTouryo/releases OpenTouryo Open棟梁 + + - + - - + + @@ -33,9 +37,9 @@ - - - + + + diff --git a/root/programs/CS/NuGet/Symbol_DamMySQL.nuspec b/root/programs/CS/NuGet/Symbol_DamMySQL.nuspec index 11fd720f3..dc01f029a 100644 --- a/root/programs/CS/NuGet/Symbol_DamMySQL.nuspec +++ b/root/programs/CS/NuGet/Symbol_DamMySQL.nuspec @@ -1,9 +1,9 @@ - + Touryo.Infrastructure.Public.Db.DamMySQL OpenTouryo.DamMySQL - 3.0.0 + $version$ OSS Consortium .net subcommittee daisukenishino77 Apache-2.0 @@ -15,14 +15,18 @@ https://github.com/OpenTouryoProject/OpenTouryo/releases OpenTouryo Open棟梁 + + - + - - + + @@ -34,9 +38,9 @@ - - - + + + diff --git a/root/programs/CS/NuGet/Symbol_DamPstGrS.nuspec b/root/programs/CS/NuGet/Symbol_DamPstGrS.nuspec index b9230f3ec..a1bdc6bfd 100644 --- a/root/programs/CS/NuGet/Symbol_DamPstGrS.nuspec +++ b/root/programs/CS/NuGet/Symbol_DamPstGrS.nuspec @@ -1,9 +1,9 @@ - + Touryo.Infrastructure.Public.Db.DamPstGrS OpenTouryo.DamPstGrS - 3.0.0 + $version$ OSS Consortium .net subcommittee daisukenishino77 Apache-2.0 @@ -15,9 +15,13 @@ https://github.com/OpenTouryoProject/OpenTouryo/releases OpenTouryo Open棟梁 + + - - + + @@ -25,9 +29,9 @@ - - - + + + diff --git a/root/programs/CS/NuGet/Symbol_Framework.RichClient.nuspec b/root/programs/CS/NuGet/Symbol_Framework.RichClient.nuspec index f96f7edfa..c5f6df6ee 100644 --- a/root/programs/CS/NuGet/Symbol_Framework.RichClient.nuspec +++ b/root/programs/CS/NuGet/Symbol_Framework.RichClient.nuspec @@ -1,9 +1,9 @@ - + Touryo.Infrastructure.Framework.RichClient OpenTouryo.Framework.RichClient - 3.0.0 + $version$ OSS Consortium .net subcommittee daisukenishino77 Apache-2.0 @@ -15,14 +15,18 @@ https://github.com/OpenTouryoProject/OpenTouryo/releases OpenTouryo Open棟梁 + + - - + + - - - + + + @@ -33,9 +37,9 @@ - - - + + + diff --git a/root/programs/CS/NuGet/Symbol_Framework.nuspec b/root/programs/CS/NuGet/Symbol_Framework.nuspec index 051a0c220..d94267524 100644 --- a/root/programs/CS/NuGet/Symbol_Framework.nuspec +++ b/root/programs/CS/NuGet/Symbol_Framework.nuspec @@ -1,9 +1,9 @@ - + Touryo.Infrastructure.Framework OpenTouryo.Framework - 3.0.0 + $version$ OSS Consortium .net subcommittee daisukenishino77 Apache-2.0 @@ -15,24 +15,26 @@ https://github.com/OpenTouryoProject/OpenTouryo/releases OpenTouryo Open棟梁 + + - - + + - - - + + + - - @@ -44,10 +46,10 @@ - - - - + + + + diff --git a/root/programs/CS/NuGet/Symbol_Public.Security.nuspec b/root/programs/CS/NuGet/Symbol_Public.Security.nuspec index b9c62e1e4..1ce8b38d9 100644 --- a/root/programs/CS/NuGet/Symbol_Public.Security.nuspec +++ b/root/programs/CS/NuGet/Symbol_Public.Security.nuspec @@ -1,9 +1,9 @@ - + Touryo.Infrastructure.Public.Security OpenTouryo.Public.Security - 3.0.0 + $version$ OSS Consortium .net subcommittee daisukenishino77 Apache-2.0 @@ -15,21 +15,21 @@ https://github.com/OpenTouryoProject/OpenTouryo/releases OpenTouryo Open棟梁 + + - + - - - + + - - - - + @@ -40,9 +40,9 @@ - - - + + + diff --git a/root/programs/CS/NuGet/Symbol_Public.nuspec b/root/programs/CS/NuGet/Symbol_Public.nuspec index b8d47556f..fbae05745 100644 --- a/root/programs/CS/NuGet/Symbol_Public.nuspec +++ b/root/programs/CS/NuGet/Symbol_Public.nuspec @@ -1,9 +1,9 @@ - + Touryo.Infrastructure.Public OpenTouryo.Public - 3.0.0 + $version$ OSS Consortium .net subcommittee daisukenishino77 Apache-2.0 @@ -15,17 +15,20 @@ https://github.com/OpenTouryoProject/OpenTouryo/releases OpenTouryo Open棟梁 + + - - + + - - - + + @@ -33,9 +36,8 @@ + - - @@ -48,10 +50,10 @@ - - - - + + + + diff --git a/root/programs/CS/NuGet/T_NuGetPack.bat b/root/programs/CS/NuGet/T_NuGetPack.bat deleted file mode 100644 index 28bc3fe9e..000000000 --- a/root/programs/CS/NuGet/T_NuGetPack.bat +++ /dev/null @@ -1,9 +0,0 @@ -setlocal -@echo off - -xcopy /E /Y "..\Frameworks\Infrastructure\Build_net48" "in\net48" -xcopy /E /Y "..\Frameworks\Infrastructure\Build_netcore80\net8.0" "in\net8.0" -xcopy /E /Y "..\Frameworks\Infrastructure\Build_netcore80\net8.0-windows" "in\net8.0-windows" - -"..\..\nuget.exe" pack T_Symbol_Public.nuspec -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg -pause diff --git a/root/programs/CS/NuGet/T_Symbol_Public.nuspec b/root/programs/CS/NuGet/T_Symbol_Public.nuspec index d607d70ea..82efd29ca 100644 --- a/root/programs/CS/NuGet/T_Symbol_Public.nuspec +++ b/root/programs/CS/NuGet/T_Symbol_Public.nuspec @@ -1,9 +1,9 @@ - + Erutcurtsarfni.Oyruot.Public NepoOyruot.Public - 3.1.0-alpha2 + $version$ OSS Consortium .net subcommittee daisukenishino77 Apache-2.0 @@ -15,17 +15,18 @@ https://github.com/OpenTouryoProject/OpenTouryo/releases + + - - + - - - + + @@ -34,8 +35,6 @@ - - @@ -48,10 +47,10 @@ - - - - + + + + diff --git a/root/programs/CS/NuGet/_Cleanup.bat b/root/programs/CS/NuGet/_Cleanup.bat new file mode 100644 index 000000000..8ad070ef7 --- /dev/null +++ b/root/programs/CS/NuGet/_Cleanup.bat @@ -0,0 +1,74 @@ +setlocal +@echo off + +@rem -------------------------------------------------- +@rem Clear the NuGet working folders (#531). +@rem +@rem _Cleanup.bat in\ and ALL packages in out\ +@rem _Cleanup.bat in\ and only that prefix +@rem +@rem /NOPAUSE skips the pause at the end, and may be given in either +@rem position (with or without a prefix). +@rem +@rem _NuGetPack.bat and _T_NuGetPack.bat call this before their xcopy, each +@rem passing its own prefix. Run it by hand for a full reset. +@rem +@rem Why this is done BEFORE packing rather than after: +@rem +@rem in\ xcopy /E /Y only overwrites. It never deletes, so a file the +@rem build no longer produces stays behind and can still be picked +@rem up by a nuspec. in\net48 had accumulated satellite assemblies +@rem from past dependencies in 14 languages. +@rem +@rem out\ _NuGetPush.bat pushes by wildcard. An older version left behind +@rem would be published together with the new one, and an +@rem unpublished prerelease would go out unintentionally. +@rem +@rem The .txt files that explain each folder, and the _NuGetPush.bat files, +@rem are tracked by Git. The folders are therefore kept: only the generated +@rem file types and the subdirectories are removed, matching .gitignore. +@rem +@rem NOTE: keep this file pure ASCII (#532). +@rem -------------------------------------------------- +set OT_PREFIX=%~1 +set OT_NOPAUSE= + +@rem /NOPAUSE may be the first argument, with no prefix given. +if /i "%OT_PREFIX%"=="/NOPAUSE" ( + set OT_PREFIX= + set OT_NOPAUSE=1 +) + +if /i "%~2"=="/NOPAUSE" set OT_NOPAUSE=1 + +echo -------------------------------------------------- + +if defined OT_PREFIX ( + echo Clearing in\ and out\ packages named %OT_PREFIX%* . +) else ( + echo Clearing in\ and ALL packages in out\ . +) + +echo -------------------------------------------------- + +@rem -------------------------------------------------- +@rem in\ : the generated file types and the subdirectories. +@rem -------------------------------------------------- +for %%d in (net48 net10.0 net10.0-windows) do if exist "%~dp0in\%%d" ( + del /q "%~dp0in\%%d\*.dll" "%~dp0in\%%d\*.pdb" "%~dp0in\%%d\*.xml" "%~dp0in\%%d\*.config" "%~dp0in\%%d\*.json" >nul 2>&1 + for /d %%s in ("%~dp0in\%%d\*") do rd /s /q "%%s" +) + +@rem -------------------------------------------------- +@rem out\ : the packages. sp is the one in use; pp is kept for the case +@rem where symbols are not registered. +@rem -------------------------------------------------- +for %%o in (sp pp) do if exist "%~dp0out\%%o" ( + del /q "%~dp0out\%%o\%OT_PREFIX%*.nupkg" "%~dp0out\%%o\%OT_PREFIX%*.snupkg" >nul 2>&1 +) + +echo Done. + +if defined OT_NOPAUSE goto :eof + +pause \ No newline at end of file diff --git a/root/programs/CS/NuGet/_NuGetPack.bat b/root/programs/CS/NuGet/_NuGetPack.bat index 2090f13bb..fa70fdabe 100644 --- a/root/programs/CS/NuGet/_NuGetPack.bat +++ b/root/programs/CS/NuGet/_NuGetPack.bat @@ -1,16 +1,158 @@ -setlocal +setlocal @echo off -xcopy /E /Y "..\Frameworks\Infrastructure\Build_net48" "in\net48" -xcopy /E /Y "..\Frameworks\Infrastructure\Build_netcore80\net8.0" "in\net8.0" -xcopy /E /Y "..\Frameworks\Infrastructure\Build_netcore80\net8.0-windows" "in\net8.0-windows" +@rem -------------------------------------------------- +@rem Read the version number from Directory.Build.props. +@rem The nuspec files keep the $version$ token, so the version is +@rem defined in exactly one place. +@rem +@rem NOTE: keep this file pure ASCII (#532). +@rem -------------------------------------------------- +set OT_INFRA=..\Frameworks\Infrastructure +set OT_PROPS=%OT_INFRA%\Directory.Build.props +set OT_VERSION= -"..\..\nuget.exe" pack Symbol_Public.nuspec -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg -"..\..\nuget.exe" pack Symbol_Public.Security.nuspec -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg -"..\..\nuget.exe" pack Symbol_Framework.nuspec -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg -"..\..\nuget.exe" pack Symbol_Framework.RichClient.nuspec -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg -"..\..\nuget.exe" pack Symbol_DamManagedOdp.nuspec -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg -"..\..\nuget.exe" pack Symbol_DamPstGrS.nuspec -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg -"..\..\nuget.exe" pack Symbol_DamMySQL.nuspec -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg +for /f "usebackq delims=" %%v in ( + `powershell -NoProfile -ExecutionPolicy Bypass -Command "([xml](Get-Content '%OT_PROPS%' -Raw)).Project.PropertyGroup.OpenTouryoVersion"` +) do set OT_VERSION=%%v +if not defined OT_VERSION ( + echo [ERROR] Failed to read OpenTouryoVersion from %OT_PROPS%. + pause + exit /b 1 +) + +@rem -------------------------------------------------- +@rem Verify that the net48 assemblies carry the same version (#531). +@rem +@rem Directory.Build.props is imported through Microsoft.Common.props, so it +@rem only reaches the SDK-style projects (*_netcore100.csproj). The old-style +@rem projects (*_net48.csproj) do not import it and keep their version in +@rem Properties\AssemblyInfo.cs instead. +@rem +@rem Raising OpenTouryoVersion without updating those files ships a package +@rem whose net48 and net10.0 assemblies carry DIFFERENT versions, and that +@rem cannot be corrected once published. Stop here instead. +@rem +@rem The 6 projects checked are the ones that go into the NuGet packages. +@rem DamPstGrS has no net48. Business is deliberately on a separate version +@rem line (1.0.0.0) and is not packaged, so neither is checked. +@rem +@rem AssemblyVersion has four components (3.0.0.0) and OpenTouryoVersion has +@rem three (3.0.0), so only the first three are compared. +@rem +@rem OpenTouryoVersion may carry a prerelease suffix (3.3.0-alpha1). The +@rem suffix never reaches the assemblies: the SDK assigns VersionPrefix to +@rem AssemblyVersion / FileVersion and the whole string to +@rem InformationalVersion. It is therefore stripped before comparing. +@rem +@rem _T_NuGetPack.bat does NOT need this check. The test package takes its +@rem version from the command line and never reads OpenTouryoVersion, so the +@rem version only names the package and is not written into any assembly. +@rem There is nothing for the assemblies to disagree with. +@rem -------------------------------------------------- +for /f "delims=- tokens=1" %%x in ("%OT_VERSION%") do set OT_VERPREFIX=%%x + +echo -------------------------------------------------- +echo Checking the net48 AssemblyVersion against %OT_VERPREFIX%. +echo -------------------------------------------------- + +powershell -NoProfile -ExecutionPolicy Bypass -Command "$v='%OT_VERPREFIX%'; $ok=$true; foreach($p in 'Public','Public\Security','Framework','Framework\RichClient','Public\Db\DamManagedOdp','Public\Db\DamMySQL'){ $f=Join-Path '%OT_INFRA%' ($p+'\Properties\AssemblyInfo.cs'); if(-not (Test-Path $f)){ Write-Host (' NG '+$p+' : AssemblyInfo.cs not found'); $ok=$false; continue }; $m=Select-String -Path $f -Pattern 'AssemblyVersion\(.([0-9]+\.[0-9]+\.[0-9]+)' | Select-Object -First 1; if(-not $m){ Write-Host (' NG '+$p+' : AssemblyVersion not found'); $ok=$false; continue }; $a=$m.Matches[0].Groups[1].Value; if($a -eq $v){ Write-Host (' OK '+$p+' : '+$a) } else { Write-Host (' NG '+$p+' : '+$a+' expected '+$v); $ok=$false } }; if(-not $ok){ exit 1 }" + +if errorlevel 1 goto VersionMismatch + +@rem -------------------------------------------------- +@rem Read the commit hash (#531). +@rem It is passed to in the nuspec so that +@rem nuget.org shows which commit the package was built from. +@rem +@rem Source Link itself works from the information inside the PDB, so +@rem source debugging still works when this is empty. It only helps +@rem people navigate back to the source. +@rem -------------------------------------------------- +set OT_COMMIT= + +for /f "usebackq delims=" %%c in (`git rev-parse HEAD 2^>nul`) do set OT_COMMIT=%%c + +if not defined OT_COMMIT ( + echo [WARN] Could not read the commit hash from git. Continuing with an empty value. + set OT_COMMIT= +) + +echo -------------------------------------------------- +echo OpenTouryoVersion = %OT_VERSION% +echo commit = %OT_COMMIT% +echo -------------------------------------------------- + +@rem -------------------------------------------------- +@rem Clear the working folders before packing (#531). +@rem +@rem Only this batch's own output is removed. The test packages built by +@rem _T_NuGetPack.bat are left alone; their push uses a different wildcard. +@rem The reasons are in _Cleanup.bat, which can also be run on its own. +@rem -------------------------------------------------- +call "%~dp0_Cleanup.bat" Touryo.Infrastructure /NOPAUSE + +xcopy /E /Y "%OT_INFRA%\Build_net48" "in\net48" +xcopy /E /Y "%OT_INFRA%\Build_netcore100\net10.0" "in\net10.0" +xcopy /E /Y "%OT_INFRA%\Build_netcore100\net10.0-windows7.0" "in\net10.0-windows" + +@rem -------------------------------------------------- +@rem Verify that the copied assemblies were actually rebuilt (#531). +@rem +@rem The check above compares two SOURCE files with each other +@rem (Directory.Build.props and AssemblyInfo.cs). It cannot notice that +@rem 0_Release4Nuget.bat was skipped: Build_* would still hold the previous +@rem version, _Cleanup.bat would refresh in\ from it, and a package carrying +@rem old assemblies would be published under the new version number. +@rem That cannot be corrected once published. +@rem +@rem The list of assemblies is taken from the nuspec files themselves, so a +@rem new package is covered without editing this batch. Satellite +@rem assemblies are skipped; they carry the same version anyway. +@rem OpenTouryo.Business.dll is not listed in any nuspec and is therefore +@rem not checked - it is deliberately on a separate version line (1.0.0.0). +@rem +@rem symbol_template.nuspec is excluded. Windows globbing is case +@rem insensitive, so Symbol_*.nuspec would otherwise match the template and +@rem report its placeholder (OpenTouryo.xxxx.dll) as missing. +@rem -------------------------------------------------- +echo -------------------------------------------------- +echo Checking the packaged assemblies against %OT_VERPREFIX%. +echo -------------------------------------------------- + +powershell -NoProfile -ExecutionPolicy Bypass -Command "$v='%OT_VERPREFIX%'; $ok=$true; $n=0; foreach($f in Get-ChildItem -Path 'Symbol_*.nuspec' -Exclude 'symbol_template.nuspec'){ $x=[xml](Get-Content $f.FullName -Raw); foreach($e in $x.package.files.file){ $s=$e.src; if($s -notlike '*.dll'){continue}; if($s -like '*ja-JP*'){continue}; if(-not (Test-Path $s)){ Write-Host (' NG '+$s+' : not found'); $ok=$false; continue }; $a=[Reflection.AssemblyName]::GetAssemblyName((Resolve-Path $s)).Version; $a3=''+$a.Major+'.'+$a.Minor+'.'+$a.Build; $n++; if($a3 -eq $v){ Write-Host (' OK '+$s+' : '+$a) } else { Write-Host (' NG '+$s+' : '+$a+' expected '+$v+'.x'); $ok=$false } } }; if($n -eq 0){ Write-Host ' NG no assemblies were checked'; $ok=$false }; if(-not $ok){ exit 1 }" + +if errorlevel 1 goto AssemblyMismatch + +"..\..\nuget.exe" pack Symbol_Public.nuspec -Properties version=%OT_VERSION%;commit=%OT_COMMIT% -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg +"..\..\nuget.exe" pack Symbol_Public.Security.nuspec -Properties version=%OT_VERSION%;commit=%OT_COMMIT% -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg +"..\..\nuget.exe" pack Symbol_Framework.nuspec -Properties version=%OT_VERSION%;commit=%OT_COMMIT% -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg +"..\..\nuget.exe" pack Symbol_Framework.RichClient.nuspec -Properties version=%OT_VERSION%;commit=%OT_COMMIT% -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg +"..\..\nuget.exe" pack Symbol_DamManagedOdp.nuspec -Properties version=%OT_VERSION%;commit=%OT_COMMIT% -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg +"..\..\nuget.exe" pack Symbol_DamPstGrS.nuspec -Properties version=%OT_VERSION%;commit=%OT_COMMIT% -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg +"..\..\nuget.exe" pack Symbol_DamMySQL.nuspec -Properties version=%OT_VERSION%;commit=%OT_COMMIT% -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg + +pause +exit /b 0 + +:VersionMismatch +echo. +echo [ERROR] The net48 AssemblyVersion does not match %OT_VERPREFIX% +echo ^(OpenTouryoVersion = %OT_VERSION%^) +echo Update Properties\AssemblyInfo.cs in the projects marked NG above, +echo rebuild with 0_Release4Nuget.bat, then run this again. +echo See RELEASE.md phase 0. +pause +exit /b 1 + +:AssemblyMismatch +echo. +echo [ERROR] The packaged assemblies do not carry %OT_VERPREFIX% +echo ^(OpenTouryoVersion = %OT_VERSION%^) +echo The sources say the right version but the binaries do not, +echo so the rebuild was skipped. Run CS\0_Release4Nuget.bat, +echo then run this again. +echo See RELEASE.md phase 0 and phase 3. pause +exit /b 1 \ No newline at end of file diff --git a/root/programs/CS/NuGet/_T_NuGetPack.bat b/root/programs/CS/NuGet/_T_NuGetPack.bat new file mode 100644 index 000000000..48011b1ee --- /dev/null +++ b/root/programs/CS/NuGet/_T_NuGetPack.bat @@ -0,0 +1,59 @@ +setlocal +@echo off + +@rem -------------------------------------------------- +@rem Build the test package (Erutcurtsarfni.Oyruot.Public). +@rem It is used to verify the symbol server and Source Link (#531). +@rem +@rem The version is passed as an argument. It is INDEPENDENT of the +@rem production version in Directory.Build.props. +@rem e.g. _T_NuGetPack.bat 3.3.0-alpha1 +@rem +@rem nuget.org only accepts a version higher than the published ones. +@rem https://www.nuget.org/packages/Erutcurtsarfni.Oyruot.Public/ +@rem +@rem NOTE: keep this file pure ASCII (#532). +@rem -------------------------------------------------- +set OT_VERSION=%~1 + +if not defined OT_VERSION ( + echo [ERROR] Specify the package version. + echo e.g. _T_NuGetPack.bat 3.3.0-alpha1 + pause + exit /b 1 +) + +@rem -------------------------------------------------- +@rem Read the commit hash (#531). +@rem It is passed to in the nuspec. +@rem -------------------------------------------------- +set OT_COMMIT= + +for /f "usebackq delims=" %%c in (`git rev-parse HEAD 2^>nul`) do set OT_COMMIT=%%c + +if not defined OT_COMMIT ( + echo [WARN] Could not read the commit hash from git. Continuing with an empty value. + set OT_COMMIT= +) + +echo -------------------------------------------------- +echo version = %OT_VERSION% +echo commit = %OT_COMMIT% +echo -------------------------------------------------- + +@rem -------------------------------------------------- +@rem Clear the working folders before packing (#531). +@rem +@rem Only the test packages are removed. The production packages built by +@rem _NuGetPack.bat are left alone; their push uses a different wildcard. +@rem The reasons are in _Cleanup.bat, which can also be run on its own. +@rem -------------------------------------------------- +call "%~dp0_Cleanup.bat" Erutcurtsarfni.Oyruot.Public /NOPAUSE + +xcopy /E /Y "..\Frameworks\Infrastructure\Build_net48" "in\net48" +xcopy /E /Y "..\Frameworks\Infrastructure\Build_netcore100\net10.0" "in\net10.0" +xcopy /E /Y "..\Frameworks\Infrastructure\Build_netcore100\net10.0-windows7.0" "in\net10.0-windows" + +"..\..\nuget.exe" pack T_Symbol_Public.nuspec -Properties version=%OT_VERSION%;commit=%OT_COMMIT% -OutputDirectory "out\sp" -Symbols -SymbolPackageFormat snupkg + +pause \ No newline at end of file diff --git "a/root/programs/CS/NuGet/_\346\211\213\351\240\206\343\201\256\350\252\254\346\230\216.txt" "b/root/programs/CS/NuGet/_\346\211\213\351\240\206\343\201\256\350\252\254\346\230\216.txt" deleted file mode 100644 index 63095ac30..000000000 --- "a/root/programs/CS/NuGet/_\346\211\213\351\240\206\343\201\256\350\252\254\346\230\216.txt" +++ /dev/null @@ -1,35 +0,0 @@ -<テスト手順> -・本番手順のうち、T_プレフィックスのあるファイルを使用する。 -・対象は、Touryo.Infrastructure.Public(OpenTouryo.Public)のみ。 -・Erutcurtsarfni.Oyruot.Public... と言う偽名を使用したα版として登録。 -・コレを使用して、NuGet.org のシンボル サーバーが機能するかどうかを確認する。 -・コレには、VSでシンボル・ソースに https://symbols.nuget.org/download/symbols を追加する。 - -<本番手順> -(1)以下の手順を実施する -  リリース・エンジニアリング - Open 棟梁 Wiki -  https://opentouryo.osscons.jp/index.php?%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%83%BB%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0 -  ※ コレは全体像の説明で、先ずは、個々の修正を行う。 -   -(2)次に、bat使用してビルドを行う。 -  ・以下の設定ファイルのDEBUG_TYPE=fullをportableに変更する。 -   ...\OpenTouryo\root\programs\CS\z_Common.bat -  ・以下のビルドbatを実行する。 -   ...\OpenTouryo\root\programs\CS\0_Release4Nuget.bat - -(3)次に、NuGetパッケージにパッケージングを行う。 -  _NuGetPack.bat - -(4)最後にNuGetパッケージをNuGetにプッシュする。 -  APIキーをNuGetサイトから取得して以下のbat内に設定してから実行する。 -  ...\OpenTouryo\root\programs\CS\NuGet\out\sp\_NuGetPush.bat -  ※ 最新では「sp」の方だけで良い。「pp」の方はシンボルを登録しないケースで利用可。 - -(5)後始末としてrevertする。 -  ・z_Common.bat:DEBUG_TYPE -  ・_NuGetPush.bat:ApiKey - -(6)以下の手順を実施する -  リリース・エンジニアリング - Open 棟梁 Wiki -  https://opentouryo.osscons.jp/index.php?%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%83%BB%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%83%AA%E3%83%B3%E3%82%B0 -  ※ NuGet利用リポジトリのNuGet参照の貼り直し。 diff --git a/root/programs/CS/NuGet/bk/DamManagedOdp.nuspec b/root/programs/CS/NuGet/bk/DamManagedOdp.nuspec deleted file mode 100644 index 52f64c4cd..000000000 --- a/root/programs/CS/NuGet/bk/DamManagedOdp.nuspec +++ /dev/null @@ -1,72 +0,0 @@ - - - - Touryo.Infrastructure.Public.Db.DamManagedOdp - OpenTouryo.DamManagedOdp - 2.7.0-preview3 - OSS Consortium .net subcommittee - daisukenishino77 - Apache-2.0 - https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamManagedOdp - _OpenTouryo.png - true - DataAccess library of Oracle.ManagedDataAccess in OpenTouryo. - DataAccess library of Oracle.ManagedDataAccess in OpenTouryo. This package is used from template of OpenTouryo. - https://github.com/OpenTouryoProject/OpenTouryo/releases - - OpenTouryo Open棟梁 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/root/programs/CS/NuGet/bk/DamMySQL.nuspec b/root/programs/CS/NuGet/bk/DamMySQL.nuspec deleted file mode 100644 index fd9314215..000000000 --- a/root/programs/CS/NuGet/bk/DamMySQL.nuspec +++ /dev/null @@ -1,76 +0,0 @@ - - - - Touryo.Infrastructure.Public.Db.DamMySQL - OpenTouryo.DamMySQL - 2.7.0-preview3 - OSS Consortium .net subcommittee - daisukenishino77 - Apache-2.0 - https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamMySQL - _OpenTouryo.png - true - DataAccess library of MySql.Data in OpenTouryo. - DataAccess library of MySql.Data in OpenTouryo. This package is used from template of OpenTouryo. - https://github.com/OpenTouryoProject/OpenTouryo/releases - - OpenTouryo Open棟梁 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/root/programs/CS/NuGet/bk/DamPstGrS.nuspec b/root/programs/CS/NuGet/bk/DamPstGrS.nuspec deleted file mode 100644 index 7a9578671..000000000 --- a/root/programs/CS/NuGet/bk/DamPstGrS.nuspec +++ /dev/null @@ -1,84 +0,0 @@ - - - - Touryo.Infrastructure.Public.Db.DamPstGrS - OpenTouryo.DamPstGrS - 2.7.0-preview3 - OSS Consortium .net subcommittee - daisukenishino77 - Apache-2.0 - https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root/programs/CS/Frameworks/Infrastructure/Public/Db/DamPstGrS - _OpenTouryo.png - true - DataAccess library of Npgsql in OpenTouryo. - DataAccess library of Npgsql in OpenTouryo. This package is used from template of OpenTouryo. - https://github.com/OpenTouryoProject/OpenTouryo/releases - - OpenTouryo Open棟梁 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/root/programs/CS/NuGet/bk/Framework.RichClient.nuspec b/root/programs/CS/NuGet/bk/Framework.RichClient.nuspec deleted file mode 100644 index 3a9ce421c..000000000 --- a/root/programs/CS/NuGet/bk/Framework.RichClient.nuspec +++ /dev/null @@ -1,62 +0,0 @@ - - - - Touryo.Infrastructure.Framework.RichClient - OpenTouryo.Framework.RichClient - 2.7.0-preview3 - OSS Consortium .net subcommittee - daisukenishino77 - Apache-2.0 - https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root/programs/CS/Frameworks/Infrastructure/Framework/RichClient - _OpenTouryo.png - true - RichClient Framework of OpenTouryo. - RichClient Framework of OpenTouryo. This package is used from template of OpenTouryo. - https://github.com/OpenTouryoProject/OpenTouryo/releases - - OpenTouryo Open棟梁 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/root/programs/CS/NuGet/bk/Framework.nuspec b/root/programs/CS/NuGet/bk/Framework.nuspec deleted file mode 100644 index c480d8d20..000000000 --- a/root/programs/CS/NuGet/bk/Framework.nuspec +++ /dev/null @@ -1,110 +0,0 @@ - - - - Touryo.Infrastructure.Framework - OpenTouryo.Framework - 2.7.0-preview3 - OSS Consortium .net subcommittee - daisukenishino77 - Apache-2.0 - https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root/programs/CS/Frameworks/Infrastructure/Framework - _OpenTouryo.png - true - Framework of OpenTouryo. - Framework of OpenTouryo. This package is used from template of OpenTouryo. - https://github.com/OpenTouryoProject/OpenTouryo/releases - - OpenTouryo Open棟梁 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/root/programs/CS/NuGet/bk/Public.Security.nuspec b/root/programs/CS/NuGet/bk/Public.Security.nuspec deleted file mode 100644 index 0f15645ea..000000000 --- a/root/programs/CS/NuGet/bk/Public.Security.nuspec +++ /dev/null @@ -1,88 +0,0 @@ - - - - Touryo.Infrastructure.Public.Security - OpenTouryo.Public.Security - 2.7.0-preview3 - OSS Consortium .net subcommittee - daisukenishino77 - Apache-2.0 - https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root/programs/CS/Frameworks/Infrastructure/Public - _OpenTouryo.png - true - Common library of OpenTouryo. - Common library of OpenTouryo. This package is used from template of OpenTouryo. - https://github.com/OpenTouryoProject/OpenTouryo/releases - - OpenTouryo Open棟梁 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/root/programs/CS/NuGet/bk/Public.nuspec b/root/programs/CS/NuGet/bk/Public.nuspec deleted file mode 100644 index a2fa2a891..000000000 --- a/root/programs/CS/NuGet/bk/Public.nuspec +++ /dev/null @@ -1,98 +0,0 @@ - - - - Touryo.Infrastructure.Public - OpenTouryo.Public - 2.7.0-preview3 - OSS Consortium .net subcommittee - daisukenishino77 - Apache-2.0 - https://github.com/OpenTouryoProject/OpenTouryo/tree/master/root/programs/CS/Frameworks/Infrastructure/Public - _OpenTouryo.png - true - Common library of OpenTouryo. - Common library of OpenTouryo. This package is used from template of OpenTouryo. - https://github.com/OpenTouryoProject/OpenTouryo/releases - - OpenTouryo Open棟梁 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/root/programs/CS/NuGet/bk/template.nuspec b/root/programs/CS/NuGet/bk/template.nuspec deleted file mode 100644 index 260879922..000000000 --- a/root/programs/CS/NuGet/bk/template.nuspec +++ /dev/null @@ -1,29 +0,0 @@ - - - - [名前空間(Touryo.Infrastructure.XXXX)]★ - OpenTouryo.[略号(OpenTouryo.XXXX)] - [バージョン番号]★ - OSS Consortium .net subcommittee★ - daisukenishino77 - Apache-2.0 - https://github.com/OpenTouryoProject/OpenTouryo/tree/master/・・・ - images\[*.png, *.iconなどの64*64の画像] - true - [概要説明を記入する] - [詳細説明を記入する]★ - https://github.com/OpenTouryoProject/OpenTouryo/releases - - OpenTouryo Open棟梁 - - - - - - - - - - - - \ No newline at end of file diff --git "a/root/programs/CS/NuGet/in/net8.0-windows/net8.0-windows\343\201\256dll\343\202\222\351\205\215\347\275\256.txt" "b/root/programs/CS/NuGet/in/net10.0-windows/net10.0-windows\343\201\256dll\343\202\222\351\205\215\347\275\256.txt" similarity index 100% rename from "root/programs/CS/NuGet/in/net8.0-windows/net8.0-windows\343\201\256dll\343\202\222\351\205\215\347\275\256.txt" rename to "root/programs/CS/NuGet/in/net10.0-windows/net10.0-windows\343\201\256dll\343\202\222\351\205\215\347\275\256.txt" diff --git "a/root/programs/CS/NuGet/in/net8.0/net8.0\343\201\256dll\343\202\222\351\205\215\347\275\256.txt" "b/root/programs/CS/NuGet/in/net10.0/net10.0\343\201\256dll\343\202\222\351\205\215\347\275\256.txt" similarity index 100% rename from "root/programs/CS/NuGet/in/net8.0/net8.0\343\201\256dll\343\202\222\351\205\215\347\275\256.txt" rename to "root/programs/CS/NuGet/in/net10.0/net10.0\343\201\256dll\343\202\222\351\205\215\347\275\256.txt" diff --git a/root/programs/CS/NuGet/out/pp/_NuGetPush.bat b/root/programs/CS/NuGet/out/pp/_NuGetPush.bat index 669480f47..81f1626bc 100644 --- a/root/programs/CS/NuGet/out/pp/_NuGetPush.bat +++ b/root/programs/CS/NuGet/out/pp/_NuGetPush.bat @@ -1,9 +1,38 @@ -setlocal +setlocal @echo off -"..\..\..\..\nuget.exe" SetApiKey [ApiKey] - -"..\..\..\..\nuget.exe" push Touryo.Infrastructure.Public.*.nupkg -source https://api.nuget.org/v3/index.json -"..\..\..\..\nuget.exe" push Touryo.Infrastructure.Framework.*.nupkg -source https://api.nuget.org/v3/index.json +@rem -------------------------------------------------- +@rem Pass the API key through the NUGET_API_KEY environment variable (#531). +@rem +@rem "nuget.exe SetApiKey" used to be written here, with the key pasted in +@rem before the run and reverted afterwards. That was dangerous twice over. +@rem +@rem - This file is tracked by Git. A key left in it lands in a commit. +@rem - SetApiKey persists the key into %AppData%\NuGet\NuGet.Config. +@rem Reverting this file does not remove it from there. +@rem +@rem An environment variable disappears when the console is closed, +@rem so there is nothing to clean up. Run this first, in the same console: +@rem +@rem set NUGET_API_KEY= +@rem +@rem The symbol server needs -SymbolApiKey. -ApiKey alone is NOT used for it, +@rem and the push of the .snupkg fails with 403 (#531). +@rem +@rem Scope the key to the target packages, give it the shortest expiry, +@rem and delete it at nuget.org once it has been used. +@rem +@rem NOTE: keep this file pure ASCII (#532). +@rem Non-ASCII comments are decoded with the console code page, +@rem which misaligns the parser and executes comment fragments. +@rem -------------------------------------------------- +if not defined NUGET_API_KEY ( + echo [ERROR] The environment variable NUGET_API_KEY is not set. + echo set NUGET_API_KEY=^ + pause + exit /b 1 +) +"..\..\..\..\nuget.exe" push Touryo.Infrastructure.Public.*.nupkg -ApiKey %NUGET_API_KEY% -SymbolApiKey %NUGET_API_KEY% -source https://api.nuget.org/v3/index.json +"..\..\..\..\nuget.exe" push Touryo.Infrastructure.Framework.*.nupkg -ApiKey %NUGET_API_KEY% -SymbolApiKey %NUGET_API_KEY% -source https://api.nuget.org/v3/index.json pause \ No newline at end of file diff --git a/root/programs/CS/NuGet/out/sp/_NuGetPush.bat b/root/programs/CS/NuGet/out/sp/_NuGetPush.bat index 98acc9257..4487c5bb6 100644 --- a/root/programs/CS/NuGet/out/sp/_NuGetPush.bat +++ b/root/programs/CS/NuGet/out/sp/_NuGetPush.bat @@ -1,15 +1,45 @@ -setlocal +setlocal @echo off -"..\..\..\..\nuget.exe" SetApiKey [ApiKey] +@rem -------------------------------------------------- +@rem Pass the API key through the NUGET_API_KEY environment variable (#531). +@rem +@rem "nuget.exe SetApiKey" used to be written here, with the key pasted in +@rem before the run and reverted afterwards. That was dangerous twice over. +@rem +@rem - This file is tracked by Git. A key left in it lands in a commit. +@rem - SetApiKey persists the key into %AppData%\NuGet\NuGet.Config. +@rem Reverting this file does not remove it from there. +@rem +@rem An environment variable disappears when the console is closed, +@rem so there is nothing to clean up. Run this first, in the same console: +@rem +@rem set NUGET_API_KEY= +@rem +@rem The symbol server needs -SymbolApiKey. -ApiKey alone is NOT used for it, +@rem and the push of the .snupkg fails with 403 (#531). +@rem +@rem Scope the key to the target packages, give it the shortest expiry, +@rem and delete it at nuget.org once it has been used. +@rem +@rem NOTE: keep this file pure ASCII (#532). +@rem Non-ASCII comments are decoded with the console code page, +@rem which misaligns the parser and executes comment fragments. +@rem -------------------------------------------------- +if not defined NUGET_API_KEY ( + echo [ERROR] The environment variable NUGET_API_KEY is not set. + echo set NUGET_API_KEY=^ + pause + exit /b 1 +) +@rem A .snupkg next to the .nupkg is published together with it. +@rem -source is required unless NuGet.Config defines DefaultPushSource. +"..\..\..\..\nuget.exe" push Touryo.Infrastructure.Public.*.nupkg -ApiKey %NUGET_API_KEY% -SymbolApiKey %NUGET_API_KEY% -source https://api.nuget.org/v3/index.json +"..\..\..\..\nuget.exe" push Touryo.Infrastructure.Framework.*.nupkg -ApiKey %NUGET_API_KEY% -SymbolApiKey %NUGET_API_KEY% -source https://api.nuget.org/v3/index.json -rem .nupkg と .snupkg の両方が在れば、両方が公開される。 -rem -sourceオプションは、NuGet.Config の DefaultPushSource 値がなければ必須 -"..\..\..\..\nuget.exe" push Touryo.Infrastructure.Public.*.nupkg -source https://api.nuget.org/v3/index.json -"..\..\..\..\nuget.exe" push Touryo.Infrastructure.Framework.*.nupkg -source https://api.nuget.org/v3/index.json - -rem 従って、以下のコマンドは実行不要になった。 -rem "..\..\..\..\nuget.exe" push Touryo.Infrastructure.Public.*.snupkg -source https://api.nuget.org/v3/index.json -rem "..\..\..\..\nuget.exe" push Touryo.Infrastructure.Framework.*.snupkg -source https://api.nuget.org/v3/index.json +@rem The symbol packages therefore need no explicit push. +@rem If the .nupkg was already published, its push fails with 409 and the +@rem symbols are never reached. Push the .snupkg on its own in that case: +@rem "..\..\..\..\nuget.exe" push Touryo.Infrastructure.Public.*.snupkg -ApiKey %NUGET_API_KEY% -SymbolApiKey %NUGET_API_KEY% -source https://api.nuget.org/v3/index.json pause \ No newline at end of file diff --git a/root/programs/CS/NuGet/out/sp/_T_NuGetPush.bat b/root/programs/CS/NuGet/out/sp/_T_NuGetPush.bat index ec6d4c1bc..21f70f019 100644 --- a/root/programs/CS/NuGet/out/sp/_T_NuGetPush.bat +++ b/root/programs/CS/NuGet/out/sp/_T_NuGetPush.bat @@ -1,13 +1,47 @@ -setlocal +setlocal @echo off -"..\..\..\..\nuget.exe" SetApiKey [ApiKey] +@rem -------------------------------------------------- +@rem Pass the API key through the NUGET_API_KEY environment variable (#531). +@rem +@rem "nuget.exe SetApiKey" used to be written here, with the key pasted in +@rem before the run and reverted afterwards. That was dangerous twice over. +@rem +@rem - This file is tracked by Git. A key left in it lands in a commit. +@rem - SetApiKey persists the key into %AppData%\NuGet\NuGet.Config. +@rem Reverting this file does not remove it from there. +@rem +@rem An environment variable disappears when the console is closed, +@rem so there is nothing to clean up. Run this first, in the same console: +@rem +@rem set NUGET_API_KEY= +@rem +@rem The symbol server needs -SymbolApiKey. -ApiKey alone is NOT used for it, +@rem and the push of the .snupkg fails with 403 (#531). +@rem +@rem Scope the key to the target packages, give it the shortest expiry, +@rem and delete it at nuget.org once it has been used. +@rem +@rem NOTE: keep this file pure ASCII (#532). +@rem Non-ASCII comments are decoded with the console code page, +@rem which misaligns the parser and executes comment fragments. +@rem -------------------------------------------------- +if not defined NUGET_API_KEY ( + echo [ERROR] The environment variable NUGET_API_KEY is not set. + echo set NUGET_API_KEY=^ + pause + exit /b 1 +) +@rem A .snupkg next to the .nupkg is published together with it. +@rem -source is required unless NuGet.Config defines DefaultPushSource. +@rem +@rem This is a WILDCARD. An older version left in out\sp is published too. +@rem Check the contents of the folder before running. +"..\..\..\..\nuget.exe" push Erutcurtsarfni.Oyruot.Public.*.nupkg -ApiKey %NUGET_API_KEY% -SymbolApiKey %NUGET_API_KEY% -source https://api.nuget.org/v3/index.json -rem .nupkg と .snupkg の両方が在れば、両方が公開される。 -rem -sourceオプションは、NuGet.Config の DefaultPushSource 値がなければ必須 -"..\..\..\..\nuget.exe" push Erutcurtsarfni.Oyruot.Public.*.nupkg -source https://api.nuget.org/v3/index.json - -rem 従って、以下のコマンドは実行不要になった。 -rem "..\..\..\..\nuget.exe" push Erutcurtsarfni.Oyruot.Public.*.snupkg -source https://api.nuget.org/v3/index.json +@rem The symbol package therefore needs no explicit push. +@rem If the .nupkg was already published, its push fails with 409 and the +@rem symbols are never reached. Push the .snupkg on its own in that case: +@rem "..\..\..\..\nuget.exe" push Erutcurtsarfni.Oyruot.Public.*.snupkg -ApiKey %NUGET_API_KEY% -SymbolApiKey %NUGET_API_KEY% -source https://api.nuget.org/v3/index.json pause \ No newline at end of file diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Business/LayerB.cs b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Business/LayerB.cs new file mode 100644 index 000000000..0a288d919 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Business/LayerB.cs @@ -0,0 +1,847 @@ +//********************************************************************************** +//* フレームワーク・テストクラス(B層) +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :LayerB +//* クラス日本語名 :B層のテスト +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +using SimpleBatch_sample.Common; +using SimpleBatch_sample.Dao; + +using System; +using System.Data; + +using Touryo.Infrastructure.Business.Business; +using Touryo.Infrastructure.Business.Dao; +using Touryo.Infrastructure.Framework.Exceptions; + +namespace SimpleBatch_sample.Business +{ + /// + /// LayerB の概要の説明です + /// + public class LayerB : MyFcBaseLogic + { + #region テンプレ + + /// 業務処理を実装 + /// 引数クラス + private void UOC_メソッド名(TestParameterValue testParameter) + { //メソッド引数にBaseParameterValueの派生の型を定義可能。 + + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + // 個別Dao + LayerD myDao = new LayerD(this.GetDam()); + //myDao.xxxx(testParameter, ref testReturn); + + // 共通Dao + CmnDao cmnDao = new CmnDao(this.GetDam()); + cmnDao.ExecSelectScalar(); + + // ↑業務処理----------------------------------------------------- + } + + #endregion + + #region UOCメソッド + + #region SelectCount + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectCount(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperCount.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperCount.xml"; + break; + } + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = cmnDao.ExecSelectScalar(); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = genDao.D5_SelCnt(); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectCount(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region SelectAll_DT + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectAll_DT(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + DataTable dt = null; + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + } + + // 戻り値 dt + dt = new DataTable(); + + // 共通Daoを実行 + cmnDao.ExecSelectFill_DT(dt); + + // 戻り値を設定 + testReturn.Obj = dt; + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // 戻り値 dt + dt = new DataTable(); + + // 自動生成Daoを実行 + genDao.D2_Select(dt); + + // 戻り値を設定 + testReturn.Obj = (DataTable)dt; + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectAll_DT(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region SelectAll_DS + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectAll_DS(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + DataSet ds = null; + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + } + + // 戻り値 ds + ds = new DataSet(); + + // 共通Daoを実行 + cmnDao.ExecSelectFill_DS(ds); + + // 戻り値を設定 + testReturn.Obj = ds; + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // 戻り値 ds + ds = new DataSet(); + ds.Tables.Add(new DataTable()); + + // 自動生成Daoを実行 + genDao.D2_Select(ds.Tables[0]); + + // 戻り値を設定 + testReturn.Obj = ds; + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectAll_DS(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region SelectAll_DR + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectAll_DR(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + DataTable dt = null; + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + } + + // 戻り値 dt + dt = new DataTable(); + + // 3列生成 + dt.Columns.Add("c1", typeof(string)); + dt.Columns.Add("c2", typeof(string)); + dt.Columns.Add("c3", typeof(string)); + + // 共通Daoを実行 + IDataReader idr = cmnDao.ExecSelect_DR(); + + while (idr.Read()) + { + // DRから読む + object[] objArray = new object[3]; + idr.GetValues(objArray); + + // DTに設定する。 + DataRow dr = dt.NewRow(); + dr.ItemArray = objArray; + dt.Rows.Add(dr); + } + + // 終了したらクローズ + idr.Close(); + + // 戻り値を設定 + testReturn.Obj = dt; + + break; + + case "generate": // 自動生成Daoを使用する。 + + // DRのI/Fなし + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // 戻り値 dt + dt = new DataTable(); + + // 自動生成Daoを実行 + genDao.D2_Select(dt); + + // 戻り値を設定 + testReturn.Obj = (DataTable)dt; + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectAll_DR(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region SelectAll_DSQL + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectAll_DSQL(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperSelectOrder.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperSelectOrder.xml"; + break; + } + + // ユーザ定義パラメタに対して、動的に値を設定する。 + string orderColumn = ""; + string orderSequence = ""; + + if (testParameter.OrderColumn == "c1") + { + orderColumn = "ShipperID"; + } + else if (testParameter.OrderColumn == "c2") + { + orderColumn = "CompanyName"; + } + else if (testParameter.OrderColumn == "c3") + { + orderColumn = "Phone"; + } + else { } + + if (testParameter.OrderSequence == "A") + { + orderSequence = "ASC"; + } + else if (testParameter.OrderSequence == "D") + { + orderSequence = "DESC"; + } + else { } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P1", "test"); + + // ユーザ入力は指定しない。 + // ※ 動的SQLのVALタグは、前後の空白をつめることが有るので、 + // 必要であれば、前後の空白を明示的に指定する必要がある。 + cmnDao.SetUserParameter("COLUMN", " " + orderColumn + " "); + cmnDao.SetUserParameter("SEQUENCE", " " + orderSequence + " "); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // 共通Daoを実行 + cmnDao.ExecSelectFill_DT(dt); + + // 自動生成Daoを実行 + testReturn.Obj = dt; + + break; + + //case "generate": // 自動生成Daoを使用する。 + // // 当該SQLなし + // break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectAll_DSQL(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region Select + + /// 業務処理を実装 + /// 引数クラス + private void UOC_Select(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + DataTable dt = null; + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperSelect.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperSelect.xml"; + break; + } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P1", testParameter.ShipperID); + + // 戻り値 dt + dt = new DataTable(); + + // 共通Daoを実行 + cmnDao.ExecSelectFill_DT(dt); + + // キャストの対策コードを挿入 + + // ・SQLの場合、ShipperIDのintがInt32型にマップされる。 + // ・ODPの場合、ShipperIDのNUMBERがInt64型にマップされる。 + // ・DB2の場合、ShipperIDのDECIMALがxxx型にマップされる。 + if (dt.Rows[0].ItemArray.GetValue(0).GetType().ToString() == "System.Int32") + { + // Int32なのでキャスト + testReturn.ShipperID = (int)dt.Rows[0].ItemArray.GetValue(0); + } + else + { + // それ以外の場合、一度、文字列に変換してInt32.Parseする。 + testReturn.ShipperID = int.Parse(dt.Rows[0].ItemArray.GetValue(0).ToString()); + } + + testReturn.CompanyName = (string)dt.Rows[0].ItemArray.GetValue(1); + testReturn.Phone = (string)dt.Rows[0].ItemArray.GetValue(2); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // パラメタに対して、動的に値を設定する。 + genDao.PK_ShipperID = testParameter.ShipperID; + + // 戻り値 dt + dt = new DataTable(); + + // 自動生成Daoを実行 + genDao.S2_Select(dt); + + // キャストの対策コードを挿入 + + // ・SQLの場合、ShipperIDのintがInt32型にマップされる。 + // ・ODPの場合、ShipperIDのNUMBERがInt64型にマップされる。 + // ・DB2の場合、ShipperIDのDECIMALがxxx型にマップされる。 + if (dt.Rows[0].ItemArray.GetValue(0).GetType().ToString() == "System.Int32") + { + // Int32なのでキャスト + testReturn.ShipperID = (int)dt.Rows[0].ItemArray.GetValue(0); + } + else + { + // それ以外の場合、一度、文字列に変換してInt32.Parseする。 + testReturn.ShipperID = int.Parse(dt.Rows[0].ItemArray.GetValue(0).ToString()); + } + + testReturn.CompanyName = (string)dt.Rows[0].ItemArray.GetValue(1); + testReturn.Phone = (string)dt.Rows[0].ItemArray.GetValue(2); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.Select(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region Insert + + /// 業務処理を実装 + /// 引数クラス + private void UOC_Insert(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + cmnDao.SQLFileName = "ShipperInsert.sql"; + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P2", testParameter.CompanyName); + cmnDao.SetParameter("P3", testParameter.Phone); + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = cmnDao.ExecInsUpDel_NonQuery(); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // パラメタに対して、動的に値を設定する。 + genDao.CompanyName = testParameter.CompanyName; + genDao.Phone = testParameter.Phone; + + // 自動生成Daoを実行 + // 戻り値を設定 + testReturn.Obj = genDao.D1_Insert(); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.Insert(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region Update + + /// 業務処理を実装 + /// 引数クラス + private void UOC_Update(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperUpdate.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperUpdate.xml"; + break; + } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P1", testParameter.ShipperID); + cmnDao.SetParameter("P2", testParameter.CompanyName); + cmnDao.SetParameter("P3", testParameter.Phone); + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = cmnDao.ExecInsUpDel_NonQuery(); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // パラメタに対して、動的に値を設定する。 + genDao.PK_ShipperID = testParameter.ShipperID; + genDao.Set_CompanyName_forUPD = testParameter.CompanyName; + genDao.Set_Phone_forUPD = testParameter.Phone; + + // 自動生成Daoを実行 + // 戻り値を設定 + testReturn.Obj = genDao.S3_Update(); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.Update(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region Delete + + /// 業務処理を実装 + /// 引数クラス + private void UOC_Delete(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperDelete.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperDelete.xml"; + break; + } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P1", testParameter.ShipperID); + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = cmnDao.ExecInsUpDel_NonQuery(); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // パラメタに対して、動的に値を設定する。 + genDao.PK_ShipperID = testParameter.ShipperID; + + // 自動生成Daoを実行 + // 戻り値を設定 + testReturn.Obj = genDao.S4_Delete(); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.Delete(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #endregion + + #region ロールバックのテスト + + /// ロールバックのテスト + /// 引数クラス + private void TestRollback(TestParameterValue testParameter) + { + switch ((testParameter.ActionType.Split('%'))[3]) + { + + case "Business": + + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // 業務例外のスロー + throw new BusinessApplicationException( + "ロールバックのテスト", + "ロールバックのテスト", + "エラー情報"); + //break; // 到達できないためコメントアウト + + case "System": + + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // システム例外のスロー + throw new BusinessSystemException( + "ロールバックのテスト", + "ロールバックのテスト"); + //break; // 到達できないためコメントアウト + + case "Other": + + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // その他、一般的な例外のスロー + throw new Exception("ロールバックのテスト"); + //break; // 到達できないためコメントアウト + + case "Other-Business": + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // その他、一般的な例外(業務例外へ振り替え)のスロー + throw new Exception("Other-Business"); + //break; // 到達できないためコメントアウト + + case "Other-System": + + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // その他、一般的な例外(システム例外へ振り替え)のスロー + throw new Exception("Other-System"); + //break; // 到達できないためコメントアウト + } + } + + #endregion + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Common/TestParameterValue.cs b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Common/TestParameterValue.cs new file mode 100644 index 000000000..e8ed92733 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Common/TestParameterValue.cs @@ -0,0 +1,60 @@ +//********************************************************************************** +//* フレームワーク・テストクラス +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :TestParameterValue +//* クラス日本語名 :テスト用の引数クラス +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +// ベースクラス +using Touryo.Infrastructure.Business.Util; +using Touryo.Infrastructure.Business.Common; + +namespace SimpleBatch_sample.Common +{ + /// + /// TestParameterValue の概要の説明です + /// + public class TestParameterValue : MyParameterValue + { + /// 汎用エリア + public object Obj; + + /// ShipperID + public int ShipperID; + + /// CompanyName + public string CompanyName; + + /// Phone + public string Phone; + + /// OrderColumn + public string OrderColumn; + + /// OrderSequence + public string OrderSequence; + + #region コンストラクタ + + /// コンストラクタ + public TestParameterValue(string screenId, string controlId, string methodName, string actionType, MyUserInfo user) + : base(screenId, controlId, methodName, actionType, user) + { + // Baseのコンストラクタに引数を渡すために必要。 + } + + #endregion + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Common/TestReturnValue.cs b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Common/TestReturnValue.cs new file mode 100644 index 000000000..d4547286c --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Common/TestReturnValue.cs @@ -0,0 +1,42 @@ +//********************************************************************************** +//* フレームワーク・テストクラス +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :TestReturnValue +//* クラス日本語名 :テスト用の戻り値クラス +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +// ベースクラス +using Touryo.Infrastructure.Business.Common; + +namespace SimpleBatch_sample.Common +{ + /// + /// TestReturnValueの概要の説明です + /// + public class TestReturnValue : MyReturnValue + { + /// 汎用エリア + public object Obj; + + /// ShipperID + public int ShipperID; + + /// CompanyName + public string CompanyName; + + /// Phone + public string Phone; + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Dao/DaoShippers.cs b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Dao/DaoShippers.cs new file mode 100644 index 000000000..b0f7f6e3a --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Dao/DaoShippers.cs @@ -0,0 +1,421 @@ +//********************************************************************************** +//* フレームワーク・テストクラス(D層) +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :DaoShippers +//* クラス日本語名 :自動生成Daoクラス +//* +//* 作成日時 :2014/2/9 +//* 作成者 :棟梁 D層自動生成ツール(墨壺), 日立 太郎 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//* 2012/06/14 西野 大介 ResourceLoaderに加え、EmbeddedResourceLoaderに対応 +//* 2013/09/09 西野 大介 ExecGenerateSQLメソッドを追加した(バッチ更新用)。 +//********************************************************************************** + +#region using + +// System~ +using System; +using System.IO; +using System.Data; +using System.Collections; + +// フレームワーク +using Touryo.Infrastructure.Framework.Dao; +using Touryo.Infrastructure.Framework.Common; + +// 部品 +using Touryo.Infrastructure.Public.Db; +using Touryo.Infrastructure.Public.Util; + +// 業務フレームワーク +using Touryo.Infrastructure.Business.Dao; + +#endregion + +/// 自動生成Daoクラス +public class DaoShippers : MyBaseDao +{ + #region インスタンス変数 + + /// ユーザ パラメタ(文字列置換)用ハッシュ テーブル + protected Hashtable HtUserParameter = new Hashtable(); + /// パラメタ ライズド クエリのパラメタ用ハッシュ テーブル + protected Hashtable HtParameter = new Hashtable(); + + #endregion + + #region コンストラクタ + + /// コンストラクタ + public DaoShippers(BaseDam dam) : base(dam) { } + + #endregion + + #region 共通関数(パラメタの制御) + + /// ユーザ パラメタ(文字列置換)をハッシュ テーブルに設定する。 + /// ユーザ パラメタ名 + /// ユーザ パラメタ値 + public void SetUserParameteToHt(string userParamName, string userParamValue) + { + // ユーザ パラメタをハッシュ テーブルに設定 + this.HtUserParameter[userParamName] = userParamValue; + } + + /// パラメタ ライズド クエリのパラメタをハッシュ テーブルに設定する。 + /// パラメタ名 + /// パラメタ値 + public void SetParameteToHt(string paramName, object paramValue) + { + // ユーザ パラメタをハッシュ テーブルに設定 + this.HtParameter[paramName] = paramValue; + } + + /// + /// ・ユーザ パラメタ(文字列置換) + /// ・パラメタ ライズド クエリのパラメタ + /// を格納するハッシュ テーブルをクリアする。 + /// + public void ClearParametersFromHt() + { + // ユーザ パラメタ(文字列置換)用ハッシュ テーブルを初期化 + this.HtUserParameter = new Hashtable(); + // パラメタ ライズド クエリのパラメタ用ハッシュ テーブルを初期化 + this.HtParameter = new Hashtable(); + } + + /// パラメタの設定(内部用) + protected void SetParametersFromHt() + { + // ユーザ パラメタ(文字列置換)を設定する。 + foreach (string userParamName in this.HtUserParameter.Keys) + { + this.SetUserParameter(userParamName, this.HtUserParameter[userParamName].ToString()); + } + + // パラメタ ライズド クエリのパラメタを設定する。 + foreach (string paramName in this.HtParameter.Keys) + { + this.SetParameter(paramName, this.HtParameter[paramName]); + } + } + + #endregion + + #region プロパティ プロシージャ(setter、getter) + + + /// ShipperID列(主キー列)に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタを除く + public object PK_ShipperID + { + set + { + this.HtParameter["ShipperID"] = value; + } + get + { + return this.HtParameter["ShipperID"]; + } + } + + + + /// CompanyName列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタを除く + public object CompanyName + { + set + { + this.HtParameter["CompanyName"] = value; + } + get + { + return this.HtParameter["CompanyName"]; + } + } + + /// Phone列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタを除く + public object Phone + { + set + { + this.HtParameter["Phone"] = value; + } + get + { + return this.HtParameter["Phone"]; + } + } + + + /// Set_ShipperID_forUPD列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタ専用 + public object Set_ShipperID_forUPD + { + set + { + this.HtParameter["Set_ShipperID_forUPD"] = value; + } + get + { + return this.HtParameter["Set_ShipperID_forUPD"]; + } + } + + + /// Set_CompanyName_forUPD列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタ専用 + public object Set_CompanyName_forUPD + { + set + { + this.HtParameter["Set_CompanyName_forUPD"] = value; + } + get + { + return this.HtParameter["Set_CompanyName_forUPD"]; + } + } + + + /// Set_Phone_forUPD列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタ専用 + public object Set_Phone_forUPD + { + set + { + this.HtParameter["Set_Phone_forUPD"] = value; + } + get + { + return this.HtParameter["Set_Phone_forUPD"]; + } + } + + + + /// ShipperID_Like列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 動的参照処理時のLIKE検索で使用するパラメタ専用 + public object ShipperID_Like + { + set + { + this.HtParameter["ShipperID_Like"] = value; + } + get + { + return this.HtParameter["ShipperID_Like"]; + } + } + + + /// CompanyName_Like列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 動的参照処理時のLIKE検索で使用するパラメタ専用 + public object CompanyName_Like + { + set + { + this.HtParameter["CompanyName_Like"] = value; + } + get + { + return this.HtParameter["CompanyName_Like"]; + } + } + + + /// Phone_Like列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 動的参照処理時のLIKE検索で使用するパラメタ専用 + public object Phone_Like + { + set + { + this.HtParameter["Phone_Like"] = value; + } + get + { + return this.HtParameter["Phone_Like"]; + } + } + + + #endregion + + #region クエリ メソッド + + #region Insert + + /// 1レコード挿入する。 + /// 挿入された行の数 + public int S1_Insert() + { + // ファイルからSQL(Insert)を設定する。 + this.SetSqlByFile2("DaoShippers_S1_Insert.sql"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(Insert)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + /// 1レコード挿入する。 + /// 挿入された行の数 + /// パラメタで指定した列のみ挿入値が有効になる。 + public int D1_Insert() + { + // ファイルからSQL(DynIns)を設定する。 + this.SetSqlByFile2("DaoShippers_D1_Insert.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(DynIns)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + #endregion + + #region Select + + /// 主キーを指定し、1レコード参照する。 + /// 結果を格納するDataTable + public void S2_Select(DataTable dt) + { + // ファイルからSQL(Select)を設定する。 + this.SetSqlByFile2("DaoShippers_S2_Select.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(Select)を実行し、戻り値を戻す。 + this.ExecSelectFill_DT(dt); + } + + /// 検索条件を指定し、結果セットを参照する。 + /// 結果を格納するDataTable + public void D2_Select(DataTable dt) + { + // ファイルからSQL(DynSel)を設定する。 + this.SetSqlByFile2("DaoShippers_D2_Select.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(DynSel)を実行し、戻り値を戻す。 + this.ExecSelectFill_DT(dt); + } + + #endregion + + #region Update + + /// 主キーを指定し、1レコード更新する。 + /// 更新された行の数 + /// パラメタで指定した列のみ更新値が有効になる。 + public int S3_Update() + { + // ファイルからSQL(Update)を設定する。 + this.SetSqlByFile2("DaoShippers_S3_Update.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(Update)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + /// 任意の検索条件でデータを更新する。 + /// 更新された行の数 + /// パラメタで指定した列のみ更新値が有効になる。 + public int D3_Update() + { + // ファイルからSQL(DynUpd)を設定する。 + this.SetSqlByFile2("DaoShippers_D3_Update.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(DynUpd)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + #endregion + + #region Delete + + /// 主キーを指定し、1レコード削除する。 + /// 削除された行の数 + public int S4_Delete() + { + // ファイルからSQL(Delete)を設定する。 + this.SetSqlByFile2("DaoShippers_S4_Delete.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(Delete)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + /// 任意の検索条件でデータを削除する。 + /// 削除された行の数 + public int D4_Delete() + { + // ファイルからSQL(DynDel)を設定する。 + this.SetSqlByFile2("DaoShippers_D4_Delete.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(DynDel)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + #endregion + + #region 拡張メソッド + + /// テーブルのレコード件数を取得する + /// テーブルのレコード件数 + public object D5_SelCnt() + { + // ファイルからSQL(DynSelCnt)を設定する。 + this.SetSqlByFile2("DaoShippers_D5_SelCnt.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(SELECT COUNT)を実行し、戻り値を戻す。 + return this.ExecSelectScalar(); + } + + /// 静的SQLを生成する。 + /// ファイル名 + /// SQLユーティリティ + /// 生成した静的SQL + public string ExecGenerateSQL(string fileName, SQLUtility sqlUtil) + { + // ファイルからSQLを設定する。 + this.SetSqlByFile2(fileName); + + // パラメタの設定 + this.SetParametersFromHt(); + + return base.ExecGenerateSQL(sqlUtil); + } + + #endregion + + #endregion +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Dao/LayerD.cs b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Dao/LayerD.cs new file mode 100644 index 000000000..8646c06d9 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Dao/LayerD.cs @@ -0,0 +1,517 @@ +//********************************************************************************** +//* フレームワーク・テストクラス(D層) +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :LayerD +//* クラス日本語名 :D層のテスト +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +using SimpleBatch_sample.Common; + +using System.Data; + +using Touryo.Infrastructure.Business.Dao; +using Touryo.Infrastructure.Public.Db; + +namespace SimpleBatch_sample.Dao +{ + /// + /// LayerD の概要の説明です + /// + public class LayerD : MyBaseDao + { + /// + /// コンストラクタ + /// + public LayerD(BaseDam dam) : base(dam) { } + + #region テンプレ + + /// テンプレ + /// 引数クラス + /// 戻り値クラス + public void テンプレ(TestParameterValue testParameter, TestReturnValue testReturn) + { + + // ↓DBアクセス----------------------------------------------------- + + // ● 下記のいづれかの方法でSQLを設定する。 + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2("ファイル名"); + + // -- 直接指定する場合。 + this.SetSqlByCommand("SQL文"); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", testParameter.ShipperID); + + object obj; + + // -- 追加、更新、削除の場合(件数を確認できる) + obj = this.ExecInsUpDel_NonQuery(); + + // -- 先頭の1セル分の情報を返すSELECTクエリを実行する場合 + obj = this.ExecSelectScalar(); + + // -- テーブル(or レコード)の情報を返す + // SELECTクエリを実行する場合(引数 = データテーブル) + obj = new DataTable(); + this.ExecSelectFill_DT((DataTable)obj); + + // -- テーブル(or レコード)の情報を返す + // SELECTクエリを実行する場合(引数 = データセット) + obj = new DataSet(); + this.ExecSelectFill_DS((DataSet)obj); + + // -- データリーダを返す + IDataReader idr = (IDataReader)this.ExecSelect_DR(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #region 参照系 + + #region 件数取得(SelectCount) + + /// 件数情報を返すSELECTクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void SelectCount(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperCount.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperCount.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + object obj; + + // -- 件数情報を返すSELECTクエリを実行する + obj = this.ExecSelectScalar(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #region 一覧取得(SelectAll) + + /// 一覧を返すSELECTクエリを実行する(DT) + /// 引数クラス + /// 戻り値クラス + public void SelectAll_DT(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string commandText = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + commandText = "SELECT * FROM Shippers"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + commandText = + "SELECT * FROM Shippers"; + // 通常、動的SQLをSetSqlByCommandで直接指定するような使い方はしない。 + } + + // -- 直接指定する場合。 + this.SetSqlByCommand(commandText); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // -- 一覧を返すSELECTクエリを実行する + this.ExecSelectFill_DT(dt); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = dt; + } + + /// 一覧を返すSELECTクエリを実行する(DS) + /// 引数クラス + /// 戻り値クラス + public void SelectAll_DS(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string commandText = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + commandText = "SELECT * FROM Shippers"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + commandText = + "SELECT * FROM Shippers"; + // 通常、動的SQLをSetSqlByCommandで直接指定するような使い方はしない。 + } + + // -- 直接指定する場合。 + this.SetSqlByCommand(commandText); + + // 戻り値 ds + DataSet ds = new DataSet(); + + // -- 一覧を返すSELECTクエリを実行する + this.ExecSelectFill_DS(ds); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = ds; + } + + /// 一覧を返すSELECTクエリを実行する(DR) + /// 引数クラス + /// 戻り値クラス + public void SelectAll_DR(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string commandText = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + commandText = "SELECT * FROM Shippers"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + commandText = + "SELECT * FROM Shippers"; + // 通常、動的SQLをSetSqlByCommandで直接指定するような使い方はしない。 + } + + // -- 直接指定する場合。 + this.SetSqlByCommand(commandText); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // 3列生成 + dt.Columns.Add("c1", typeof(string)); + dt.Columns.Add("c2", typeof(string)); + dt.Columns.Add("c3", typeof(string)); + + // -- 一覧を返すSELECTクエリを実行する + IDataReader idr = (IDataReader)this.ExecSelect_DR(); + + while (idr.Read()) + { + // DRから読む + object[] objArray = new object[3]; + idr.GetValues(objArray); + + // DTに設定する。 + DataRow dr = dt.NewRow(); + dr.ItemArray = objArray; + dt.Rows.Add(dr); + } + + // 終了したらクローズ + idr.Close(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = dt; + } + + /// 一覧を返すSELECTクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void SelectAll_DSQL(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperSelectOrder.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperSelectOrder.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + // ユーザ定義パラメタに対して、動的に値を設定する。 + string orderColumn = ""; + string orderSequence = ""; + + if (testParameter.OrderColumn == "c1") + { + orderColumn = "ShipperID"; + } + else if (testParameter.OrderColumn == "c2") + { + orderColumn = "CompanyName"; + } + else if (testParameter.OrderColumn == "c3") + { + orderColumn = "Phone"; + } + else { } + + if (testParameter.OrderSequence == "A") + { + orderSequence = "ASC"; + } + else if (testParameter.OrderSequence == "D") + { + orderSequence = "DESC"; + } + else { } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", "test"); + + // ユーザ入力は指定しない。 + // ※ 動的SQLのVALタグは、前後の空白をつめることが有るので、 + // 必要であれば、前後の空白を明示的に指定する必要がある。 + this.SetUserParameter("COLUMN", " " + orderColumn + " "); + this.SetUserParameter("SEQUENCE", " " + orderSequence + " "); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // -- 一覧を返すSELECTクエリを実行する + this.ExecSelectFill_DT(dt); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = dt; + } + + #endregion + + #region 参照 + + /// 1レコードを返すSELECTクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void Select(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperSelect.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperSelect.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", testParameter.ShipperID); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // -- 1レコードを返すSELECTクエリを実行する + this.ExecSelectFill_DT(dt); + + // ↑DBアクセス----------------------------------------------------- + + //// 戻り値を設定 // 不要 + //testReturn.Obj = dt; + + // キャストの対策コードを挿入 + + // ・SQLの場合、ShipperIDのintがInt32型にマップされる。 + // ・ODPの場合、ShipperIDのNUMBERがInt64型にマップされる。 + // ・DB2の場合、ShipperIDのDECIMALがxxx型にマップされる。 + if (dt.Rows[0].ItemArray.GetValue(0).GetType().ToString() == "System.Int32") + { + // Int32なのでキャスト + testReturn.ShipperID = (int)dt.Rows[0].ItemArray.GetValue(0); + } + else + { + // それ以外の場合、一度、文字列に変換してInt32.Parseする。 + testReturn.ShipperID = int.Parse(dt.Rows[0].ItemArray.GetValue(0).ToString()); + } + + testReturn.CompanyName = (string)dt.Rows[0].ItemArray.GetValue(1); + testReturn.Phone = (string)dt.Rows[0].ItemArray.GetValue(2); + } + + #endregion + + #endregion + + #region 更新系 + + #region 追加 + + /// Insertクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void Insert(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2("ShipperInsert.sql"); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P2", testParameter.CompanyName); + this.SetParameter("P3", testParameter.Phone); + + object obj; + + // -- 追加(件数を確認できる) + obj = this.ExecInsUpDel_NonQuery(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #region 更新 + + /// Updateクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void Update(TestParameterValue testParameter, TestReturnValue testReturn) + { + + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperUpdate.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperUpdate.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", testParameter.ShipperID); + this.SetParameter("P2", testParameter.CompanyName); + this.SetParameter("P3", testParameter.Phone); + + object obj; + + // -- 更新(件数を確認できる) + obj = this.ExecInsUpDel_NonQuery(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #region 削除 + + /// Deleteクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void Delete(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperDelete.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperDelete.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", testParameter.ShipperID); + + object obj; + + // -- 削除(件数を確認できる) + obj = this.ExecInsUpDel_NonQuery(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #endregion + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/MSGDefinition.xml b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/MSGDefinition.xml new file mode 100644 index 000000000..f2283b409 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/MSGDefinition.xml @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + + + + + + + diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Program.cs b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Program.cs new file mode 100644 index 000000000..afe9a190d --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/Program.cs @@ -0,0 +1,96 @@ +//********************************************************************************** +//* 単純バッチ処理・サンプル アプリ +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :Program +//* クラス日本語名 :サンプル バッチ +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +using SimpleBatch_sample.Business; +using SimpleBatch_sample.Common; + +using System; +using System.IO; +using System.Collections.Generic; +using System.Reflection; + +using Touryo.Infrastructure.Business.Util; +using Touryo.Infrastructure.Public.Db; +using Touryo.Infrastructure.Public.Str; +using Touryo.Infrastructure.Public.Util; + +namespace SimpleBatch_sample +{ + /// Program + class Program + { + /// Main + static void Main(string[] args) + { + //////////////////////////////////////////////////////////////////////// + // 簡素なサンプルなので、 + // ・多重化(タスク毎、結果セットを分割) + // ・フェッチ・サイズ(メモリ消費量を抑える) + // ・コミット・インターバル、リラン + // 等の考慮が別途必要になることがあります。 + //////////////////////////////////////////////////////////////////////// + + // configの初期化 + string dir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory + .FullName.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + GetConfigParameter.InitConfiguration(dir + "/appsettings.json"); + + // コマンドラインをバラす関数がある。 + List valsLst = null; + Dictionary argsDic = null; + + StringVariableOperator.GetCommandArgs('/', out argsDic, out valsLst); + + // 引数クラスを生成 + // 下位(B・D層)は、テスト クラスを流用する + TestParameterValue testParameterValue + = new TestParameterValue( + System.Reflection.Assembly.GetExecutingAssembly().Location, "-", "SelectCount", + argsDic["/DAP"] + "%" + + argsDic["/MODE1"] + "%" + + argsDic["/MODE2"] + "%" + + argsDic["/EXROLLBACK"], + new MyUserInfo("", "")); + + // 戻り値 + TestReturnValue testReturnValue; + + // B層呼出し + LayerB layerB = new LayerB(); + testReturnValue = (TestReturnValue)layerB.DoBusinessLogic(testParameterValue, DbEnum.IsolationLevelEnum.ReadCommitted); + + if (testReturnValue.ErrorFlag == true) + { + // 結果(業務続行可能なエラー) + string error = "ErrorMessageID:" + testReturnValue.ErrorMessageID + "\r\n"; + error += "ErrorMessage:" + testReturnValue.ErrorMessage + "\r\n"; + error += "ErrorInfo:" + testReturnValue.ErrorInfo + "\r\n"; + + Console.WriteLine(error); + Console.ReadKey(); + } + else + { + // 結果(正常系) + Console.WriteLine(testReturnValue.Obj.ToString() + "件のデータがあります"); + Console.ReadKey(); + } + } + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SPDefinition.xml b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SPDefinition.xml new file mode 100644 index 000000000..6baf634bc --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SPDefinition.xml @@ -0,0 +1,15 @@ + + + + +]> + + + + + + + diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SampleLogConf2CS.xml b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SampleLogConf2CS.xml new file mode 100644 index 000000000..476cea7c5 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SampleLogConf2CS.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SimpleBatch_sample.csproj b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SimpleBatch_sample.csproj new file mode 100644 index 000000000..37ba00258 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SimpleBatch_sample.csproj @@ -0,0 +1,45 @@ + + + + Exe + net10.0 + + + + full + true + + + + + + + + + + + + + + + + ..\..\..\..\..\Frameworks\Infrastructure\Build_netcore100\net10.0\OpenTouryo.Business.dll + + + + + + Always + + + Always + + + Always + + + Always + + + + diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SimpleBatch_sample.sln b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SimpleBatch_sample.sln new file mode 100644 index 000000000..baf24c72d --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/SimpleBatch_sample.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11018.127 d18.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleBatch_sample", "SimpleBatch_sample.csproj", "{4E1E7400-A012-49E2-8D28-A361F0E1BEE2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4E1E7400-A012-49E2-8D28-A361F0E1BEE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E1E7400-A012-49E2-8D28-A361F0E1BEE2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E1E7400-A012-49E2-8D28-A361F0E1BEE2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E1E7400-A012-49E2-8D28-A361F0E1BEE2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3D69CB54-D2E7-441E-B62A-0E3FC8FD87CB} + EndGlobalSection +EndGlobal diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/appsettings.json b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/appsettings.json new file mode 100644 index 000000000..4ea963306 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/appsettings.json @@ -0,0 +1,19 @@ +{ + "connectionStrings": { + "ConnectionString_SQL": "Data Source=localhost;Initial Catalog=Northwind;User ID=sa;Password=seigi@123;Encrypt=false;", + "ConnectionString_ODBC": "Dsn=odbc_test1", + "ConnectionString_ODP": "User Id=SCOTT;Password=tiger;Data Source=localhost/XE;", + "ConnectionString_MCN": "Server=localhost;Database=test;User Id=root;Password=seigi@123", + "ConnectionString_NPS": "HOST=localhost;DATABASE=postgres;USER ID=postgres;PASSWORD=seigi@123;" + }, + "appSettings": { + "FxXMLMSGDefinition": "MSGDefinition.xml", + "FxXMLSPDefinition": "SPDefinition.xml", + "FxLog4NetConfFile": "SampleLogConf2CS.xml", + "FxSqlTraceLog": "on", + "FxSqlCacheSwitch": "off", + "FxSqlEncoding": "utf-8", + "FxSqlCommandTimeout": "30", + "SqlTextFilePath": "C:/root/files/resource/Sql" + } +} \ No newline at end of file diff --git a/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/readme.txt b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/readme.txt new file mode 100644 index 000000000..c501c1efb --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net10.0/SimpleBatch_sample/readme.txt @@ -0,0 +1,4 @@ +以下の様なコマンドライン引数をプロジェクトのプロパティの +デバッグ → 開始オプション → コマンドライン引数から設定して下さい。 + +/Dap SQL /Mode1 individual /Mode2 static /EXROLLBACK - \ No newline at end of file diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Business/LayerB.cs b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Business/LayerB.cs new file mode 100644 index 000000000..0a288d919 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Business/LayerB.cs @@ -0,0 +1,847 @@ +//********************************************************************************** +//* フレームワーク・テストクラス(B層) +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :LayerB +//* クラス日本語名 :B層のテスト +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +using SimpleBatch_sample.Common; +using SimpleBatch_sample.Dao; + +using System; +using System.Data; + +using Touryo.Infrastructure.Business.Business; +using Touryo.Infrastructure.Business.Dao; +using Touryo.Infrastructure.Framework.Exceptions; + +namespace SimpleBatch_sample.Business +{ + /// + /// LayerB の概要の説明です + /// + public class LayerB : MyFcBaseLogic + { + #region テンプレ + + /// 業務処理を実装 + /// 引数クラス + private void UOC_メソッド名(TestParameterValue testParameter) + { //メソッド引数にBaseParameterValueの派生の型を定義可能。 + + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + // 個別Dao + LayerD myDao = new LayerD(this.GetDam()); + //myDao.xxxx(testParameter, ref testReturn); + + // 共通Dao + CmnDao cmnDao = new CmnDao(this.GetDam()); + cmnDao.ExecSelectScalar(); + + // ↑業務処理----------------------------------------------------- + } + + #endregion + + #region UOCメソッド + + #region SelectCount + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectCount(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperCount.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperCount.xml"; + break; + } + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = cmnDao.ExecSelectScalar(); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = genDao.D5_SelCnt(); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectCount(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region SelectAll_DT + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectAll_DT(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + DataTable dt = null; + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + } + + // 戻り値 dt + dt = new DataTable(); + + // 共通Daoを実行 + cmnDao.ExecSelectFill_DT(dt); + + // 戻り値を設定 + testReturn.Obj = dt; + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // 戻り値 dt + dt = new DataTable(); + + // 自動生成Daoを実行 + genDao.D2_Select(dt); + + // 戻り値を設定 + testReturn.Obj = (DataTable)dt; + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectAll_DT(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region SelectAll_DS + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectAll_DS(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + DataSet ds = null; + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + } + + // 戻り値 ds + ds = new DataSet(); + + // 共通Daoを実行 + cmnDao.ExecSelectFill_DS(ds); + + // 戻り値を設定 + testReturn.Obj = ds; + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // 戻り値 ds + ds = new DataSet(); + ds.Tables.Add(new DataTable()); + + // 自動生成Daoを実行 + genDao.D2_Select(ds.Tables[0]); + + // 戻り値を設定 + testReturn.Obj = ds; + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectAll_DS(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region SelectAll_DR + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectAll_DR(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + DataTable dt = null; + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLText = "SELECT * FROM Shippers"; + break; + } + + // 戻り値 dt + dt = new DataTable(); + + // 3列生成 + dt.Columns.Add("c1", typeof(string)); + dt.Columns.Add("c2", typeof(string)); + dt.Columns.Add("c3", typeof(string)); + + // 共通Daoを実行 + IDataReader idr = cmnDao.ExecSelect_DR(); + + while (idr.Read()) + { + // DRから読む + object[] objArray = new object[3]; + idr.GetValues(objArray); + + // DTに設定する。 + DataRow dr = dt.NewRow(); + dr.ItemArray = objArray; + dt.Rows.Add(dr); + } + + // 終了したらクローズ + idr.Close(); + + // 戻り値を設定 + testReturn.Obj = dt; + + break; + + case "generate": // 自動生成Daoを使用する。 + + // DRのI/Fなし + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // 戻り値 dt + dt = new DataTable(); + + // 自動生成Daoを実行 + genDao.D2_Select(dt); + + // 戻り値を設定 + testReturn.Obj = (DataTable)dt; + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectAll_DR(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region SelectAll_DSQL + + /// 業務処理を実装 + /// 引数クラス + private void UOC_SelectAll_DSQL(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperSelectOrder.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperSelectOrder.xml"; + break; + } + + // ユーザ定義パラメタに対して、動的に値を設定する。 + string orderColumn = ""; + string orderSequence = ""; + + if (testParameter.OrderColumn == "c1") + { + orderColumn = "ShipperID"; + } + else if (testParameter.OrderColumn == "c2") + { + orderColumn = "CompanyName"; + } + else if (testParameter.OrderColumn == "c3") + { + orderColumn = "Phone"; + } + else { } + + if (testParameter.OrderSequence == "A") + { + orderSequence = "ASC"; + } + else if (testParameter.OrderSequence == "D") + { + orderSequence = "DESC"; + } + else { } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P1", "test"); + + // ユーザ入力は指定しない。 + // ※ 動的SQLのVALタグは、前後の空白をつめることが有るので、 + // 必要であれば、前後の空白を明示的に指定する必要がある。 + cmnDao.SetUserParameter("COLUMN", " " + orderColumn + " "); + cmnDao.SetUserParameter("SEQUENCE", " " + orderSequence + " "); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // 共通Daoを実行 + cmnDao.ExecSelectFill_DT(dt); + + // 自動生成Daoを実行 + testReturn.Obj = dt; + + break; + + //case "generate": // 自動生成Daoを使用する。 + // // 当該SQLなし + // break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectAll_DSQL(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region Select + + /// 業務処理を実装 + /// 引数クラス + private void UOC_Select(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + DataTable dt = null; + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperSelect.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperSelect.xml"; + break; + } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P1", testParameter.ShipperID); + + // 戻り値 dt + dt = new DataTable(); + + // 共通Daoを実行 + cmnDao.ExecSelectFill_DT(dt); + + // キャストの対策コードを挿入 + + // ・SQLの場合、ShipperIDのintがInt32型にマップされる。 + // ・ODPの場合、ShipperIDのNUMBERがInt64型にマップされる。 + // ・DB2の場合、ShipperIDのDECIMALがxxx型にマップされる。 + if (dt.Rows[0].ItemArray.GetValue(0).GetType().ToString() == "System.Int32") + { + // Int32なのでキャスト + testReturn.ShipperID = (int)dt.Rows[0].ItemArray.GetValue(0); + } + else + { + // それ以外の場合、一度、文字列に変換してInt32.Parseする。 + testReturn.ShipperID = int.Parse(dt.Rows[0].ItemArray.GetValue(0).ToString()); + } + + testReturn.CompanyName = (string)dt.Rows[0].ItemArray.GetValue(1); + testReturn.Phone = (string)dt.Rows[0].ItemArray.GetValue(2); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // パラメタに対して、動的に値を設定する。 + genDao.PK_ShipperID = testParameter.ShipperID; + + // 戻り値 dt + dt = new DataTable(); + + // 自動生成Daoを実行 + genDao.S2_Select(dt); + + // キャストの対策コードを挿入 + + // ・SQLの場合、ShipperIDのintがInt32型にマップされる。 + // ・ODPの場合、ShipperIDのNUMBERがInt64型にマップされる。 + // ・DB2の場合、ShipperIDのDECIMALがxxx型にマップされる。 + if (dt.Rows[0].ItemArray.GetValue(0).GetType().ToString() == "System.Int32") + { + // Int32なのでキャスト + testReturn.ShipperID = (int)dt.Rows[0].ItemArray.GetValue(0); + } + else + { + // それ以外の場合、一度、文字列に変換してInt32.Parseする。 + testReturn.ShipperID = int.Parse(dt.Rows[0].ItemArray.GetValue(0).ToString()); + } + + testReturn.CompanyName = (string)dt.Rows[0].ItemArray.GetValue(1); + testReturn.Phone = (string)dt.Rows[0].ItemArray.GetValue(2); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.Select(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region Insert + + /// 業務処理を実装 + /// 引数クラス + private void UOC_Insert(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + cmnDao.SQLFileName = "ShipperInsert.sql"; + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P2", testParameter.CompanyName); + cmnDao.SetParameter("P3", testParameter.Phone); + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = cmnDao.ExecInsUpDel_NonQuery(); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // パラメタに対して、動的に値を設定する。 + genDao.CompanyName = testParameter.CompanyName; + genDao.Phone = testParameter.Phone; + + // 自動生成Daoを実行 + // 戻り値を設定 + testReturn.Obj = genDao.D1_Insert(); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.Insert(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region Update + + /// 業務処理を実装 + /// 引数クラス + private void UOC_Update(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperUpdate.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperUpdate.xml"; + break; + } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P1", testParameter.ShipperID); + cmnDao.SetParameter("P2", testParameter.CompanyName); + cmnDao.SetParameter("P3", testParameter.Phone); + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = cmnDao.ExecInsUpDel_NonQuery(); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // パラメタに対して、動的に値を設定する。 + genDao.PK_ShipperID = testParameter.ShipperID; + genDao.Set_CompanyName_forUPD = testParameter.CompanyName; + genDao.Set_Phone_forUPD = testParameter.Phone; + + // 自動生成Daoを実行 + // 戻り値を設定 + testReturn.Obj = genDao.S3_Update(); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.Update(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #region Delete + + /// 業務処理を実装 + /// 引数クラス + private void UOC_Delete(TestParameterValue testParameter) + { + // 戻り値クラスを生成して、事前に戻り値に設定しておく。 + TestReturnValue testReturn = new TestReturnValue(); + this.ReturnValue = testReturn; + + // ↓業務処理----------------------------------------------------- + + switch ((testParameter.ActionType.Split('%'))[1]) + { + case "common": // 共通Daoを使用する。 + + // 共通Daoを生成 + CmnDao cmnDao = new CmnDao(this.GetDam()); + + switch ((testParameter.ActionType.Split('%'))[2]) + { + case "static": + // 静的SQLを指定 + cmnDao.SQLFileName = "ShipperDelete.sql"; + break; + + case "dynamic": + // 動的SQLを指定 + cmnDao.SQLFileName = "ShipperDelete.xml"; + break; + } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + cmnDao.SetParameter("P1", testParameter.ShipperID); + + // 共通Daoを実行 + // 戻り値を設定 + testReturn.Obj = cmnDao.ExecInsUpDel_NonQuery(); + + break; + + case "generate": // 自動生成Daoを使用する。 + + // 自動生成Daoを生成 + DaoShippers genDao = new DaoShippers(this.GetDam()); + + // パラメタに対して、動的に値を設定する。 + genDao.PK_ShipperID = testParameter.ShipperID; + + // 自動生成Daoを実行 + // 戻り値を設定 + testReturn.Obj = genDao.S4_Delete(); + + break; + + default: // 個別Daoを使用する。 + LayerD myDao = new LayerD(this.GetDam()); + myDao.Delete(testParameter, testReturn); + break; + } + + // ↑業務処理----------------------------------------------------- + + // ロールバックのテスト + this.TestRollback(testParameter); + } + + #endregion + + #endregion + + #region ロールバックのテスト + + /// ロールバックのテスト + /// 引数クラス + private void TestRollback(TestParameterValue testParameter) + { + switch ((testParameter.ActionType.Split('%'))[3]) + { + + case "Business": + + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // 業務例外のスロー + throw new BusinessApplicationException( + "ロールバックのテスト", + "ロールバックのテスト", + "エラー情報"); + //break; // 到達できないためコメントアウト + + case "System": + + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // システム例外のスロー + throw new BusinessSystemException( + "ロールバックのテスト", + "ロールバックのテスト"); + //break; // 到達できないためコメントアウト + + case "Other": + + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // その他、一般的な例外のスロー + throw new Exception("ロールバックのテスト"); + //break; // 到達できないためコメントアウト + + case "Other-Business": + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // その他、一般的な例外(業務例外へ振り替え)のスロー + throw new Exception("Other-Business"); + //break; // 到達できないためコメントアウト + + case "Other-System": + + // 戻り値が見えるか確認する。 + ((TestReturnValue)this.ReturnValue).Obj = "戻り値が戻るか?"; + + // その他、一般的な例外(システム例外へ振り替え)のスロー + throw new Exception("Other-System"); + //break; // 到達できないためコメントアウト + } + } + + #endregion + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Common/TestParameterValue.cs b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Common/TestParameterValue.cs new file mode 100644 index 000000000..e8ed92733 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Common/TestParameterValue.cs @@ -0,0 +1,60 @@ +//********************************************************************************** +//* フレームワーク・テストクラス +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :TestParameterValue +//* クラス日本語名 :テスト用の引数クラス +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +// ベースクラス +using Touryo.Infrastructure.Business.Util; +using Touryo.Infrastructure.Business.Common; + +namespace SimpleBatch_sample.Common +{ + /// + /// TestParameterValue の概要の説明です + /// + public class TestParameterValue : MyParameterValue + { + /// 汎用エリア + public object Obj; + + /// ShipperID + public int ShipperID; + + /// CompanyName + public string CompanyName; + + /// Phone + public string Phone; + + /// OrderColumn + public string OrderColumn; + + /// OrderSequence + public string OrderSequence; + + #region コンストラクタ + + /// コンストラクタ + public TestParameterValue(string screenId, string controlId, string methodName, string actionType, MyUserInfo user) + : base(screenId, controlId, methodName, actionType, user) + { + // Baseのコンストラクタに引数を渡すために必要。 + } + + #endregion + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Common/TestReturnValue.cs b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Common/TestReturnValue.cs new file mode 100644 index 000000000..d4547286c --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Common/TestReturnValue.cs @@ -0,0 +1,42 @@ +//********************************************************************************** +//* フレームワーク・テストクラス +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :TestReturnValue +//* クラス日本語名 :テスト用の戻り値クラス +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +// ベースクラス +using Touryo.Infrastructure.Business.Common; + +namespace SimpleBatch_sample.Common +{ + /// + /// TestReturnValueの概要の説明です + /// + public class TestReturnValue : MyReturnValue + { + /// 汎用エリア + public object Obj; + + /// ShipperID + public int ShipperID; + + /// CompanyName + public string CompanyName; + + /// Phone + public string Phone; + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Dao/DaoShippers.cs b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Dao/DaoShippers.cs new file mode 100644 index 000000000..b0f7f6e3a --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Dao/DaoShippers.cs @@ -0,0 +1,421 @@ +//********************************************************************************** +//* フレームワーク・テストクラス(D層) +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :DaoShippers +//* クラス日本語名 :自動生成Daoクラス +//* +//* 作成日時 :2014/2/9 +//* 作成者 :棟梁 D層自動生成ツール(墨壺), 日立 太郎 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//* 2012/06/14 西野 大介 ResourceLoaderに加え、EmbeddedResourceLoaderに対応 +//* 2013/09/09 西野 大介 ExecGenerateSQLメソッドを追加した(バッチ更新用)。 +//********************************************************************************** + +#region using + +// System~ +using System; +using System.IO; +using System.Data; +using System.Collections; + +// フレームワーク +using Touryo.Infrastructure.Framework.Dao; +using Touryo.Infrastructure.Framework.Common; + +// 部品 +using Touryo.Infrastructure.Public.Db; +using Touryo.Infrastructure.Public.Util; + +// 業務フレームワーク +using Touryo.Infrastructure.Business.Dao; + +#endregion + +/// 自動生成Daoクラス +public class DaoShippers : MyBaseDao +{ + #region インスタンス変数 + + /// ユーザ パラメタ(文字列置換)用ハッシュ テーブル + protected Hashtable HtUserParameter = new Hashtable(); + /// パラメタ ライズド クエリのパラメタ用ハッシュ テーブル + protected Hashtable HtParameter = new Hashtable(); + + #endregion + + #region コンストラクタ + + /// コンストラクタ + public DaoShippers(BaseDam dam) : base(dam) { } + + #endregion + + #region 共通関数(パラメタの制御) + + /// ユーザ パラメタ(文字列置換)をハッシュ テーブルに設定する。 + /// ユーザ パラメタ名 + /// ユーザ パラメタ値 + public void SetUserParameteToHt(string userParamName, string userParamValue) + { + // ユーザ パラメタをハッシュ テーブルに設定 + this.HtUserParameter[userParamName] = userParamValue; + } + + /// パラメタ ライズド クエリのパラメタをハッシュ テーブルに設定する。 + /// パラメタ名 + /// パラメタ値 + public void SetParameteToHt(string paramName, object paramValue) + { + // ユーザ パラメタをハッシュ テーブルに設定 + this.HtParameter[paramName] = paramValue; + } + + /// + /// ・ユーザ パラメタ(文字列置換) + /// ・パラメタ ライズド クエリのパラメタ + /// を格納するハッシュ テーブルをクリアする。 + /// + public void ClearParametersFromHt() + { + // ユーザ パラメタ(文字列置換)用ハッシュ テーブルを初期化 + this.HtUserParameter = new Hashtable(); + // パラメタ ライズド クエリのパラメタ用ハッシュ テーブルを初期化 + this.HtParameter = new Hashtable(); + } + + /// パラメタの設定(内部用) + protected void SetParametersFromHt() + { + // ユーザ パラメタ(文字列置換)を設定する。 + foreach (string userParamName in this.HtUserParameter.Keys) + { + this.SetUserParameter(userParamName, this.HtUserParameter[userParamName].ToString()); + } + + // パラメタ ライズド クエリのパラメタを設定する。 + foreach (string paramName in this.HtParameter.Keys) + { + this.SetParameter(paramName, this.HtParameter[paramName]); + } + } + + #endregion + + #region プロパティ プロシージャ(setter、getter) + + + /// ShipperID列(主キー列)に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタを除く + public object PK_ShipperID + { + set + { + this.HtParameter["ShipperID"] = value; + } + get + { + return this.HtParameter["ShipperID"]; + } + } + + + + /// CompanyName列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタを除く + public object CompanyName + { + set + { + this.HtParameter["CompanyName"] = value; + } + get + { + return this.HtParameter["CompanyName"]; + } + } + + /// Phone列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタを除く + public object Phone + { + set + { + this.HtParameter["Phone"] = value; + } + get + { + return this.HtParameter["Phone"]; + } + } + + + /// Set_ShipperID_forUPD列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタ専用 + public object Set_ShipperID_forUPD + { + set + { + this.HtParameter["Set_ShipperID_forUPD"] = value; + } + get + { + return this.HtParameter["Set_ShipperID_forUPD"]; + } + } + + + /// Set_CompanyName_forUPD列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタ専用 + public object Set_CompanyName_forUPD + { + set + { + this.HtParameter["Set_CompanyName_forUPD"] = value; + } + get + { + return this.HtParameter["Set_CompanyName_forUPD"]; + } + } + + + /// Set_Phone_forUPD列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 更新処理時のSET句で使用するパラメタ専用 + public object Set_Phone_forUPD + { + set + { + this.HtParameter["Set_Phone_forUPD"] = value; + } + get + { + return this.HtParameter["Set_Phone_forUPD"]; + } + } + + + + /// ShipperID_Like列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 動的参照処理時のLIKE検索で使用するパラメタ専用 + public object ShipperID_Like + { + set + { + this.HtParameter["ShipperID_Like"] = value; + } + get + { + return this.HtParameter["ShipperID_Like"]; + } + } + + + /// CompanyName_Like列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 動的参照処理時のLIKE検索で使用するパラメタ専用 + public object CompanyName_Like + { + set + { + this.HtParameter["CompanyName_Like"] = value; + } + get + { + return this.HtParameter["CompanyName_Like"]; + } + } + + + /// Phone_Like列に対するパラメタ ライズド クエリのパラメタを設定する。 + /// 動的参照処理時のLIKE検索で使用するパラメタ専用 + public object Phone_Like + { + set + { + this.HtParameter["Phone_Like"] = value; + } + get + { + return this.HtParameter["Phone_Like"]; + } + } + + + #endregion + + #region クエリ メソッド + + #region Insert + + /// 1レコード挿入する。 + /// 挿入された行の数 + public int S1_Insert() + { + // ファイルからSQL(Insert)を設定する。 + this.SetSqlByFile2("DaoShippers_S1_Insert.sql"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(Insert)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + /// 1レコード挿入する。 + /// 挿入された行の数 + /// パラメタで指定した列のみ挿入値が有効になる。 + public int D1_Insert() + { + // ファイルからSQL(DynIns)を設定する。 + this.SetSqlByFile2("DaoShippers_D1_Insert.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(DynIns)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + #endregion + + #region Select + + /// 主キーを指定し、1レコード参照する。 + /// 結果を格納するDataTable + public void S2_Select(DataTable dt) + { + // ファイルからSQL(Select)を設定する。 + this.SetSqlByFile2("DaoShippers_S2_Select.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(Select)を実行し、戻り値を戻す。 + this.ExecSelectFill_DT(dt); + } + + /// 検索条件を指定し、結果セットを参照する。 + /// 結果を格納するDataTable + public void D2_Select(DataTable dt) + { + // ファイルからSQL(DynSel)を設定する。 + this.SetSqlByFile2("DaoShippers_D2_Select.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(DynSel)を実行し、戻り値を戻す。 + this.ExecSelectFill_DT(dt); + } + + #endregion + + #region Update + + /// 主キーを指定し、1レコード更新する。 + /// 更新された行の数 + /// パラメタで指定した列のみ更新値が有効になる。 + public int S3_Update() + { + // ファイルからSQL(Update)を設定する。 + this.SetSqlByFile2("DaoShippers_S3_Update.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(Update)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + /// 任意の検索条件でデータを更新する。 + /// 更新された行の数 + /// パラメタで指定した列のみ更新値が有効になる。 + public int D3_Update() + { + // ファイルからSQL(DynUpd)を設定する。 + this.SetSqlByFile2("DaoShippers_D3_Update.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(DynUpd)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + #endregion + + #region Delete + + /// 主キーを指定し、1レコード削除する。 + /// 削除された行の数 + public int S4_Delete() + { + // ファイルからSQL(Delete)を設定する。 + this.SetSqlByFile2("DaoShippers_S4_Delete.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(Delete)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + /// 任意の検索条件でデータを削除する。 + /// 削除された行の数 + public int D4_Delete() + { + // ファイルからSQL(DynDel)を設定する。 + this.SetSqlByFile2("DaoShippers_D4_Delete.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(DynDel)を実行し、戻り値を戻す。 + return this.ExecInsUpDel_NonQuery(); + } + + #endregion + + #region 拡張メソッド + + /// テーブルのレコード件数を取得する + /// テーブルのレコード件数 + public object D5_SelCnt() + { + // ファイルからSQL(DynSelCnt)を設定する。 + this.SetSqlByFile2("DaoShippers_D5_SelCnt.xml"); + + // パラメタの設定 + this.SetParametersFromHt(); + + // SQL(SELECT COUNT)を実行し、戻り値を戻す。 + return this.ExecSelectScalar(); + } + + /// 静的SQLを生成する。 + /// ファイル名 + /// SQLユーティリティ + /// 生成した静的SQL + public string ExecGenerateSQL(string fileName, SQLUtility sqlUtil) + { + // ファイルからSQLを設定する。 + this.SetSqlByFile2(fileName); + + // パラメタの設定 + this.SetParametersFromHt(); + + return base.ExecGenerateSQL(sqlUtil); + } + + #endregion + + #endregion +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Dao/LayerD.cs b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Dao/LayerD.cs new file mode 100644 index 000000000..8646c06d9 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Dao/LayerD.cs @@ -0,0 +1,517 @@ +//********************************************************************************** +//* フレームワーク・テストクラス(D層) +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :LayerD +//* クラス日本語名 :D層のテスト +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +using SimpleBatch_sample.Common; + +using System.Data; + +using Touryo.Infrastructure.Business.Dao; +using Touryo.Infrastructure.Public.Db; + +namespace SimpleBatch_sample.Dao +{ + /// + /// LayerD の概要の説明です + /// + public class LayerD : MyBaseDao + { + /// + /// コンストラクタ + /// + public LayerD(BaseDam dam) : base(dam) { } + + #region テンプレ + + /// テンプレ + /// 引数クラス + /// 戻り値クラス + public void テンプレ(TestParameterValue testParameter, TestReturnValue testReturn) + { + + // ↓DBアクセス----------------------------------------------------- + + // ● 下記のいづれかの方法でSQLを設定する。 + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2("ファイル名"); + + // -- 直接指定する場合。 + this.SetSqlByCommand("SQL文"); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", testParameter.ShipperID); + + object obj; + + // -- 追加、更新、削除の場合(件数を確認できる) + obj = this.ExecInsUpDel_NonQuery(); + + // -- 先頭の1セル分の情報を返すSELECTクエリを実行する場合 + obj = this.ExecSelectScalar(); + + // -- テーブル(or レコード)の情報を返す + // SELECTクエリを実行する場合(引数 = データテーブル) + obj = new DataTable(); + this.ExecSelectFill_DT((DataTable)obj); + + // -- テーブル(or レコード)の情報を返す + // SELECTクエリを実行する場合(引数 = データセット) + obj = new DataSet(); + this.ExecSelectFill_DS((DataSet)obj); + + // -- データリーダを返す + IDataReader idr = (IDataReader)this.ExecSelect_DR(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #region 参照系 + + #region 件数取得(SelectCount) + + /// 件数情報を返すSELECTクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void SelectCount(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperCount.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperCount.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + object obj; + + // -- 件数情報を返すSELECTクエリを実行する + obj = this.ExecSelectScalar(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #region 一覧取得(SelectAll) + + /// 一覧を返すSELECTクエリを実行する(DT) + /// 引数クラス + /// 戻り値クラス + public void SelectAll_DT(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string commandText = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + commandText = "SELECT * FROM Shippers"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + commandText = + "SELECT * FROM Shippers"; + // 通常、動的SQLをSetSqlByCommandで直接指定するような使い方はしない。 + } + + // -- 直接指定する場合。 + this.SetSqlByCommand(commandText); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // -- 一覧を返すSELECTクエリを実行する + this.ExecSelectFill_DT(dt); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = dt; + } + + /// 一覧を返すSELECTクエリを実行する(DS) + /// 引数クラス + /// 戻り値クラス + public void SelectAll_DS(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string commandText = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + commandText = "SELECT * FROM Shippers"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + commandText = + "SELECT * FROM Shippers"; + // 通常、動的SQLをSetSqlByCommandで直接指定するような使い方はしない。 + } + + // -- 直接指定する場合。 + this.SetSqlByCommand(commandText); + + // 戻り値 ds + DataSet ds = new DataSet(); + + // -- 一覧を返すSELECTクエリを実行する + this.ExecSelectFill_DS(ds); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = ds; + } + + /// 一覧を返すSELECTクエリを実行する(DR) + /// 引数クラス + /// 戻り値クラス + public void SelectAll_DR(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string commandText = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + commandText = "SELECT * FROM Shippers"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + commandText = + "SELECT * FROM Shippers"; + // 通常、動的SQLをSetSqlByCommandで直接指定するような使い方はしない。 + } + + // -- 直接指定する場合。 + this.SetSqlByCommand(commandText); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // 3列生成 + dt.Columns.Add("c1", typeof(string)); + dt.Columns.Add("c2", typeof(string)); + dt.Columns.Add("c3", typeof(string)); + + // -- 一覧を返すSELECTクエリを実行する + IDataReader idr = (IDataReader)this.ExecSelect_DR(); + + while (idr.Read()) + { + // DRから読む + object[] objArray = new object[3]; + idr.GetValues(objArray); + + // DTに設定する。 + DataRow dr = dt.NewRow(); + dr.ItemArray = objArray; + dt.Rows.Add(dr); + } + + // 終了したらクローズ + idr.Close(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = dt; + } + + /// 一覧を返すSELECTクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void SelectAll_DSQL(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperSelectOrder.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperSelectOrder.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + // ユーザ定義パラメタに対して、動的に値を設定する。 + string orderColumn = ""; + string orderSequence = ""; + + if (testParameter.OrderColumn == "c1") + { + orderColumn = "ShipperID"; + } + else if (testParameter.OrderColumn == "c2") + { + orderColumn = "CompanyName"; + } + else if (testParameter.OrderColumn == "c3") + { + orderColumn = "Phone"; + } + else { } + + if (testParameter.OrderSequence == "A") + { + orderSequence = "ASC"; + } + else if (testParameter.OrderSequence == "D") + { + orderSequence = "DESC"; + } + else { } + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", "test"); + + // ユーザ入力は指定しない。 + // ※ 動的SQLのVALタグは、前後の空白をつめることが有るので、 + // 必要であれば、前後の空白を明示的に指定する必要がある。 + this.SetUserParameter("COLUMN", " " + orderColumn + " "); + this.SetUserParameter("SEQUENCE", " " + orderSequence + " "); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // -- 一覧を返すSELECTクエリを実行する + this.ExecSelectFill_DT(dt); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = dt; + } + + #endregion + + #region 参照 + + /// 1レコードを返すSELECTクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void Select(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperSelect.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperSelect.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", testParameter.ShipperID); + + // 戻り値 dt + DataTable dt = new DataTable(); + + // -- 1レコードを返すSELECTクエリを実行する + this.ExecSelectFill_DT(dt); + + // ↑DBアクセス----------------------------------------------------- + + //// 戻り値を設定 // 不要 + //testReturn.Obj = dt; + + // キャストの対策コードを挿入 + + // ・SQLの場合、ShipperIDのintがInt32型にマップされる。 + // ・ODPの場合、ShipperIDのNUMBERがInt64型にマップされる。 + // ・DB2の場合、ShipperIDのDECIMALがxxx型にマップされる。 + if (dt.Rows[0].ItemArray.GetValue(0).GetType().ToString() == "System.Int32") + { + // Int32なのでキャスト + testReturn.ShipperID = (int)dt.Rows[0].ItemArray.GetValue(0); + } + else + { + // それ以外の場合、一度、文字列に変換してInt32.Parseする。 + testReturn.ShipperID = int.Parse(dt.Rows[0].ItemArray.GetValue(0).ToString()); + } + + testReturn.CompanyName = (string)dt.Rows[0].ItemArray.GetValue(1); + testReturn.Phone = (string)dt.Rows[0].ItemArray.GetValue(2); + } + + #endregion + + #endregion + + #region 更新系 + + #region 追加 + + /// Insertクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void Insert(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2("ShipperInsert.sql"); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P2", testParameter.CompanyName); + this.SetParameter("P3", testParameter.Phone); + + object obj; + + // -- 追加(件数を確認できる) + obj = this.ExecInsUpDel_NonQuery(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #region 更新 + + /// Updateクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void Update(TestParameterValue testParameter, TestReturnValue testReturn) + { + + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperUpdate.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperUpdate.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", testParameter.ShipperID); + this.SetParameter("P2", testParameter.CompanyName); + this.SetParameter("P3", testParameter.Phone); + + object obj; + + // -- 更新(件数を確認できる) + obj = this.ExecInsUpDel_NonQuery(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #region 削除 + + /// Deleteクエリを実行する + /// 引数クラス + /// 戻り値クラス + public void Delete(TestParameterValue testParameter, TestReturnValue testReturn) + { + // ↓DBアクセス----------------------------------------------------- + + string filename = ""; + + if ((testParameter.ActionType.Split('%'))[2] == "static") + { + // 静的SQL + filename = "ShipperDelete.sql"; + } + else if ((testParameter.ActionType.Split('%'))[2] == "dynamic") + { + // 動的SQL + filename = "ShipperDelete.xml"; + } + + // -- ファイルから読み込む場合。 + this.SetSqlByFile2(filename); + + // パラメタ ライズド クエリのパラメタに対して、動的に値を設定する。 + this.SetParameter("P1", testParameter.ShipperID); + + object obj; + + // -- 削除(件数を確認できる) + obj = this.ExecInsUpDel_NonQuery(); + + // ↑DBアクセス----------------------------------------------------- + + // 戻り値を設定 + testReturn.Obj = obj; + } + + #endregion + + #endregion + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/MSGDefinition.xml b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/MSGDefinition.xml new file mode 100644 index 000000000..f2283b409 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/MSGDefinition.xml @@ -0,0 +1,23 @@ + + + + +]> + + + + + + + + + + + + + + + diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Program.cs b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Program.cs new file mode 100644 index 000000000..d970f08e3 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Program.cs @@ -0,0 +1,89 @@ +//********************************************************************************** +//* 単純バッチ処理・サンプル アプリ +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :Program +//* クラス日本語名 :サンプル バッチ +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +using SimpleBatch_sample.Business; +using SimpleBatch_sample.Common; + +using System; +using System.Collections.Generic; + +using Touryo.Infrastructure.Business.Util; +using Touryo.Infrastructure.Public.Db; +using Touryo.Infrastructure.Public.Str; +using Touryo.Infrastructure.Public.Util; + +namespace SimpleBatch_sample +{ + /// Program + class Program + { + /// Main + static void Main(string[] args) + { + //////////////////////////////////////////////////////////////////////// + // 簡素なサンプルなので、 + // ・多重化(タスク毎、結果セットを分割) + // ・フェッチ・サイズ(メモリ消費量を抑える) + // ・コミット・インターバル、リラン + // 等の考慮が別途必要になることがあります。 + //////////////////////////////////////////////////////////////////////// + + // コマンドラインをバラす関数がある。 + List valsLst = null; + Dictionary argsDic = null; + + StringVariableOperator.GetCommandArgs('/', out argsDic, out valsLst); + + // 引数クラスを生成 + // 下位(B・D層)は、テスト クラスを流用する + TestParameterValue testParameterValue + = new TestParameterValue( + System.Reflection.Assembly.GetExecutingAssembly().Location, "-", "SelectCount", + argsDic["/DAP"] + "%" + + argsDic["/MODE1"] + "%" + + argsDic["/MODE2"] + "%" + + argsDic["/EXROLLBACK"], + new MyUserInfo("", "")); + + // 戻り値 + TestReturnValue testReturnValue; + + // B層呼出し + LayerB layerB = new LayerB(); + testReturnValue = (TestReturnValue)layerB.DoBusinessLogic(testParameterValue, DbEnum.IsolationLevelEnum.ReadCommitted); + + if (testReturnValue.ErrorFlag == true) + { + // 結果(業務続行可能なエラー) + string error = "ErrorMessageID:" + testReturnValue.ErrorMessageID + "\r\n"; + error += "ErrorMessage:" + testReturnValue.ErrorMessage + "\r\n"; + error += "ErrorInfo:" + testReturnValue.ErrorInfo + "\r\n"; + + Console.WriteLine(error); + Console.ReadKey(); + } + else + { + // 結果(正常系) + Console.WriteLine(testReturnValue.Obj.ToString() + "件のデータがあります"); + Console.ReadKey(); + } + } + } +} diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Properties/AssemblyInfo.cs b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..3abb0315b --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/Properties/AssemblyInfo.cs @@ -0,0 +1,51 @@ +//********************************************************************************** +//* 単純バッチ処理・サンプル アプリ +//********************************************************************************** + +// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。 + +//********************************************************************************** +//* クラス名 :AssemblyInfo +//* クラス日本語名 :AssemblyInfo設定 +//* +//* 作成日時 :- +//* 作成者 :生技 +//* 更新履歴 : +//* +//* 日時 更新者 内容 +//* ---------- ---------------- ------------------------------------------------- +//* 20xx/xx/xx XX XX XXXX +//********************************************************************************** + +using System.Reflection; +using System.Runtime.InteropServices; + +// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 +// アセンブリに関連付けられている情報を変更するには、 +// これらの属性値を変更してください。 +[assembly: AssemblyTitle("SimpleBatch_sample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("xxxx")] +[assembly: AssemblyProduct("SimpleBatch_sample")] +[assembly: AssemblyCopyright("Copyright (C) xxxx")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントには +// 参照不可能になります。COM からこのアセンブリ内の型にアクセスする場合は、 +// その型の ComVisible 属性を true に設定してください。 +[assembly: ComVisible(false)] + +// 次の GUID は、このプロジェクトが COM に公開される場合の、typelib の ID です +[assembly: Guid("f333aecb-bd73-4b3a-87f5-deaef035efa3")] + +// アセンブリのバージョン情報は、以下の 4 つの値で構成されています: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SPDefinition.xml b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SPDefinition.xml new file mode 100644 index 000000000..6baf634bc --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SPDefinition.xml @@ -0,0 +1,15 @@ + + + + +]> + + + + + + + diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SampleLogConf2CS.xml b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SampleLogConf2CS.xml new file mode 100644 index 000000000..476cea7c5 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SampleLogConf2CS.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SimpleBatch_sample.csproj b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SimpleBatch_sample.csproj new file mode 100644 index 000000000..e3d3285a8 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SimpleBatch_sample.csproj @@ -0,0 +1,158 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {D4941E87-FCE4-4102-B569-C17208AE13CF} + Exe + Properties + SimpleBatch_sample + SimpleBatch_sample + v4.8 + + + 2.0 + + + http://localhost/SimpleBatch_sample/ + true + Web + true + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + true + false + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + ..\..\..\..\..\Frameworks\Infrastructure\Build_net48\OpenTouryo.Business.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + Always + + + + + 1.46.2 + + + 1.14.0 + + + 9.0.6 + + + 6.0.2 + + + 9.0.6 + + + 4.72.1 + + + 8.12.0 + + + 4.6.3 + + + 9.0.6 + + + 6.0.1 + + + 9.0.6 + + + 9.0.6 + + + 4.6.3 + + + 4.6.1 + + + 3.3.0-alpha1 + + + 3.3.0-alpha1 + + + 3.3.0-alpha1 + + + + + \ No newline at end of file diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SimpleBatch_sample.sln b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SimpleBatch_sample.sln new file mode 100644 index 000000000..42d809b8d --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/SimpleBatch_sample.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11205.157 d18.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleBatch_sample", "SimpleBatch_sample.csproj", "{D4941E87-FCE4-4102-B569-C17208AE13CF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D4941E87-FCE4-4102-B569-C17208AE13CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4941E87-FCE4-4102-B569-C17208AE13CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4941E87-FCE4-4102-B569-C17208AE13CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4941E87-FCE4-4102-B569-C17208AE13CF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {6CAF0726-7971-4F3E-8DE8-DD42AF2BD736} + EndGlobalSection +EndGlobal diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/app.config b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/app.config new file mode 100644 index 000000000..1aadc4ed0 --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/app.config @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/readme.txt b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/readme.txt new file mode 100644 index 000000000..c501c1efb --- /dev/null +++ b/root/programs/CS/NuGet/proj/pdtn/net48/SimpleBatch_sample/readme.txt @@ -0,0 +1,4 @@ +以下の様なコマンドライン引数をプロジェクトのプロパティの +デバッグ → 開始オプション → コマンドライン引数から設定して下さい。 + +/Dap SQL /Mode1 individual /Mode2 static /EXROLLBACK - \ No newline at end of file diff --git a/root/programs/CS/NuGet/proj/test/net10.0/ConsoleApp1/ConsoleApp1.csproj b/root/programs/CS/NuGet/proj/test/net10.0/ConsoleApp1/ConsoleApp1.csproj new file mode 100644 index 000000000..ec7b8e346 --- /dev/null +++ b/root/programs/CS/NuGet/proj/test/net10.0/ConsoleApp1/ConsoleApp1.csproj @@ -0,0 +1,14 @@ + + + + Exe + net10.0 + enable + enable + + + + + + + diff --git a/root/programs/CS/NuGet/proj/test/net10.0/ConsoleApp1/ConsoleApp1.slnx b/root/programs/CS/NuGet/proj/test/net10.0/ConsoleApp1/ConsoleApp1.slnx new file mode 100644 index 000000000..7a2300a12 --- /dev/null +++ b/root/programs/CS/NuGet/proj/test/net10.0/ConsoleApp1/ConsoleApp1.slnx @@ -0,0 +1,3 @@ + + + diff --git a/root/programs/CS/NuGet/proj/test/net10.0/ConsoleApp1/Program.cs b/root/programs/CS/NuGet/proj/test/net10.0/ConsoleApp1/Program.cs new file mode 100644 index 000000000..dcf810c5a --- /dev/null +++ b/root/programs/CS/NuGet/proj/test/net10.0/ConsoleApp1/Program.cs @@ -0,0 +1,4 @@ +using Touryo.Infrastructure.Public.Str; + +Console.WriteLine(StringConverter.ToZenkaku("abc")); +Console.WriteLine("Hello, World!"); diff --git a/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/App.config b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/App.config new file mode 100644 index 000000000..f7a3e566f --- /dev/null +++ b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/App.config @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/ConsoleApp1.csproj b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/ConsoleApp1.csproj new file mode 100644 index 000000000..8ce7668c3 --- /dev/null +++ b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/ConsoleApp1.csproj @@ -0,0 +1,189 @@ + + + + + Debug + AnyCPU + {E87BE501-0556-4F9F-893F-FDB53FA1CA77} + Exe + ConsoleApp1 + ConsoleApp1 + v4.8 + 512 + true + true + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + packages\Azure.Core.1.38.0\lib\net472\Azure.Core.dll + + + packages\Azure.Identity.1.11.4\lib\netstandard2.0\Azure.Identity.dll + + + packages\log4net.3.3.0\lib\net462\log4net.dll + + + packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + + + packages\Microsoft.Bcl.Cryptography.8.0.0\lib\net462\Microsoft.Bcl.Cryptography.dll + + + packages\Microsoft.Data.SqlClient.6.0.2\lib\net462\Microsoft.Data.SqlClient.dll + + + packages\Microsoft.Extensions.Caching.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.Caching.Abstractions.dll + + + packages\Microsoft.Extensions.Caching.Memory.8.0.1\lib\net462\Microsoft.Extensions.Caching.Memory.dll + + + packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + packages\Microsoft.Extensions.Logging.Abstractions.8.0.2\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll + + + packages\Microsoft.Extensions.Options.8.0.2\lib\net462\Microsoft.Extensions.Options.dll + + + packages\Microsoft.Extensions.Primitives.8.0.0\lib\net462\Microsoft.Extensions.Primitives.dll + + + packages\Microsoft.Identity.Client.4.61.3\lib\net462\Microsoft.Identity.Client.dll + + + packages\Microsoft.Identity.Client.Extensions.Msal.4.61.3\lib\netstandard2.0\Microsoft.Identity.Client.Extensions.Msal.dll + + + packages\Microsoft.IdentityModel.Abstractions.7.5.0\lib\net472\Microsoft.IdentityModel.Abstractions.dll + + + packages\Microsoft.IdentityModel.JsonWebTokens.7.5.0\lib\net472\Microsoft.IdentityModel.JsonWebTokens.dll + + + packages\Microsoft.IdentityModel.Logging.7.5.0\lib\net472\Microsoft.IdentityModel.Logging.dll + + + packages\Microsoft.IdentityModel.Protocols.7.5.0\lib\net472\Microsoft.IdentityModel.Protocols.dll + + + packages\Microsoft.IdentityModel.Protocols.OpenIdConnect.7.5.0\lib\net472\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll + + + packages\Microsoft.IdentityModel.Tokens.7.5.0\lib\net472\Microsoft.IdentityModel.Tokens.dll + + + packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + packages\NLog.5.5.0\lib\net46\NLog.dll + + + packages\Erutcurtsarfni.Oyruot.Public.3.3.0-alpha1\lib\net48\OpenTouryo.Public.dll + + + + packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + packages\System.ClientModel.1.0.0\lib\netstandard2.0\System.ClientModel.dll + + + + + + packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll + + + + + packages\System.IdentityModel.Tokens.Jwt.7.5.0\lib\net472\System.IdentityModel.Tokens.Jwt.dll + + + + packages\System.IO.FileSystem.AccessControl.5.0.0\lib\net461\System.IO.FileSystem.AccessControl.dll + + + packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + packages\System.Memory.Data.1.0.2\lib\net461\System.Memory.Data.dll + + + + packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + + packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll + + + packages\System.Security.Cryptography.Pkcs.8.0.1\lib\net462\System.Security.Cryptography.Pkcs.dll + + + packages\System.Security.Cryptography.ProtectedData.4.7.0\lib\net461\System.Security.Cryptography.ProtectedData.dll + + + packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll + + + packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll + + + packages\System.Text.Json.6.0.10\lib\net461\System.Text.Json.dll + + + packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + + + + + + + + + + + + + + + + + + + + 3.3.0-alpha2 + + + + \ No newline at end of file diff --git a/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/ConsoleApp1.slnx b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/ConsoleApp1.slnx new file mode 100644 index 000000000..911a754e4 --- /dev/null +++ b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/ConsoleApp1.slnx @@ -0,0 +1,3 @@ + + + diff --git a/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/Program.cs b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/Program.cs new file mode 100644 index 000000000..bd9aabc24 --- /dev/null +++ b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/Program.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Touryo.Infrastructure.Public.Str; + +namespace ConsoleApp1 +{ + internal class Program + { + static void Main(string[] args) + { + Console.WriteLine(StringConverter.ToZenkaku("abc")); + } + } +} diff --git a/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/Properties/AssemblyInfo.cs b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..8f305ed0d --- /dev/null +++ b/root/programs/CS/NuGet/proj/test/net48/ConsoleApp1/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// アセンブリに関する一般的な情報は、次の方法で制御されます。 +// 制御されます。アセンブリに関連付けられている情報を変更するには、 +// これらの属性値を変更します。 +[assembly: AssemblyTitle("ConsoleApp1")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ConsoleApp1")] +[assembly: AssemblyCopyright("Copyright © 2026")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから +// 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 +// その型の ComVisible 属性を true に設定します。 +[assembly: ComVisible(false)] + +// このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります +[assembly: Guid("e87be501-0556-4f9f-893f-fdb53fa1ca77")] + +// アセンブリのバージョン情報は次の 4 つの値で構成されています: +// +// メジャー バージョン +// マイナー バージョン +// ビルド番号 +// リビジョン +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/root/programs/CS/NuGet/symbol_template.nuspec b/root/programs/CS/NuGet/symbol_template.nuspec index d5eb317d2..af7e8f907 100644 --- a/root/programs/CS/NuGet/symbol_template.nuspec +++ b/root/programs/CS/NuGet/symbol_template.nuspec @@ -1,4 +1,4 @@ - + [名前空間(Touryo.Infrastructure.xxxx)]★ @@ -15,10 +15,17 @@ https://github.com/OpenTouryoProject/OpenTouryo/releases OpenTouryo Open棟梁 + + + + + @@ -27,6 +34,10 @@ + + + + \ No newline at end of file diff --git a/root/programs/CS/Samples/ANALYSIS.md b/root/programs/CS/Samples/ANALYSIS.md new file mode 100644 index 000000000..db6d3112d --- /dev/null +++ b/root/programs/CS/Samples/ANALYSIS.md @@ -0,0 +1,375 @@ +# ANALYSIS.md — Open棟梁 サンプル アプリ(CS/Samples)コード分析 + +対象: `root/programs/CS/Samples`(**.NET Framework 4.8 専用**) / ブランチ: `develop` +最終更新: 2026-07-31 + +本書は **コーディング・エージェントが本ディレクトリで作業する際の Context** を目的とする。 +フレームワーク本体の分析は `../Frameworks/ANALYSIS.md` を、 +.NET (Core) 版サンプルは `../Samples4NetCore/ANALYSIS.md` を参照。 + +--- + +## 1. これは何か + +Open棟梁フレームワークの **使い方を示すサンプル兼テンプレート**。 +実務では「該当するサンプルをコピーして中身を書き換える」のが標準的な使い方であり、 +コード中に **`// テスト用サンプルなので、必要に応じて流用 or 削除して下さい。`** という +断り書きが全ファイルに入っている。つまり **これらは「消して良い雛形」として書かれている**。 + +同時に **フレームワークの動作確認(テストベッド)** も兼ねており、 +特に `WebForms_Sample` は P層機能(画面遷移制御・二重送信検出・ダイアログ等)の網羅テストになっている。 + +**全プロジェクトが `net48`(旧形式 csproj)。** SDK 形式は 1 つもない。 + +--- + +## 2. 前提条件(これを満たさないと動かない) + +### 2-1. リポジトリを `C:\root\` に配置する + +**サンプルの設定ファイルは `C:\root\files\resource\...` という絶対パスを直書きしている。** + +```xml + + +``` + +`root/Readme.ja.md` の手順どおり、リポジトリの `root` 配下を `C:\root\` に展開する必要がある。 +本リポジトリのチェックアウト先が `C:\OpenTouryo\root\` の場合、**`C:\root\files` を別途用意しないと +実行時に定義ファイルが見つからず落ちる**(ビルドは通る)。 + +> 補足: 分析時点のこの環境には `C:\root\files\` が存在し、`Log / MultiPurposeAuthSite / Sql / Test / X509 / Xml` が配置済み。 + +### 2-2. データベース + +- **SQL Server の Northwind データベース**が既定(`app.config` の `ConnectionString_SQL`)。 +- `Bat_sample/RerunnableBatch_sample*` は追加で **`ORDERS2` テーブル**が必要 + (各 `readme.txt` 記載。`CREATE ORDERS2.sql` を実行し、実行の都度 `DELETE FROM ORDERS2`)。 +- SQL Server 以外は `C:\root\files\resource\Sql\[DBMS名]\TestTable.txt` でテスト表を作成。 +- 接続文字列は `localhost` / `sa` / `seigi@123` 等の **サンプル値**がリポジトリに直書きされている + (公開 OSS のサンプル設定であり実資格情報ではない。流用時は必ず差し替える)。 + +### 2-3. フレームワークを先にビルドしておく + +**全サンプルが `Frameworks\Infrastructure\Build\` の DLL を `HintPath` で参照する。** + +```xml +..\..\..\Frameworks\Infrastructure\Build\OpenTouryo.Business.dll +``` + +`Build\` は `4_Build_CopyAssemblies.bat`(`Build_net48` → `Build\` を xcopy)が作るディレクトリ。 +したがって **ビルド順は厳守**: + +``` +2_Build_NuGet_net48.bat → Public / Framework / Public.Security / Dam* +3_Build_Business_net48.bat → Business +4_Build_CopyAssemblies.bat → Build_net48 を Build\ へコピー ★これを飛ばすと全滅 +5〜10_Build_*_sample.bat → 各サンプル +``` + +CS/VB 合わせて **42 プロジェクト**がこの `Build\` を参照している。 + +--- + +## 3. サンプル一覧 + +| ディレクトリ | 種別 | 概要 | +|---|---|---| +| `2CS_sample/2CSClientWin_sample` | WinForms | **2層C/S の基本形**。Splash → Login → Form1 | +| `2CS_sample/2CSClientWPF_sample` | WPF | 同上の WPF 版 | +| `2CS_sample/GenDaoAndBatUpd_sample` | WinForms | **自動生成Dao(DaoGen_Tool 出力)とバッチ更新**の利用例 | +| `2CS_sample/TimeStamp_sample` | WinForms | **タイムスタンプ(楽観排他)対応**の自動生成Dao | +| `2CS_sample/CustCtrl_sample` | WinForms | **カスタム コントロール**(`WinCustomTextBox` 等)のデザインタイム プロパティ検証。`Readme.txt` が事実上の仕様書 | +| `2CS_sample/AsyncEvent_sample` | WinForms/WPF | **非同期イベント処理**。`test-winx2&wpfx2.bat` で 4 プロセス起動 | +| `Bat_sample/SimpleBatch_sample` | コンソール | **バッチの最小形**。オンライン処理と同じ流儀 | +| `Bat_sample/RerunnableBatch_sample` | コンソール | リラン可能バッチ。通常のデータアクセス | +| `Bat_sample/RerunnableBatch_sample2` | コンソール | `SQLUtility` + `ExecGenerateSQL` でラウンドトリップ削減 | +| `Bat_sample/RerunnableBatch_sample3` | コンソール | `SQLUtility` で DataTable から Insert 文生成(**静的SQLのみ**) | +| `WS_sample/WSServer_sample` | Library | **サービス側の B/D 層**。ServiceInterface からレイトバインドされる | +| `WS_sample/WSIFType_sample` | Library | WS の I/F 型(引数・戻り値クラス)を**サーバ/クライアント共有**するためのアセンブリ | +| `WS_sample/WSClient_sample/*` | WinForms/WPF | **3層型クライアント**。`CallController` 経由で B層を呼ぶ(4 種) | +| `WS_sample/ASPNETWebService` | — | **README のみ**。実体は別リポジトリ `ResourceServerTemplates` へ移動済み | +| `WebApp_sample/WebForms_Sample` | ASP.NET Web Forms | **最大のサンプル(.aspx 38 画面)**。P層機能の網羅テスト | +| `WebApp_sample/MVC_Sample` | ASP.NET MVC5 | MVC5 + WebAPI 版 | +| `CLI_sample/*` | — | **README のみ(3 件)**。net48 版はドロップ済み(後述) | + +### 存在しないもの / 移動したもの + +- **`CLI_sample` の実体は無い。** `Simple_CLI` は Sharprompt が .NET Framework サポートを終了したため net48 版をドロップ。 + `DAG_Login_CLI` / `LIR_Login_CLI` は `System.CommandLine` の beta 解除待ちで移植保留。 + → **実装は `../Samples4NetCore/Legacy/CLI_sample/` にのみ存在する。** +- **`WS_sample/ASPNETWebService`** は `OpenTouryoProject/ResourceServerTemplates` へ移動。 + +--- + +## 4. 標準的なプロジェクト構成(この形をコピーする) + +``` +XXX_sample/ +├─ Business/LayerB.cs … B層(MyFcBaseLogic 継承、UOC_ メソッド群) +├─ Common/TestParameterValue.cs … 引数クラス(MyParameterValue 継承) +├─ Common/TestReturnValue.cs … 戻り値クラス(MyReturnValue 継承) +├─ Dao/LayerD.cs … D層(MyBaseDao 継承、個別Dao) +├─ Dao/DaoShippers.cs … D層(DaoGen_Tool が生成した自動生成Dao) +├─ Program.cs / Form1.cs … P層(エントリポイント) +├─ MSGDefinition.xml … メッセージ定義 +├─ SPDefinition.xml … 共有プロパティ定義 +├─ SampleLogConf2CS.xml … log4net 設定 +├─ app.config … 接続文字列 + appSettings +└─ readme.txt … 実行方法(コマンドライン引数など) +``` + +WS 系はこれに `TMProtocolDefinition.xml` / `TMInProcessDefinition.xml` が加わる。 +Web 系は `Logic/{Business,Common,Dao}` または `AppCode/sample/{Business,Common,Dao}` に入る。 + +--- + +## 5. 呼び出しパターン + +### 5-1. インプロセス(2層C/S・バッチ・Web) + +```csharp +// P層 +TestParameterValue p = new TestParameterValue( + screenId, controlId, "SelectCount", // ← methodName が UOC_ 振り分けキー + "SQL%individual%static%-", // ← ActionType(後述) + new MyUserInfo("", "")); + +LayerB layerB = new LayerB(); +TestReturnValue r = (TestReturnValue)layerB.DoBusinessLogic(p, DbEnum.IsolationLevelEnum.ReadCommitted); + +if (r.ErrorFlag) { /* 業務例外:ErrorMessageID / ErrorMessage / ErrorInfo */ } +else { /* 正常系:r.Obj など */ } +``` + +### 5-2. サービス呼び出し(WS クライアント) + +```csharp +CallController cc = new CallController(context); +object ret = cc.Invoke("testInProcess", parameterValue); // 論理名で解決 +``` + +論理名 → プロトコル は `TMProtocolDefinition.xml`、 +論理名 → assembly/class は `TMInProcessDefinition.xml` で解決される。 + +`WSClientWPF_sample/TMProtocolDefinition.xml` の実例: + +| id | protocol | 意味 | +|---|---|---| +| `testInProcess` | 1 | インプロセス | +| `testWebService` | 2 | ASP.NET Web サービス (asmx) ※コメントアウト | +| `testWebService2` | 3 | WCF-HTTP ※コメントアウト | +| `testWebService3` | 4 | WCF-TCP (`net.tcp://localhost:7777/...`) | +| `testWebService4` | 5 | ASP.NET WebAPI (JSON-RPC) | + +`_` 始まりの id(`_testWebService` 等)は `url_ref` / `prop_ref` でマスタ データを参照する記法の例。 + +--- + +## 6. `ActionType` の規約(サンプル横断のローカル ルール) + +`%` 区切りの 4 要素。**フレームワークが解釈するのは [0] のみ**で、[1] 以降はサンプル独自。 + +| 位置 | 意味 | 値 | +|---|---|---| +| `[0]` | **データ プロバイダ選択**(フレームワークが解釈) | `SQL` `OLE` `ODB` `ODP` `MCN` `NPS` `DB2` `HIR` | +| `[1]` | Dao の種類(サンプル独自) | `common`(`CmnDao`) / `generate`(自動生成Dao) / それ以外(個別 `LayerD`) | +| `[2]` | SQL の種類(サンプル独自) | `static`(`.sql`) / `dynamic`(`.xml` = DPQ) | +| `[3]` | ロールバック試験(サンプル独自) | `Business`(業務例外) / `System`(システム例外) / `-`(正常) | + +バッチのコマンドライン例(`SimpleBatch_sample/readme.txt`): + +``` +/Dap SQL /Mode1 individual /Mode2 static /EXROLLBACK - +``` + +`StringVariableOperator.GetCommandArgs('/', out argsDic, out valsLst)` で分解し、 +**キーは大文字化されて `argsDic["/DAP"]` のように引かれる**点に注意。 + +--- + +## 7. 設定ファイル + +### 7-1. コンソール / WinForms / WPF — `app.config` + +`appSettings` に `Fx*` キー、`connectionStrings` に `ConnectionString_{SQL,OLE,ODBC,ODP,MCN}`。 +`` に **大量の `bindingRedirect`** が入っている(net48 の宿命)。 +NuGet パッケージを更新すると、ここも追随が必要。 + +### 7-2. Web — `Web.config` + `app.config` + +`WebForms_Sample` は `` で **appSettings を外部ファイルに分離**している。 +`Fx*` キーの実体は `app.config` 側にあるので、**設定を探すときは `Web.config` ではなく `app.config` を見る**。 + +P層(Web Forms)専用の設定群: + +| 種別 | キー | +|---|---| +| コントロール接頭辞 | `FxPrefixOfButton`=btn, `FxPrefixOfTextBox`=txt, `FxPrefixOfGridView`=gvw … 全 13 種 | +| 基盤画面パス | `FxErrorScreenPath` `FxOKMessageDialogPath` `FxYesNoMessageDialogPath` `FxDialogFramePath` | +| アイコン | `FxInformationIconPath` `FxWarningIconPath` `FxErrorIconPath` `FxQuestionIconPath` | +| ダイアログ既定スタイル | `FxDefaultFxDialogStyle` `FxDefaultBusinessDialogStyle` `FxDefaultNormalScreenStyle` | +| 画面制御 | `FxSessionTimeOutCheck` `FxDoubleTransmissionCheck` `FxScreenTransitionMode` `FxScreenTransitionCheck` | +| キュー長 | `FxRequestTicketGuidMaxQueueLength` `FxButtonhistoryMaxQueueLength` `FxScreeenGuidMaxQueueLength` `FxWindowGuidMaxQueueLength` | +| XML 定義 | `FxXMLSPDefinition` `FxXMLMSGDefinition` `FxXMLSCDefinition` `FxXMLTCDefinition` `FxXMLTMProtocolDefinition` `FxXMLTMInProcessDefinition` | +| `_3TierEngine` 命名規約 | `DaoClassNameHeader`=Dao, `MethodNameHeaderS`=S, `MethodNameHeaderD`=D, `MethodLabel_Ins`=1_Insert … `UpdateParamHeader`=Set_, `LikeParamFooter`=_Like | + +**`_3TierEngine` の命名規約キーは自動生成Daoのメソッド名(`S1_Insert` / `D2_Select` / `D5_SelCnt`)と直結**しており、 +片方だけ変えると実行時に解決できなくなる。 + +### 7-3. `Fx*` キーは大文字小文字を区別しない + +`MyBaseDao.SetSqlByFile2` は内部で `GetConfigValue("sqlTextFilePath")`(小文字 s)を引くが、 +`app.config` の定義は `SqlTextFilePath`(大文字 S)。 +.NET Framework の `appSettings` も `Microsoft.Extensions.Configuration` も**キー比較は大文字小文字を無視する**ため +動作するが、意図的な一致ではないので、**このキー名を「揃える」目的で書き換えない**こと。 + +--- + +## 8. ビルドと実行 + +### ビルド + +`root/programs/CS/` 直下の bat(`z_Common.bat` が MSBuild を解決)。 + +| bat | 対象 | +|---|---| +| `5_Build_2CS_sample.bat` | `2CS_sample/*` | +| `5_Build_Bat_sample.bat` | `Bat_sample/*`(4 sln を順次) | +| `5_Build_CLI_sample.bat` | `CLI_sample`(実体が無いので実質 no-op) | +| `6_Build_WSSrv_sample.bat` | `WSServer_sample` → `WS_sample/Temp` → `WS_sample/Build` へ xcopy | +| `7_Build_Framework_WS.bat` | `ServiceInterface`。`WS_sample/Build` を `WCFService/dll` へコピーしてからビルド | +| `8_Build_WSClnt_sample.bat` | `WSClient_sample/*`(4 sln) | +| `10_Build_WebApp_sample.bat` | `WebForms_Sample` → `MVC_Sample` | + +**`WS_sample/Build/` は成果物置き場**であり、`7_Build_Framework_WS.bat` が +`ServiceInterface/WCFService/dll/` へ流し込む中継点になっている(`.gitignore` 済み)。 + +Web 系は `packages.config` 方式(NuGet classic)なので、**`nuget.exe restore` が必須** +(各 bat が `..\nuget.exe restore` を実行している)。 + +### 実行 + +- バッチ: プロジェクトのプロパティ → デバッグ → コマンドライン引数に `readme.txt` の文字列を設定。 +- `AsyncEvent_sample`: sln をビルド後 `test-winx2&wpfx2.bat` から 4 プロセス起動。 +- `WebForms_Sample`: `sessionState mode="StateServer"` 既定 → **ASP.NET 状態サービスの起動が必要** + (`C:\root\files\bat\aspnet_state-stat.bat`)。 +- WS クライアント: 先に `WSServer_sample` と `ServiceInterface`(WCF/WebAPI ホスト)を起動。 + +--- + +## 9. 個別サンプルの読みどころ + +### `Bat_sample/SimpleBatch_sample` — まずここを読む + +B層(`LayerB.UOC_SelectCount` 等)が **`CmnDao` / 自動生成Dao / 個別Dao の 3 経路**を +`switch` で切り替える形になっており、Open棟梁のデータアクセス手段が 1 ファイルで俯瞰できる。 + +```csharp +switch ((testParameter.ActionType.Split('%'))[1]) +{ + case "common": CmnDao cmnDao = new CmnDao(this.GetDam()); + cmnDao.SQLFileName = "ShipperCount.sql"; // or .xml (DPQ) + testReturn.Obj = cmnDao.ExecSelectScalar(); break; + case "generate": DaoShippers genDao = new DaoShippers(this.GetDam()); + testReturn.Obj = genDao.D5_SelCnt(); break; + default: LayerD myDao = new LayerD(this.GetDam()); + myDao.SelectCount(testParameter, testReturn); break; +} +``` + +### `Dao/LayerD.cs` の `テンプレ()` メソッド + +**日本語のメソッド名「テンプレ」**が各サンプルの `LayerD` に入っており、 +`SetSqlByFile2` / `SetSqlByCommand` / `SetParameter` / `ExecXxx` の全パターンが +コメント付きで並んでいる。**D層を書くときのチートシート**として機能する。 +実運用コードにコピーする際は削除する前提。 + +### `Dao/DaoShippers.cs` — DaoGen_Tool の出力形 + +ヘッダに `作成者:棟梁 D層自動生成ツール(墨壺)` と入る。メソッド命名は +`S1_Insert` `D1_Insert` `S2_Select` `D2_Select` `S3_Update` `D3_Update` `S4_Delete` `D4_Delete` `D5_SelCnt` +(`S`=静的SQL、`D`=動的SQL(DPQ)、番号は `MethodLabel_*` 設定に対応)。 +**手で編集せず、ツールで再生成する**のが本来の運用。 + +### `WebForms_Sample` — P層機能のテストベッド + +`Aspx/` 配下の内訳: + +| ディレクトリ | .aspx 数 | 内容 | +|---|---|---| +| `testFxLayerP/` | 19 | **P層機能の網羅テスト**(最重要) | +| `testScreenCtrl/` | 6 | 画面遷移制御 | +| `sample/` | 5 | 業務サンプル | +| `start/` | 3 | ログイン・メニュー | +| `Framework/` | 3 | ダイアログ等の基盤画面 | +| `OAuth2/` | 1 | OAuth2 連携 | +| `Common/` | 1 | エラー画面 | + +`AppCode/testPublic/Business/TestMTC*.cs` はマルチ トランザクション制御の検証コード。 +`Aspx/Common/Master/testNest/` にはマスタ ページ多重ネストの検証が入っている。 + +### `Bat_sample/RerunnableBatch_sample{,2,3}` — 性能モデル 3 種 + +| | 手法 | 動的SQL | +|---|---|---| +| 無印 | 通常のデータアクセス(`S1_Insert` / `D1_Insert` を切替) | 可 | +| `2` | `SQLUtility` + `ExecGenerateSQL` でラウンドトリップ削減 | 可 | +| `3` | `SQLUtility` で DataTable から Insert 文を生成 | **不可(静的のみ)** | + +--- + +## 10. 落とし穴 + +1. **`4_Build_CopyAssemblies.bat` を飛ばすと全サンプルがビルドできない。** + `Build\`(`Build_net48` のコピー)を `HintPath` 参照しているため。 +2. **`C:\root\files\...` の絶対パス依存。** チェックアウト先が `C:\root` 以外だと実行時に落ちる。 + IDE から F5 する前に `C:\root\files` の存在を確認すること。 +3. **`net48` のみ。** .NET (Core) 版は `../Samples4NetCore/Legacy/` にある**別コピー**。 + B層・D層のソースは**ほぼ同一だが独立管理**(4-2 参照)→ **片方を直したらもう片方も直す**。 +4. **`ReturnValue` を設定し忘れると戻り値が null。** `UOC_` メソッドの冒頭で必ず + `this.ReturnValue = testReturn;` する(フレームワーク側の仕様。`../Frameworks/ANALYSIS.md` 3.2 節)。 +5. **`app.config` の `bindingRedirect` が大量**。NuGet 更新時は追随が必要。 +6. **`WebForms_Sample` / `MVC_Sample` は `packages.config` 方式**。`PackageReference` 移行はされていない。 + `nuget.exe restore` を忘れるとビルドが落ちる。 +7. **`CLI_sample` にコードは無い**(README のみ)。実装を探すなら `../Samples4NetCore/Legacy/CLI_sample/`。 +8. **`WS_sample/Build/` `WS_sample/Temp/` はビルド生成物**。コミット対象ではない(`Build/` は `.gitignore` 済み)。 +9. **`_3TierEngine` の命名規約キーと自動生成Daoのメソッド名は連動**。片方だけ変えない(7-2 参照)。 +10. **VB 版ミラーが存在**(`root/programs/VB/Samples/`)。構成はほぼ 1:1 対応。 + +--- + +## 11. `Samples` と `Samples4NetCore/Legacy` の関係 + +`Samples4NetCore/Legacy/` は `Samples/` を **.NET (Core) 向けに移植した独立コピー**。 +`Compile Include` によるファイル共有は**していない**(リンク参照ゼロ)。 + +実測した差分: + +| サンプル群 | 同一ファイル | 差異あり | `Samples` 側のみ | +|---|---|---|---| +| `2CS_sample` | 138 | 18 | 26 | +| `Bat_sample` | 73 | 14 | 8 | +| `WS_sample` | 65 | 14 | 36 | + +- **`Business/LayerB.cs` や `Dao/*.cs` は多くがバイト単位で同一。** +- 差異があるのは主に `*.csproj` / `*.sln` / `Program.cs`(Core 側は `GetConfigParameter.InitConfiguration()` 呼び出しが増える)。 +- `Samples` 側のみ = `app.config`(Core は `appsettings.json`)、`Properties/AssemblyInfo.cs`(SDK 形式では自動生成)、 + および未移植の `AsyncEvent_sample` / `WSClientWinCone_sample`。 + +→ **B層・D層のロジックを修正したら、`Samples4NetCore/Legacy/` 側の同名ファイルも同じ修正が必要。** + +--- + +## 12. エージェント向け作業チェックリスト + +- [ ] `AGENTS.md` のポリシー遵守(**git 操作をしない**) +- [ ] 変更が `Samples4NetCore/Legacy/` 側にも必要か判定(11 節) +- [ ] `Frameworks` を先にビルド → `4_Build_CopyAssemblies.bat` を実行(`Build\` を作る) +- [ ] Web 系を触るなら `nuget.exe restore`(`packages.config` 方式) +- [ ] 新規 .cs にはヘッダ コメント(Apache License / クラス名・日本語名・更新履歴)を付与、既存変更時は履歴に 1 行追記。 + **Copyright ブロックは新規には付けない**(`../../CODING.md` 1 節) +- [ ] `UOC_` メソッドの冒頭で `this.ReturnValue = ...` を設定 +- [ ] `ActionType` の `%` 区切り規約を壊さない(6 節) +- [ ] 設定キーを増やしたら `app.config`(Web は `app.config` 側)に追記 +- [ ] 実行確認をするなら `C:\root\files` と Northwind DB の準備状況を先に確認 diff --git a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/MVC_Sample.csproj b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/MVC_Sample.csproj index 60da843d2..a69202e32 100644 --- a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/MVC_Sample.csproj +++ b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/MVC_Sample.csproj @@ -318,6 +318,8 @@ + + diff --git a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.js b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.js new file mode 100644 index 000000000..85a9b1dad --- /dev/null +++ b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.js @@ -0,0 +1,205 @@ +// Unobtrusive Ajax support library for jQuery +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// @version v3.2.6 +// +// Microsoft grants you the right to use these script files for the sole +// purpose of either: (i) interacting through your browser with the Microsoft +// website or online service, subject to the applicable licensing or use +// terms; or (ii) using the files as included with a Microsoft product subject +// to that product's license terms. Microsoft reserves all other rights to the +// files not expressly granted by Microsoft, whether by implication, estoppel +// or otherwise. Insofar as a script file is dual licensed under GPL, +// Microsoft neither took the code under GPL nor distributes it thereunder but +// under the terms set out in this paragraph. All notices and licenses +// below are for informational purposes only. + +/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */ +/*global window: false, jQuery: false */ + +(function ($) { + var data_click = "unobtrusiveAjaxClick", + data_target = "unobtrusiveAjaxClickTarget", + data_validation = "unobtrusiveValidation"; + + function getFunction(code, argNames) { + var fn = window, parts = (code || "").split("."); + while (fn && parts.length) { + fn = fn[parts.shift()]; + } + if (typeof (fn) === "function") { + return fn; + } + argNames.push(code); + return Function.constructor.apply(null, argNames); + } + + function isMethodProxySafe(method) { + return method === "GET" || method === "POST"; + } + + function asyncOnBeforeSend(xhr, method) { + if (!isMethodProxySafe(method)) { + xhr.setRequestHeader("X-HTTP-Method-Override", method); + } + } + + function asyncOnSuccess(element, data, contentType) { + var mode; + + if (contentType.indexOf("application/x-javascript") !== -1) { // jQuery already executes JavaScript for us + return; + } + + mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase(); + $(element.getAttribute("data-ajax-update")).each(function (i, update) { + var top; + + switch (mode) { + case "BEFORE": + $(update).prepend(data); + break; + case "AFTER": + $(update).append(data); + break; + case "REPLACE-WITH": + $(update).replaceWith(data); + break; + default: + $(update).html(data); + break; + } + }); + } + + function asyncRequest(element, options) { + var confirm, loading, method, duration; + + confirm = element.getAttribute("data-ajax-confirm"); + if (confirm && !window.confirm(confirm)) { + return; + } + + loading = $(element.getAttribute("data-ajax-loading")); + duration = parseInt(element.getAttribute("data-ajax-loading-duration"), 10) || 0; + + $.extend(options, { + type: element.getAttribute("data-ajax-method") || undefined, + url: element.getAttribute("data-ajax-url") || undefined, + cache: (element.getAttribute("data-ajax-cache") || "").toLowerCase() === "true", + beforeSend: function (xhr) { + var result; + asyncOnBeforeSend(xhr, method); + result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(element, arguments); + if (result !== false) { + loading.show(duration); + } + return result; + }, + complete: function () { + loading.hide(duration); + getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(element, arguments); + }, + success: function (data, status, xhr) { + asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html"); + getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(element, arguments); + }, + error: function () { + getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"]).apply(element, arguments); + } + }); + + options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" }); + + method = options.type.toUpperCase(); + if (!isMethodProxySafe(method)) { + options.type = "POST"; + options.data.push({ name: "X-HTTP-Method-Override", value: method }); + } + + // change here: + // Check for a Form POST with enctype=multipart/form-data + // add the input file that were not previously included in the serializeArray() + // set processData and contentType to false + var $element = $(element); + if ($element.is("form") && $element.attr("enctype") == "multipart/form-data") { + var formdata = new FormData(); + $.each(options.data, function (i, v) { + formdata.append(v.name, v.value); + }); + $("input[type=file]", $element).each(function () { + var file = this; + $.each(file.files, function (n, v) { + formdata.append(file.name, v); + }); + }); + $.extend(options, { + processData: false, + contentType: false, + data: formdata + }); + } + // end change + + $.ajax(options); + } + + function validate(form) { + var validationInfo = $(form).data(data_validation); + return !validationInfo || !validationInfo.validate || validationInfo.validate(); + } + + $(document).on("click", "a[data-ajax=true]", function (evt) { + evt.preventDefault(); + asyncRequest(this, { + url: this.href, + type: "GET", + data: [] + }); + }); + + $(document).on("click", "form[data-ajax=true] input[type=image]", function (evt) { + var name = evt.target.name, + target = $(evt.target), + form = $(target.parents("form")[0]), + offset = target.offset(); + + form.data(data_click, [ + { name: name + ".x", value: Math.round(evt.pageX - offset.left) }, + { name: name + ".y", value: Math.round(evt.pageY - offset.top) } + ]); + + setTimeout(function () { + form.removeData(data_click); + }, 0); + }); + + $(document).on("click", "form[data-ajax=true] :submit", function (evt) { + var name = evt.currentTarget.name, + target = $(evt.target), + form = $(target.parents("form")[0]); + + form.data(data_click, name ? [{ name: name, value: evt.currentTarget.value }] : []); + form.data(data_target, target); + + setTimeout(function () { + form.removeData(data_click); + form.removeData(data_target); + }, 0); + }); + + $(document).on("submit", "form[data-ajax=true]", function (evt) { + var clickInfo = $(this).data(data_click) || [], + clickTarget = $(this).data(data_target), + isCancel = clickTarget && (clickTarget.hasClass("cancel") || clickTarget.attr('formnovalidate') !== undefined); + evt.preventDefault(); + if (!isCancel && !validate(this)) { + return; + } + asyncRequest(this, { + url: this.action, + type: this.method || "GET", + data: clickInfo.concat($(this).serializeArray()) + }); + }); +}(jQuery)); diff --git a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.min.js b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.min.js new file mode 100644 index 000000000..ae780ac8a --- /dev/null +++ b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.min.js @@ -0,0 +1,16 @@ +// Unobtrusive Ajax support library for jQuery +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// @version v3.2.6 +// +// Microsoft grants you the right to use these script files for the sole +// purpose of either: (i) interacting through your browser with the Microsoft +// website or online service, subject to the applicable licensing or use +// terms; or (ii) using the files as included with a Microsoft product subject +// to that product's license terms. Microsoft reserves all other rights to the +// files not expressly granted by Microsoft, whether by implication, estoppel +// or otherwise. Insofar as a script file is dual licensed under GPL, +// Microsoft neither took the code under GPL nor distributes it thereunder but +// under the terms set out in this paragraph. All notices and licenses +// below are for informational purposes only. +!function(t){function a(t,a){for(var e=window,r=(t||"").split(".");e&&r.length;)e=e[r.shift()];return"function"==typeof e?e:(a.push(t),Function.constructor.apply(null,a))}function e(t){return"GET"===t||"POST"===t}function r(t,a){e(a)||t.setRequestHeader("X-HTTP-Method-Override",a)}function n(a,e,r){var n;r.indexOf("application/x-javascript")===-1&&(n=(a.getAttribute("data-ajax-mode")||"").toUpperCase(),t(a.getAttribute("data-ajax-update")).each(function(a,r){switch(n){case"BEFORE":t(r).prepend(e);break;case"AFTER":t(r).append(e);break;case"REPLACE-WITH":t(r).replaceWith(e);break;default:t(r).html(e)}}))}function i(i,u){var o,c,d,s;if(o=i.getAttribute("data-ajax-confirm"),!o||window.confirm(o)){c=t(i.getAttribute("data-ajax-loading")),s=parseInt(i.getAttribute("data-ajax-loading-duration"),10)||0,t.extend(u,{type:i.getAttribute("data-ajax-method")||void 0,url:i.getAttribute("data-ajax-url")||void 0,cache:"true"===(i.getAttribute("data-ajax-cache")||"").toLowerCase(),beforeSend:function(t){var e;return r(t,d),e=a(i.getAttribute("data-ajax-begin"),["xhr"]).apply(i,arguments),e!==!1&&c.show(s),e},complete:function(){c.hide(s),a(i.getAttribute("data-ajax-complete"),["xhr","status"]).apply(i,arguments)},success:function(t,e,r){n(i,t,r.getResponseHeader("Content-Type")||"text/html"),a(i.getAttribute("data-ajax-success"),["data","status","xhr"]).apply(i,arguments)},error:function(){a(i.getAttribute("data-ajax-failure"),["xhr","status","error"]).apply(i,arguments)}}),u.data.push({name:"X-Requested-With",value:"XMLHttpRequest"}),d=u.type.toUpperCase(),e(d)||(u.type="POST",u.data.push({name:"X-HTTP-Method-Override",value:d}));var p=t(i);if(p.is("form")&&"multipart/form-data"==p.attr("enctype")){var f=new FormData;t.each(u.data,function(t,a){f.append(a.name,a.value)}),t("input[type=file]",p).each(function(){var a=this;t.each(a.files,function(t,e){f.append(a.name,e)})}),t.extend(u,{processData:!1,contentType:!1,data:f})}t.ajax(u)}}function u(a){var e=t(a).data(d);return!e||!e.validate||e.validate()}var o="unobtrusiveAjaxClick",c="unobtrusiveAjaxClickTarget",d="unobtrusiveValidation";t(document).on("click","a[data-ajax=true]",function(t){t.preventDefault(),i(this,{url:this.href,type:"GET",data:[]})}),t(document).on("click","form[data-ajax=true] input[type=image]",function(a){var e=a.target.name,r=t(a.target),n=t(r.parents("form")[0]),i=r.offset();n.data(o,[{name:e+".x",value:Math.round(a.pageX-i.left)},{name:e+".y",value:Math.round(a.pageY-i.top)}]),setTimeout(function(){n.removeData(o)},0)}),t(document).on("click","form[data-ajax=true] :submit",function(a){var e=a.currentTarget.name,r=t(a.target),n=t(r.parents("form")[0]);n.data(o,e?[{name:e,value:a.currentTarget.value}]:[]),n.data(c,r),setTimeout(function(){n.removeData(o),n.removeData(c)},0)}),t(document).on("submit","form[data-ajax=true]",function(a){var e=t(this).data(o)||[],r=t(this).data(c),n=r&&(r.hasClass("cancel")||void 0!==r.attr("formnovalidate"));a.preventDefault(),(n||u(this))&&i(this,{url:this.action,type:this.method||"GET",data:e.concat(t(this).serializeArray())})})}(jQuery); \ No newline at end of file diff --git a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Views/Shared/_Layout.cshtml b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Views/Shared/_Layout.cshtml index 781f02a0c..91b3a57ea 100644 --- a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Views/Shared/_Layout.cshtml +++ b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Views/Shared/_Layout.cshtml @@ -69,10 +69,10 @@ @if (User.Identity.IsAuthenticated) { @* 各メニューは、ユーザーが認証されている時だけ表示する *@ -
  • +
  • メニュー1
  • -
  • +
  • メニュー2
  • } diff --git a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Web.config b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Web.config index 2f02c8c76..fbeaf2b1a 100644 --- a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Web.config +++ b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Web.config @@ -142,6 +142,13 @@ http://msdn2.microsoft.com/ja-jp/library/1d3t3c61.aspx http://msdn2.microsoft.com/ja-jp/library/1d3t3c61(VS.80).aspx --> + + + + diff --git a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/images/touryo/loading.gif b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/images/touryo/loading.gif new file mode 100644 index 000000000..3e0220309 Binary files /dev/null and b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/images/touryo/loading.gif differ diff --git a/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/images/touryo/logo.png b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/images/touryo/logo.png new file mode 100644 index 000000000..a28bca100 Binary files /dev/null and b/root/programs/CS/Samples/WebApp_sample/MVC_Sample/MVC_Sample/images/touryo/logo.png differ diff --git a/root/programs/CS/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Scripts/touryo/common.js b/root/programs/CS/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Scripts/touryo/common.js index d9584cf27..7b2a6aa61 100644 --- a/root/programs/CS/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Scripts/touryo/common.js +++ b/root/programs/CS/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Scripts/touryo/common.js @@ -44,6 +44,9 @@ //* 2019/03/04 西野 大介 二重送信防止のブラウザ判定処理を修正 //* 2019/03/04 西野 大介 WebForms版とMVC版のDiffを取り易く修正。 //* 2020/03/19 西野 大介 モダン・ブラウザ・サポート(2017/04/20)の制限事項解除 +//* 2026/08/01 玄人 幸道 業務モーダル画面を閉じた際に親画面がPost Backされない問題に対応 +//* (unloadイベントがブラウザ側で無効化されたため、 +//*  window.closedのポーリングによる終了検知を併用する) //********************************************************************************** // --------------------------------------------------------------- @@ -582,6 +585,46 @@ function Fx_InitPseudoDialog() { } +// --------------------------------------------------------------- +// 擬似DialogのiframeへURLを設定してよいかを判定 +// --------------------------------------------------------------- +// 引数 url +// 戻り値 true : 設定してよい / false : 設定しない +// --------------------------------------------------------------- +// このURLはフレームワーク(ShowModalScreen)が組み立てており、 +// 利用者の入力は入ってこない。AppScanのテストもクリアしている。 +// ここでの検証は、サンプルを手本にしたコードが動的なURLを +// 流し込んだ場合に備える多層防御である。 +// ・javascript: / data: / vbscript: … スクリプト実行を防ぐ +// ・//evil.example.com … 別オリジンの表示を防ぐ +// 相対URL(Aspx/... や /App/... )だけを通す。 +// --------------------------------------------------------------- +function Fx_IsSafeDialogUrl(url) { + + if (typeof url !== "string" || url === "") { + return false; + } + + // 前後の空白と制御文字を除いてから判定する + // ("java\tscript:" のような細工を防ぐ)。 + var u = url.replace(/[\u0000-\u0020]/g, ""); + + // スキーム付きは、http / https だけを通す。 + var scheme = u.match(/^([A-Za-z][A-Za-z0-9+.-]*):/); + if (scheme) { + var s = scheme[1].toLowerCase(); + return (s === "http" || s === "https"); + } + + // "//host/path" はプロトコル相対=別オリジンになり得るので通さない。 + if (u.indexOf("//") === 0) { + return false; + } + + // ここまで来たものは相対URL。 + return true; +} + // --------------------------------------------------------------- // Pseudo Dialog表示 // --------------------------------------------------------------- @@ -603,7 +646,16 @@ function Fx_DisplayPseudoDialog(ajaxPseudoDialog, url) { for (var i = 0; i < elementChildren.length; i++) { if (elementChildren[i].id === "FxIFrame") { - elementChildren[i].src = url; + // URLを検証してから設定する(CodeQL: DOM text reinterpreted as HTML)。 + if (Fx_IsSafeDialogUrl(url)) { + elementChildren[i].src = url; + } + else { + // 通さなかったことが分かるようにする(画面は空のままになる)。 + if (window.console && window.console.error) { + window.console.error("Fx_DisplayPseudoDialog: unsafe url was blocked."); + } + } } } @@ -938,11 +990,24 @@ function Fx_CallbackOfBusinessModalScreen() { // --------------------------------------------------------------- function Fx_CallbackOfBusinessModalScreen2() { + // ↓↓↓【追加】↓↓↓ + // unloadイベントとポーリングの両方から呼ばれる可能性があるため、二重実行を防ぐ。 + if (Fx_BusinessPseudoModelDialog === null + || Fx_BusinessPseudoModelDialog === undefined) { + return; + } + // ↑↑↑【追加】↑↑↑ + // イベントを外す if (Fx_BusinessPseudoModelDialog.closed) { // 閉じている。 $(Fx_BusinessPseudoModelDialog).off("unload"); //, Fx_CallbackOfBusinessModalScreen); Fx_BusinessPseudoModelDialog = null; + + // ↓↓↓【追加】↓↓↓ + // 終了検知のポーリングも解除する。 + Fx_ClearWatcherOfBusinessModalScreen(); + // ↑↑↑【追加】↑↑↑ } else { // 閉じていない。 // unloadのCallbackを"再度"仕掛ける。 @@ -1129,8 +1194,61 @@ function Fx_SetCallbackOfBusinessModalScreen() { // --------------------------------------------------------------- function Fx_SetCallbackOfBusinessModalScreen2() { $(Fx_BusinessPseudoModelDialog).on("unload", Fx_CallbackOfBusinessModalScreen); + + // ↓↓↓【追加】↓↓↓ + // unloadイベントは、モダン・ブラウザ側で無効化が進んでおり発火しないことがある + // (Chromeでは document.featurePolicy.allowsFeature("unload") が false になる)。 + // このため、window.closed のポーリングでも子画面の終了を検知する。 + Fx_SetWatcherOfBusinessModalScreen(); + // ↑↑↑【追加】↑↑↑ } +// ↓↓↓【追加】↓↓↓ + +// Business疑似Model(実体はModeless)Screenの終了監視タイマ +var Fx_WatcherOfBusinessPseudoModelDialog = null; + +// --------------------------------------------------------------- +// モダンブラウザ版(window.closedのポーリングによる終了検知を仕掛ける) +// --------------------------------------------------------------- +// 引数 - +// 戻り値 - +// --------------------------------------------------------------- +function Fx_SetWatcherOfBusinessModalScreen() { + + // 多重に仕掛けない。 + Fx_ClearWatcherOfBusinessModalScreen(); + + Fx_WatcherOfBusinessPseudoModelDialog = setInterval( + function () { + if (Fx_BusinessPseudoModelDialog === null + || Fx_BusinessPseudoModelDialog === undefined + || Fx_BusinessPseudoModelDialog.closed) { + + // 閉じられたので、監視を終了して後処理を実行する。 + Fx_ClearWatcherOfBusinessModalScreen(); + Fx_CallbackOfBusinessModalScreen(); + } + }, + TimeLag4BusinessPseudoModelDialog); +} + +// --------------------------------------------------------------- +// モダンブラウザ版(終了検知のポーリングを解除する) +// --------------------------------------------------------------- +// 引数 - +// 戻り値 - +// --------------------------------------------------------------- +function Fx_ClearWatcherOfBusinessModalScreen() { + + if (Fx_WatcherOfBusinessPseudoModelDialog !== null) { + clearInterval(Fx_WatcherOfBusinessPseudoModelDialog); + Fx_WatcherOfBusinessPseudoModelDialog = null; + } +} + +// ↑↑↑【追加】↑↑↑ + //********************************************************************************** // フレームワーク機能(Ajax Extension) //********************************************************************************** diff --git a/root/programs/CS/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Web.config b/root/programs/CS/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Web.config index 9954eee1f..7c679c292 100644 --- a/root/programs/CS/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Web.config +++ b/root/programs/CS/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Web.config @@ -136,6 +136,13 @@ http://msdn2.microsoft.com/ja-jp/library/1d3t3c61.aspx http://msdn2.microsoft.com/ja-jp/library/1d3t3c61(VS.80).aspx --> + + + + + diff --git a/root/programs/CS/Samples4NetCore/ANALYSIS.md b/root/programs/CS/Samples4NetCore/ANALYSIS.md new file mode 100644 index 000000000..b44e5b305 --- /dev/null +++ b/root/programs/CS/Samples4NetCore/ANALYSIS.md @@ -0,0 +1,360 @@ +# ANALYSIS.md — Open棟梁 サンプル アプリ(CS/Samples4NetCore)コード分析 + +対象: `root/programs/CS/Samples4NetCore`(**.NET 10.0**) / ブランチ: `develop` +最終更新: 2026-07-31 + +本書は **コーディング・エージェントが本ディレクトリで作業する際の Context** を目的とする。 +フレームワーク本体は `../Frameworks/ANALYSIS.md`、net48 版サンプルは `../Samples/ANALYSIS.md` を参照。 + +--- + +## 1. これは何か + +Open棟梁の **.NET (Core) 系サンプル**。3 つの区画に分かれており、性格がまったく違う。 + +| 区画 | 中身 | 性格 | +|---|---|---| +| **`Backend/`** | `MVC_Sample`(ASP.NET Core MVC) | **現行の推奨サンプル。** ここが本命 | +| **`Frontend/`** | README のみ | 別リポジトリ `FrontendTemplates` へ移動済み | +| **`Legacy/`** | `2CS_sample` / `Bat_sample` / `CLI_sample` / `WS_sample` | `../Samples`(net48)を .NET へ移植した**独立コピー**。名前どおり「レガシー」扱い | + +**全プロジェクトが SDK 形式 csproj / `net10.0`(GUI は `net10.0-windows7.0`)。** + +--- + +## 2. 前提条件 + +### 2-1. フレームワークを先にビルドする(最重要) + +**18 プロジェクト中 17 が `Build_netcore100\net10.0\*.dll` を `HintPath` で直接参照する** +(例外は `Legacy/CLI_sample/Simple_CLI` のみ。こちらはフレームワーク非依存)。 +`ProjectReference` ではないので、**フレームワークをビルドしない限り古い / 存在しない DLL を見る。** + +```xml + + ..\..\..\..\Frameworks\Infrastructure\Build_netcore100\net10.0\OpenTouryo.Framework.dll + +``` + +``` +dotnet build ../Frameworks/Infrastructure/Nuget_netcore100.sln ★先にこれ +dotnet build ../Frameworks/Infrastructure/Business_netcore100.sln +→ その後に各サンプル +``` + +> net48 側の `Samples` が参照する `Build\` とは**別のディレクトリ**。 +> `4_Build_CopyAssemblies.bat`(`Build_net48` → `Build\`)は **.NET (Core) 側には関係しない**。 + +### 2-2. リポジトリを `C:\root\` に配置する + +`Backend/MVC_Sample` と `Legacy/*` の設定は `C:/root/files/resource/...` を直書きしている。 + +```json +"FxXMLSPDefinition": "C:/root/files/resource/XML/SPDefinition.xml", +"SqlTextFilePath": "C:/root/files/resource/Sql" +``` + +チェックアウト先が `C:\root` 以外(例: `C:\OpenTouryo\root`)の場合、**ビルドは通るが実行時に落ちる**。 +net48 側と違い **区切り文字が `/`**(JSON なのでエスケープ回避)。 + +### 2-3. データベース + +SQL Server の **Northwind** が既定。`Legacy/Bat_sample/RerunnableBatch_sample*` は `ORDERS2` テーブルが追加で必要。 +接続文字列は net48 版と同一のサンプル値(`localhost` / `sa` / `seigi@123` 等)。 +Core 側は **PostgreSQL (`ConnectionString_NPS`) が追加**されている点が net48 版との差。 + +--- + +## 3. `Backend/MVC_Sample` — 現行の推奨サンプル + +ASP.NET Core MVC(`Microsoft.NET.Sdk.Web` / `net10.0`)。`Startup.cs` 方式(Minimal API ではない)。 + +### 3-1. フレームワークの組み込み方(テンプレートとして重要) + +```csharp +// Program.cs +public static void Main(string[] args) +{ + OAuth2AndOIDCClient.HttpClient = new HttpClient(); // ★静的 HttpClient を差し込む + Program.BuildWebHost(args).Run(); +} + +// Startup.cs +public Startup(IConfiguration configuration) +{ + Configuration = configuration; + GetConfigParameter.InitConfiguration(configuration); // ★必須。これが無いと Fx* 設定が全て null +} + +public void Configure(IApplicationBuilder app, IWebHostEnvironment env) +{ + app._UseHttpContextAccessor(); // ★必須。MyHttpContext.Current を有効化する拡張メソッド + ... + app.UseSession(new SessionOptions() { ... }); // セッション機能を使うなら必須 +} +``` + +**この 3 点(`InitConfiguration` / `_UseHttpContextAccessor` / `UseSession`)が +.NET (Core) で Open棟梁 を動かすための定型**。`_UseHttpContextAccessor` は +`Touryo.Infrastructure.Framework.StdMigration.HttpContextExtensions` の拡張メソッドで、 +`System.Web.HttpContext.Current` 相当を `MyHttpContext.Current` として復活させる。 + +### 3-2. 構成 + +``` +MVC_Sample/ +├─ Program.cs / Startup.cs +├─ Controllers/ +│ ├─ Crud1Controller.cs … Ajax(部分更新)版 CRUD +│ ├─ Crud2Controller.cs … Html.BeginForm(全体更新)版 CRUD +│ ├─ HomeController.cs … ログイン / OAuth2 認可コードグラント / ログアウト +│ ├─ ErrorController.cs +│ └─ PingController.cs … 死活監視(MyBaseMVControllerCore を継承しない素の Controller) +├─ Logic/Business/LayerB.cs … B層 +├─ Logic/Common/Test*Value.cs … 引数・戻り値クラス +├─ Logic/Dao/{LayerD,DaoShippers}.cs … D層 +├─ Models/ViewModels/*.cs +├─ Views/{Crud1,Crud2,Home,Error,Shared}/*.cshtml +├─ wwwroot/{css,js,images}/ … bootstrap 等はリポジトリに直接格納(npm 不使用) +├─ appsettings.json / appsettings.Development.json +└─ Properties/launchSettings.json +``` + +- コントローラは **`MyBaseMVControllerCore` を継承**(`Touryo.Infrastructure.Business.Presentation`)。 +- **`[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]`** が + `Crud1` / `Crud2` に付与されており、Cookie 認証必須。 +- B層呼び出しは **`await layerB.DoBusinessLogicAsync(...)`**(net48 版は同期の `DoBusinessLogic`)。 + +```csharp +public async Task SelectCount(CrudViweModel model) +{ + LayerB layerB = new LayerB(); + TestReturnValue r = (TestReturnValue)await layerB.DoBusinessLogicAsync( + testParameterValue, this.SelectIsolationLevel(model.DdlIso)); + ... +} +``` + +- `Crud1` = Ajax 部分更新(`_ChartView.cshtml` / `_MessageView.cshtml` を部分レンダリング) +- `Crud2` = `Html.BeginForm` で全体更新 + → **同じ業務ロジックを 2 つの UI 方式で呼ぶ対比サンプル**になっている。 + +### 3-3. 認証(`HomeController`) + +- フォーム ログイン: `ClaimsIdentity` / `ClaimsPrincipal` を組み立てて `SignInAsync` +- **OAuth2 認可コードグラント**: `OAuth2AndOIDCClient.GetAccessTokenByCodeAsync` → + id_token 検証 → `GetUserInfoAsync` → `SignInAsync` +- 接続先は `appsettings.json` の `SpRp_*` / `OAuth2AndOidc*` / `JwkSetUri` + (既定は `https://localhost:44300/MultiPurposeAuthSite/...` = 別リポジトリの汎用認証サイト) + +**この OAuth2 フローを動かすには MultiPurposeAuthSite が別途必要。** 単体では Login 画面までしか動かない。 + +### 3-4. npm / grunt は使わない + +**`wwwroot/lib/` 配下(bootstrap 等)はリポジトリに直接格納**されており、 +`package.json` / `gruntfile.js` / `RestoreLib1.bat` / `RestoreLib2.bat` は存在しない +(コミット `2a08482f` で npm/grunt を廃止した)。`10_Build_WebAppCore_sample.bat` も npm 手順を持たない。 + +### 3-5. 起動 + +``` +dotnet run --project Backend/MVC_Sample/MVC_Sample/MVC_Sample.csproj +``` + +`launchSettings.json` のプロファイル: `http`(5219) / `https`(7014) / `IIS Express`(26422, ssl 44383)。 + +--- + +## 4. `Legacy/` — net48 版からの移植 + +`../Samples/` の **独立コピー**。`Compile Include` によるファイル共有は**していない**。 + +| ディレクトリ | 中身 | net48 版との差 | +|---|---|---| +| `Legacy/2CS_sample` | 2CSClientWin / 2CSClientWPF / CustCtrl / GenDaoAndBatUpd / TimeStamp | **`AsyncEvent_sample` が未移植** | +| `Legacy/Bat_sample` | SimpleBatch / RerunnableBatch ×3 | 同等 | +| `Legacy/CLI_sample` | Simple_CLI / DAG_Login_CLI / LIR_Login_CLI | **こちらにしか実体が無い**(後述) | +| `Legacy/WS_sample` | WSServer / WSIFType / WSClient ×3 | **`WSClientWinCone_sample` が未移植** | + +### 4-1. `Samples`(net48)との同一性 — 実測 + +| サンプル群 | 同一ファイル | 差異あり | net48 側のみ | +|---|---|---|---| +| `2CS_sample` | 138 | 18 | 26 | +| `Bat_sample` | 73 | 14 | 8 | +| `WS_sample` | 65 | 14 | 36 | + +- **`Business/LayerB.cs` や `Dao/*.cs` は多くがバイト単位で同一。** +- 差異があるのは主に `*.csproj` / `*.sln` / `Program.cs`。 +- net48 側のみ = `app.config`(Core は `appsettings.json`)、`Properties/AssemblyInfo.cs`(SDK 形式は自動生成)。 + +→ **B層・D層のロジックを直したら `../Samples/` 側の同名ファイルも同じ修正が必要。** + +### 4-2. `Program.cs` の差分(移植の定型) + +Core 側は **冒頭で config を明示初期化する**のが唯一の実質的な差。 + +```csharp +// configの初期化(net48 版には無い) +string dir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory + .FullName.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); +GetConfigParameter.InitConfiguration(dir + "/appsettings.json"); +``` + +以降の `TestParameterValue` 生成 → `layerB.DoBusinessLogic(...)` は net48 版と同一。 + +### 4-3. `Legacy/CLI_sample` — ここにしか無い + +net48 版は README のみ(Sharprompt が .NET Framework サポートを終了したため)。 +実体は Core 側だけに存在する。 + +| プロジェクト | 内容 | +|---|---| +| `Simple_CLI` | `System.CommandLine` + `Sharprompt` の CLI テンプレート。**フレームワーク非依存**(`OpenTouryo.*` 参照なし) | +| `DAG_Login_CLI` | OAuth 2.0 **Device Authorization Grant** クライアント | +| `LIR_Login_CLI` | OAuth 2.0 for Native Apps の **Loopback Interface Redirection** | + +`DAG` / `LIR` は `OpenTouryo.Framework` / `Public` / `Public.Security` を参照する。 + +> **注意**: `System.CommandLine` が **`2.0.0-beta1.21216.1`(2021 年の beta)** で固定されている。 +> net48 版 README には「beta が解除され Ctrl-C で CancellationToken がハングする問題が修正されたら移植する」 +> と書かれており、この beta 依存は**意図的に据え置かれている**。安易に上げない。 + +### 4-4. `Legacy/WS_sample` — リモート プロトコルは実質使えない + +`TMProtocolDefinition.xml` は net48 版からコピーされており `protocol="2"〜"5"`(asmx / WCF-HTTP / +WCF-TCP / WebAPI)の定義が残っているが、**.NET (Core) の `FxEnum.TmProtocol` は `InProcess`(1) しか持たない** +(`../Frameworks/ANALYSIS.md` 6.4 節)。 + +さらに `7_Build_Framework_WSCore.bat` はサービス ホスト側のビルドを丸ごと `rem` で無効化しており、 +理由が `Core系のBinarySerializeの完全廃止対応` と記されている。 + +→ **Core 側の WS_sample は `testInProcess`(インプロセス呼び出し)でのみ動作する。** +定義ファイルに remote の記述が残っていることに惑わされないこと。 + +--- + +## 5. 設定(`appsettings.json`) + +net48 の `app.config` → Core は `appsettings.json`。**`appSettings` / `connectionStrings` という +セクション名を JSON でもそのまま使う**のが Open棟梁の流儀。 + +```json +{ + "connectionStrings": { + "ConnectionString_SQL": "Data Source=localhost;Initial Catalog=Northwind;...", + "ConnectionString_NPS": "HOST=localhost;DATABASE=postgres;..." + }, + "appSettings": { + "FxXMLSPDefinition": "C:/root/files/resource/XML/SPDefinition.xml", + "FxLog4NetConfFile": "C:/root/files/resource/Log/SampleLogConf.xml", + "FxSqlTraceLog": "on", + "SqlTextFilePath": "C:/root/files/resource/Sql" + } +} +``` + +- **`appsettings.json` はコメント付き JSON(JSONC)**で書かれている。 + `Microsoft.Extensions.Configuration.Json` は `//` コメントを許容するが、 + 厳密な JSON パーサで読むと壊れるので注意。 +- `Legacy/*` は `csproj` で `Always` を + `appsettings.json` / `MSGDefinition.xml` / `SPDefinition.xml` / `SampleLogConf2CS.xml` に指定している。 + **定義ファイルを追加したら csproj にもコピー指定を足す**必要がある。 +- `Backend/MVC_Sample` は Web SDK なので `appsettings.json` は自動でコピーされる。 + +--- + +## 6. ビルド + +`root/programs/CS/` 直下の bat(内部は `dotnet restore` + `dotnet msbuild`)。 + +| bat | 対象 | +|---|---| +| `5_Build_2CSCore_sample.bat` | `Legacy/2CS_sample/*` | +| `5_Build_BatCore_sample.bat` | `Legacy/Bat_sample/*`(4 sln) | +| `5_Build_CLICore_sample.bat` | `Legacy/CLI_sample/*` | +| `6_Build_WSSrvCore_sample.bat` | `Legacy/WS_sample/WSServer_sample` → `Temp` → `Build/net10.0` へ xcopy | +| `7_Build_Framework_WSCore.bat` | **中身が `rem` で無効化されている**(no-op) | +| `8_Build_WSClntCore_sample.bat` | `Legacy/WS_sample/WSClient_sample/*` | +| `10_Build_WebAppCore_sample.bat` | `Backend/MVC_Sample` | + +bat を経由せず **`dotnet build ` を直接叩いてよい**(Core 側は MSBuild.exe 不要)。 +ただし **フレームワークを先にビルドする**こと(2-1 節)。 + +--- + +## 7. 依存パッケージのバージョン ドリフト(実測) + +サンプルはフレームワークを `HintPath` で直接参照するため **NuGet の推移的解決が効かない**。 +.NET には binding redirect も無いので、**サンプル側のパッケージ版がフレームワーク側より古いと +起動直後に `FileNotFoundException`(`Could not load file or assembly ...`)で落ちる。** + +`log4net` は全プロジェクトで **3.3.0**(フレームワーク本体と一致)に統一済み。 + +一方、以下は依然としてプロジェクトごとに版が違う。 + +| パッケージ | 混在しているバージョン | +|---|---| +| `Microsoft.Data.SqlClient` | **6.0.2**(Legacy) / **6.1.3**(Backend/MVC_Sample) / 6.0.1(フレームワーク) | +| `Newtonsoft.Json` | **13.0.3**(Legacy/フレームワーク) / **13.0.4**(Backend/MVC_Sample) | +| `Microsoft.Extensions.Configuration*` | 9.0.5 / 9.0.6 / 9.0.4(フレームワーク) | +| `System.Data.Odbc` | 9.0.5 / 9.0.6 | + +サンプル側が**新しい**分には動作するが、**フレームワーク側が上がったとき(Dependabot 等)に +サンプルが取り残されると即座に起動不能になる**。フレームワークの依存を上げたら、 +サンプル側(`Backend` / `Legacy` の全 csproj)も同時に上げること。 + +--- + +## 8. 落とし穴 + +1. **フレームワークを先にビルドしないと `HintPath` 参照が解決できない。** これが最頻の失敗要因。 +2. **`GetConfigParameter.InitConfiguration(...)` を呼ばないと `Fx*` 設定が全て null** + になり、定義ファイルが読めず例外になる。net48 には無かった手順。 +3. **`app._UseHttpContextAccessor()` を呼ばないと `MyHttpContext.Current` が null。** + Web アプリで必須。 +4. **`C:/root/files/...` の絶対パス依存。** ビルドは通るが実行時に落ちる。 +5. **`Legacy/` は `../Samples/` の独立コピー。** 片方を直したらもう片方も直す(4-1 節)。 +6. **Core では `CallController` のリモート プロトコルが使えない**(`InProcess` のみ)。 + `TMProtocolDefinition.xml` に残る `protocol="2"〜"5"` は死んだ定義(4-4 節)。 +7. **`_3TierEngine` / `MyBaseLogic` は .NET (Core) 版フレームワークに含まれない** + (`Business_netcore100.csproj` が `Compile Remove` している)。 + Core のサンプルが使うのは `MyFcBaseLogic` 系のみ。 +8. **`System.CommandLine` の beta 固定は意図的**(4-3 節)。 +9. **`appsettings.json` はコメント付き JSON。** +10. **`Legacy/WS_sample/Build/` `Temp/` はビルド生成物**(`Build/` は `.gitignore` 済み)。 +11. **`ReturnValue` を設定し忘れると戻り値が null**(フレームワーク仕様。`../Frameworks/ANALYSIS.md` 3.2 節)。 +12. **`Frontend/` に実体は無い。** `OpenTouryoProject/FrontendTemplates` を見ること。 +13. **`Backend/ASPNETWebService/` にも実体は無い。** `OpenTouryoProject/ResourceServerTemplates` へ移動済み。 + +--- + +## 9. `Samples`(net48)との対応表 + +| | `../Samples`(net48) | `Samples4NetCore` | +|---|---|---| +| TFM | `net48`(旧形式 csproj) | `net10.0` / `net10.0-windows7.0`(SDK 形式) | +| フレームワーク参照 | `Build\`(`4_Build_CopyAssemblies.bat` が生成) | `Build_netcore100\net10.0\` を直接 | +| 設定 | `app.config`(+ Web は `Web.config`) | `appsettings.json` | +| config 初期化 | 不要(暗黙) | **`InitConfiguration()` が必須** | +| Web | Web Forms(38 画面)+ MVC5 | ASP.NET Core MVC のみ | +| B層呼び出し | 同期 `DoBusinessLogic` | 非同期 `DoBusinessLogicAsync`(Backend) | +| WS リモート | asmx / WCF-HTTP / WCF-TCP / WebAPI | **InProcess のみ** | +| CLI | README のみ | **実体あり** | +| 非同期イベント | `AsyncEvent_sample` あり | 未移植 | +| NuGet | `packages.config`(Web) | `PackageReference` | + +--- + +## 10. エージェント向け作業チェックリスト + +- [ ] `AGENTS.md` のポリシー遵守(**git 操作をしない**) +- [ ] **フレームワークを先にビルド**(`Nuget_netcore100.sln` → `Business_netcore100.sln`) +- [ ] `Legacy/` を触ったら `../Samples/` 側の同名ファイルの追随要否を判定・報告(4-1 節) +- [ ] Web アプリを新規に起こすなら `InitConfiguration` / `_UseHttpContextAccessor` / `UseSession` を忘れない +- [ ] 定義 XML を追加したら `Legacy/*` の csproj に `CopyToOutputDirectory` を追記 +- [ ] パッケージ バージョンを変えるならフレームワーク本体との整合を確認(7 節) +- [ ] 新規 .cs にはヘッダ コメント(Apache License / クラス名・日本語名・更新履歴)を付与、既存変更時は履歴に 1 行追記。 + **Copyright ブロックは新規には付けない**(`../../CODING.md` 1 節) +- [ ] `UOC_` メソッドの冒頭で `this.ReturnValue = ...` を設定 +- [ ] 実行確認をするなら `C:\root\files` と Northwind DB の準備状況を先に確認 diff --git a/root/programs/CS/Samples4NetCore/Backend/MVC_Sample/MVC_Sample/MVC_Sample.csproj b/root/programs/CS/Samples4NetCore/Backend/MVC_Sample/MVC_Sample/MVC_Sample.csproj index 93a6ce2a8..fe2f7d83d 100644 --- a/root/programs/CS/Samples4NetCore/Backend/MVC_Sample/MVC_Sample/MVC_Sample.csproj +++ b/root/programs/CS/Samples4NetCore/Backend/MVC_Sample/MVC_Sample/MVC_Sample.csproj @@ -11,7 +11,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/2CSClientWPF_sample/2CSClientWPF_sample.csproj b/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/2CSClientWPF_sample/2CSClientWPF_sample.csproj index 5b07b1de6..ea085d287 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/2CSClientWPF_sample/2CSClientWPF_sample.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/2CSClientWPF_sample/2CSClientWPF_sample.csproj @@ -23,7 +23,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/2CSClientWin_sample/2CSClientWin_sample.csproj b/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/2CSClientWin_sample/2CSClientWin_sample.csproj index d8337f210..3a06822d3 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/2CSClientWin_sample/2CSClientWin_sample.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/2CSClientWin_sample/2CSClientWin_sample.csproj @@ -25,7 +25,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/GenDaoAndBatUpd_sample/GenDaoAndBatUpd_sample.csproj b/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/GenDaoAndBatUpd_sample/GenDaoAndBatUpd_sample.csproj index f964bfc59..56353541b 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/GenDaoAndBatUpd_sample/GenDaoAndBatUpd_sample.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/GenDaoAndBatUpd_sample/GenDaoAndBatUpd_sample.csproj @@ -136,7 +136,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/TimeStamp_sample/TimeStamp_sample.csproj b/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/TimeStamp_sample/TimeStamp_sample.csproj index 8043b9b0b..b42243277 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/TimeStamp_sample/TimeStamp_sample.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/2CS_sample/TimeStamp_sample/TimeStamp_sample.csproj @@ -239,7 +239,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample/RerunnableBatch_sample.csproj b/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample/RerunnableBatch_sample.csproj index 9de4b1dc1..ea6eee18b 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample/RerunnableBatch_sample.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample/RerunnableBatch_sample.csproj @@ -16,7 +16,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample2/RerunnableBatch_sample2.csproj b/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample2/RerunnableBatch_sample2.csproj index 9de4b1dc1..ea6eee18b 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample2/RerunnableBatch_sample2.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample2/RerunnableBatch_sample2.csproj @@ -16,7 +16,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample3/RerunnableBatch_sample3.csproj b/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample3/RerunnableBatch_sample3.csproj index 9de4b1dc1..ea6eee18b 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample3/RerunnableBatch_sample3.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/RerunnableBatch_sample3/RerunnableBatch_sample3.csproj @@ -16,7 +16,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/SimpleBatch_sample/SimpleBatch_sample.csproj b/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/SimpleBatch_sample/SimpleBatch_sample.csproj index 4bf9b12e9..942929f1d 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/SimpleBatch_sample/SimpleBatch_sample.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/Bat_sample/SimpleBatch_sample/SimpleBatch_sample.csproj @@ -15,7 +15,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample.csproj b/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample.csproj index 3f12d6375..c0d117164 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample.csproj @@ -46,7 +46,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWin2_sample/WSClientWin2_sample.csproj b/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWin2_sample/WSClientWin2_sample.csproj index e8e1e15b6..ab35da905 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWin2_sample/WSClientWin2_sample.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWin2_sample/WSClientWin2_sample.csproj @@ -26,7 +26,7 @@ - + diff --git a/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample.csproj b/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample.csproj index 0331f35b4..fffe74349 100644 --- a/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample.csproj +++ b/root/programs/CS/Samples4NetCore/Legacy/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample.csproj @@ -48,7 +48,7 @@ - + diff --git a/root/programs/CS/y_Build_TestCode.bat b/root/programs/CS/y_Build_TestCode.bat index 7b4d0cda1..b50eed96a 100644 --- a/root/programs/CS/y_Build_TestCode.bat +++ b/root/programs/CS/y_Build_TestCode.bat @@ -1,4 +1,4 @@ -@rem -------------------------------------------------- +@rem -------------------------------------------------- @rem TestCode -> TestCodeFx, TestCodeCore @rem -------------------------------------------------- echo | call y_Build_TestCode_Public.bat diff --git a/root/programs/CS/y_Build_TestCode_Batch.bat b/root/programs/CS/y_Build_TestCode_Batch.bat index 96982fffb..fe56ef025 100644 --- a/root/programs/CS/y_Build_TestCode_Batch.bat +++ b/root/programs/CS/y_Build_TestCode_Batch.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat @rem -------------------------------------------------- @rem Batch build of SimpleBatch. @rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Tests\TestBatch\SimpleBatch\SimpleBatch.sln" +..\nuget.exe restore "Frameworks\Tests\TestBatch\SimpleBatch\SimpleBatch.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Tests\TestBatch\SimpleBatch\SimpleBatch.sln" dotnet restore "Frameworks\Tests\TestBatch\SimpleBatchCore\SimpleBatchCore.sln" diff --git a/root/programs/CS/y_Build_TestCode_DataAccess.bat b/root/programs/CS/y_Build_TestCode_DataAccess.bat new file mode 100644 index 000000000..0e7aca7d5 --- /dev/null +++ b/root/programs/CS/y_Build_TestCode_DataAccess.bat @@ -0,0 +1,52 @@ +setlocal + +@rem -------------------------------------------------- +@rem Turn off the echo function. +@rem -------------------------------------------------- +@echo off + +@rem -------------------------------------------------- +@rem Get the path to the executable file. +@rem -------------------------------------------------- +set CURRENT_DIR="%~dp0" + +@rem -------------------------------------------------- +@rem Execution of the common processing. +@rem -------------------------------------------------- +call %CURRENT_DIR%z_Common.bat + +@rem -------------------------------------------------- +@rem Batch build of TestDataAccess. +@rem -------------------------------------------------- +..\nuget.exe restore "Frameworks\Tests\TestDataAccess\TestDataAccessFx48.sln" %NUGET_MSBUILD% +%BUILDFILEPATH% %COMMANDLINE% "Frameworks\Tests\TestDataAccess\TestDataAccessFx48.sln" + +dotnet restore "Frameworks\Tests\TestDataAccess\TestDataAccessCore100.sln" +dotnet msbuild %COMMANDLINE% "Frameworks\Tests\TestDataAccess\TestDataAccessCore100.sln" + +@rem -------------------------------------------------- +@rem /MODE SQLONLY : SQL Server only (the default). +@rem /MODE LOCAL : all the DBMS running on the local Docker. +@rem The expected results (Result*.txt) are recorded with SQLONLY. +@rem -------------------------------------------------- + +@echo -------------------------------------------------- +@echo Test the TestDataAccessFx(48). +@echo -------------------------------------------------- +set CURRENTDIR=%cd% +cd "Frameworks\Tests\TestDataAccess\net48\bin\Debug" +"TestDataAccessFx.exe" /MODE SQLONLY > ..\..\..\Result48.txt +cd %CURRENTDIR% + +@echo -------------------------------------------------- +@echo Test the TestDataAccessCore(100). +@echo -------------------------------------------------- +set CURRENTDIR=%cd% +cd "Frameworks\Tests\TestDataAccess\core100\bin\Debug\net10.0" +dotnet "TestDataAccessCore.dll" -- /MODE SQLONLY > ..\..\..\..\ResultCore100.txt +cd %CURRENTDIR% + +pause + +rem ------------------------------------------------------- +endlocal diff --git a/root/programs/CS/y_Build_TestCode_Public.bat b/root/programs/CS/y_Build_TestCode_Public.bat index de5e2cbda..799bab923 100644 --- a/root/programs/CS/y_Build_TestCode_Public.bat +++ b/root/programs/CS/y_Build_TestCode_Public.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -18,11 +18,11 @@ call %CURRENT_DIR%z_Common.bat @rem -------------------------------------------------- @rem Batch build of TestCode. @rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Tests\TestCode\TestCodeFx48.sln" +..\nuget.exe restore "Frameworks\Tests\TestCode\TestCodeFx48.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Tests\TestCode\TestCodeFx48.sln" -dotnet restore "Frameworks\Tests\TestCode\TestCodeCore80.sln" -dotnet msbuild %COMMANDLINE% "Frameworks\Tests\TestCode\TestCodeCore80.sln" +dotnet restore "Frameworks\Tests\TestCode\TestCodeCore100.sln" +dotnet msbuild %COMMANDLINE% "Frameworks\Tests\TestCode\TestCodeCore100.sln" @echo -------------------------------------------------- @echo Test the TestCodeFx(48). diff --git a/root/programs/CS/y_Build_TestCode_SecCUI.bat b/root/programs/CS/y_Build_TestCode_SecCUI.bat index a3ddb87b5..3b237e051 100644 --- a/root/programs/CS/y_Build_TestCode_SecCUI.bat +++ b/root/programs/CS/y_Build_TestCode_SecCUI.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -23,7 +23,7 @@ cd "Frameworks\Tests\EncAndDecUtilCUI" call copy_cert.bat cd %CURRENTDIR% -..\nuget.exe restore "Frameworks\Tests\EncAndDecUtilCUI\EncAndDecUtilCUIFx48.sln" +..\nuget.exe restore "Frameworks\Tests\EncAndDecUtilCUI\EncAndDecUtilCUIFx48.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Tests\EncAndDecUtilCUI\EncAndDecUtilCUIFx48.sln" dotnet restore "Frameworks\Tests\EncAndDecUtilCUI\EncAndDecUtilCUICore100.sln" diff --git a/root/programs/CS/y_Build_TestCode_SecGUI.bat b/root/programs/CS/y_Build_TestCode_SecGUI.bat index 46ee8d078..55eb45e16 100644 --- a/root/programs/CS/y_Build_TestCode_SecGUI.bat +++ b/root/programs/CS/y_Build_TestCode_SecGUI.bat @@ -1,4 +1,4 @@ -setlocal +setlocal @rem -------------------------------------------------- @rem Turn off the echo function. @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of EncAndDecUtil. rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Tests\EncAndDecUtil\EncAndDecUtil48.sln" +..\nuget.exe restore "Frameworks\Tests\EncAndDecUtil\EncAndDecUtil48.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Tests\EncAndDecUtil\EncAndDecUtil48.sln" pause diff --git a/root/programs/CS/z_Common.bat b/root/programs/CS/z_Common.bat index 7646fdcb0..3ec2290c2 100644 --- a/root/programs/CS/z_Common.bat +++ b/root/programs/CS/z_Common.bat @@ -1,12 +1,18 @@ @rem -------------------------------------------------- @rem Execution of the common processing. +@rem +@rem NOTE: keep this file pure ASCII (#532). +@rem +@rem cmd.exe reads a batch file by byte offset. Non-ASCII text is decoded +@rem with the console code page, which can misalign the parser and make it +@rem execute the tail of an @rem line as a command. A UTF-8 BOM reduces +@rem this but does not prevent it, and "chcp 65001" inside the file makes +@rem it worse by changing the code page half way through. +@rem +@rem This file is called by every build batch, so it is kept ASCII only. +@rem chcp is not used here; a caller that needs UTF-8 output sets it up. @rem -------------------------------------------------- -@rem -------------------------------------------------- -@rem 文字化け対策 -@rem -------------------------------------------------- -chcp 65001 - @rem -------------------------------------------------- @rem Specifying Build tool. @rem -------------------------------------------------- @@ -51,26 +57,143 @@ echo BUILDFILEPATH4.0 %BUILDFILEPATH4.0% echo BUILDFILEPATH15 %BUILDFILEPATH15% echo BUILDFILEPATH16 %BUILDFILEPATH16% echo BUILDFILEPATH17 %BUILDFILEPATH17% -echo BUILDFILEPATH17 %BUILDFILEPATH18% +echo BUILDFILEPATH18 %BUILDFILEPATH18% + +@rem -------------------------------------------------- +@rem Resolve MSBuild with vswhere, independently of the VS edition. +@rem The fixed paths above only look for Community, so this also finds +@rem Professional / Enterprise / BuildTools. +@rem -------------------------------------------------- +set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +set BUILDFILEPATH= + +if exist %VSWHERE% ( + for /f "usebackq tokens=*" %%i in ( + `%VSWHERE% -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe` + ) do set BUILDFILEPATH="%%i" +) + +@rem -------------------------------------------------- +@rem Fallback, for when vswhere is missing or resolves nothing. +@rem -------------------------------------------------- +if not defined BUILDFILEPATH set BUILDFILEPATH=%BUILDFILEPATH18% +if not defined BUILDFILEPATH set BUILDFILEPATH=%BUILDFILEPATH17% +if not defined BUILDFILEPATH set BUILDFILEPATH=%BUILDFILEPATH16% -set BUILDFILEPATH=%BUILDFILEPATH18% echo BUILDFILEPATH %BUILDFILEPATH% +@rem -------------------------------------------------- +@rem Stop when nothing was found. +@rem Carrying on with an empty value makes "/p:Configuration=..." run as +@rem the command itself, which is hard to diagnose. +@rem -------------------------------------------------- +if not defined BUILDFILEPATH ( + echo [ERROR] MSBuild.exe was not found. + echo Check the Visual Studio or Build Tools installation. + exit /b 1 +) + +@rem -------------------------------------------------- +@rem The MSBuild passed to nuget.exe restore. +@rem +@rem nuget.exe detects MSBuild on its own, but when another product that +@rem ships MSBuild is installed - SQL Server Management Studio, say - it +@rem can pick that one instead. +@rem e.g. "Using MSBuild version ... from 'C:\Program Files\Microsoft SQL +@rem Server Management Studio 22\Release\MSBuild\Current\bin'." +@rem +@rem That MSBuild has no Microsoft.WebApplication.targets for web apps, and +@rem the project.assets.json it writes does not match the real build, so +@rem errors like these follow. +@rem error MSB4226: The imported project "...WebApplications\ +@rem Microsoft.WebApplication.targets" was not found. +@rem error : Your project file doesn't list 'win' as a "RuntimeIdentifier". +@rem +@rem The folder resolved above is therefore passed explicitly. +@rem -------------------------------------------------- +for %%i in (%BUILDFILEPATH%) do set MSBUILDDIR=%%~dpi + +@rem Strip the trailing backslash. In -MSBuildPath "...\" the \" would be +@rem read as an escape and the argument would break. +if defined MSBUILDDIR set MSBUILDDIR=%MSBUILDDIR:~0,-1% + +set NUGET_MSBUILD=-MSBuildPath "%MSBUILDDIR%" + +echo NUGET_MSBUILD %NUGET_MSBUILD% + @echo -------------------------------------------------- @echo The choice of build configuration (Debug / Release). -@echo BUILD_CONFIG は 特定の構成(Debug や Release)を指定 -@echo DEBUG_TYPE は full, pdbonly, portable, embedded, none -@echo https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/compiler-options/code-generation#debugtype +@echo BUILD_CONFIG names the configuration (Debug or Release). +@echo DEBUG_TYPE is full, pdbonly, portable, embedded or none. +@echo https://learn.microsoft.com/dotnet/csharp/language-reference/compiler-options/code-generation#debugtype @echo -------------------------------------------------- set BUILD_CONFIG=Debug -set DEBUG_TYPE=full -set VisualStudioVersion=18.0 + +@rem -------------------------------------------------- +@rem DEBUG_TYPE honours the value the caller has already set (#531). +@rem +@rem The build for the NuGet packages (0_Release4Nuget.bat) needs portable. +@rem - a .snupkg is only accepted when the PDB is portable +@rem - the Source Link information also lives in the portable PDB +@rem This line used to be edited by hand and reverted afterwards. Forgetting +@rem the revert meant publishing with "full", so the caller passes it now. +@rem -------------------------------------------------- +if not defined DEBUG_TYPE set DEBUG_TYPE=full + +@rem -------------------------------------------------- +@rem CI_BUILD likewise honours the value the caller has already set (#531). +@rem +@rem true turns on ContinuousIntegrationBuild, which normalizes the source +@rem paths recorded in the PDB to /_/... . +@rem - the published package no longer carries the local paths of the +@rem machine that built it +@rem - Visual Studio opens the file at the path in the PDB when it exists, +@rem so an absolute path means Source Link is never used on the build +@rem machine. Normalizing lets it be verified there as well. +@rem +@rem Off for ordinary builds. Only the build for the NuGet packages +@rem (0_Release4Nuget.bat) passes true. +@rem +@rem DeterministicSourcePaths is passed as well. The conversion from +@rem ContinuousIntegrationBuild is done by the Microsoft.NET.Sdk targets, +@rem so it does not reach the old-style projects - the same shape as Source +@rem Link not being picked up automatically. Without it, only the net48 +@rem side keeps absolute paths. +@rem -------------------------------------------------- +if not defined CI_BUILD set CI_BUILD=false + +@rem -------------------------------------------------- +@rem VisualStudioVersion comes from the same VS as the MSBuild resolved +@rem above. +@rem +@rem A web app csproj builds its targets path from this value. +@rem $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) +@rem +@rem +@rem A fixed value breaks on a machine that only has another VS version. +@rem e.g. windows-latest on GitHub Actions is VS 2022 = 17.x, so passing +@rem 18.0 makes it look for v18.0\WebApplications\ and fail MSB4226. +@rem -------------------------------------------------- +set VSVER_MAJOR= + +if exist %VSWHERE% ( + for /f "usebackq tokens=1 delims=." %%i in ( + `%VSWHERE% -latest -products * -requires Microsoft.Component.MSBuild -property installationVersion` + ) do set VSVER_MAJOR=%%i +) + +@rem Fall back to the previous value when vswhere is missing or resolves +@rem nothing. +if not defined VSVER_MAJOR set VSVER_MAJOR=18 + +set VisualStudioVersion=%VSVER_MAJOR%.0 +echo VisualStudioVersion %VisualStudioVersion% @echo -------------------------------------------------- @echo Creating a build command. @echo -------------------------------------------------- @set COMMANDLINE=/p:Configuration=%BUILD_CONFIG% -v:d -set COMMANDLINE=/p:Configuration=%BUILD_CONFIG% /p:DebugType=%DEBUG_TYPE% -v:d +set COMMANDLINE=/p:Configuration=%BUILD_CONFIG% /p:DebugType=%DEBUG_TYPE% /p:ContinuousIntegrationBuild=%CI_BUILD% /p:DeterministicSourcePaths=%CI_BUILD% -v:d @echo -------------------------------------------------- @echo Set the proxy settings of Nuget. diff --git a/root/programs/CS/z_Common2.bat b/root/programs/CS/z_Common2.bat index 4aa58775c..4d9da6253 100644 --- a/root/programs/CS/z_Common2.bat +++ b/root/programs/CS/z_Common2.bat @@ -1,7 +1,28 @@ -@rem -------------------------------------------------- +@rem -------------------------------------------------- @rem Execution of the common processing. @rem -------------------------------------------------- +@rem ************************************************** +@rem [経緯] 本バッチは z_Common.bat の devenv 版である。 +@rem MSBuild.exe ではエラーになるが devenv.com では通る、という +@rem ケースが散在していた時期に、ビルド ツールを devenv.com へ +@rem 差し替えるために用意された。 +@rem z_Common.bat と同じインターフェイス(%BUILDFILEPATH% と +@rem %COMMANDLINE%)を提供するため、呼び出し側の bat は +@rem call するファイルを差し替えるだけで切り替えられる。 +@rem ※ そのため COMMANDLINE は devenv 構文の "/build <構成>" であり、 +@rem MSBuild 構文の "/p:Configuration=<構成>" ではない。 +@rem +@rem [注意] 現在は未使用であり、かつこのままでは動作しない。 +@rem ・リポジトリ内に z_Common2.bat を呼び出すバッチは存在しない。 +@rem ・"set BUILDFILEPATH10.0 =..." は "=" の前に空白があるため、 +@rem 変数名に末尾の空白が含まれてしまう。 +@rem ・"set BUILDFILEPATH=BUILDFILEPATH10.0" は "%" が抜けているため、 +@rem パスではなく文字列そのものを代入している。 +@rem 通常は z_Common.bat(MSBuild 版)を使用すること。 +@rem 再び devenv でのビルドが必要になった場合は、上記を修正したうえで使用する。 +@rem ************************************************** + @rem -------------------------------------------------- @rem Set Program Files path @rem -------------------------------------------------- diff --git a/root/programs/CompareResult.ps1 b/root/programs/CompareResult.ps1 new file mode 100644 index 000000000..86b52c054 --- /dev/null +++ b/root/programs/CompareResult.ps1 @@ -0,0 +1,188 @@ +<# +.SYNOPSIS + 単体テストの実行結果を、同梱の期待結果ファイルと比較して合否を判定する。 + +.DESCRIPTION + 従来「diff で目視」していた判定を機械化するためのスクリプト。 + + 期待結果ファイルと実行結果には、実行のたびに変わる値(日時・処理時間・乱数・ + 署名値・パス等)が含まれるため、素の diff では必ず差分が出る。 + 本スクリプトはそれらを正規化したうえで比較し、残った差分だけを報告する。 + + 正規化しても残る差分は「実質的な差分」であり、次のいずれかを意味する。 + ・退行(コードの不具合) + ・期待結果ファイルの陳腐化 + ・テスト データの汚染(DB のレコードが増減している等) + +.PARAMETER Expected + 期待結果ファイルのパス。 + +.PARAMETER Actual + 実行結果ファイルのパス。 + +.PARAMETER SkipLog4netTrace + log4net の内部トレース("log4net: " で始まる行)を比較対象から除外する。 + 設定内容の確認が目的でなければ、除外した方が判定が読みやすい。 + +.PARAMETER ShowAll + 差分の全件を表示する(既定は先頭 20 件)。 + +.EXAMPLE + .\CompareResult.ps1 -Expected TestCode\Result48.txt -Actual out\TestCode48.txt + +.EXAMPLE + .\CompareResult.ps1 -Expected TestBatch\ResultSimpleBatch48.txt ` + -Actual out\TestBatch48.txt -SkipLog4netTrace + +.NOTES + 作成者 :玄人 幸道 + 更新履歴 : + 日時 更新者 内容 + ---------- ---------------- ------------------------------------------------- + 2026/08/01 玄人 幸道 新規作成(リリース ワークのエージェント化) + 2026/08/05 玄人 幸道 OSメッセージの正規化を追加(CI の英語環境への対応) +#> +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)][string]$Expected, + [Parameter(Mandatory = $true)][string]$Actual, + [switch]$SkipLog4netTrace, + [switch]$ShowAll, + # 判定結果をオブジェクトとして出力する(呼び出し元での集計用)。 + # 画面表示は Write-Host で行っておりパイプラインに乗らないため、 + # 件数を機械的に受け取りたい場合はこれを指定する。 + [switch]$PassThru +) + +# ------------------------------------------------------------------ +# 正規化ルール +# ------------------------------------------------------------------ +# 実行のたびに変わる値を、比較前にプレースホルダへ置き換える。 +# ここに無いものが差分として残る=実質的な差分、という設計。 +$normalizers = @( + # 日時(log4net の ConversionPattern : yyyy/MM/dd HH:mm:ss,fff) + @{ Name = '日時'; Pattern = '\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2},\d{3}'; Replace = '' } + # 日時(Dao 生成物のヘッダ等 : yyyy/M/d) + @{ Name = '日付'; Pattern = '\d{4}/\d{1,2}/\d{1,2}'; Replace = '' } + # 処理時間(フレームワークのアクセス ログ) + # ※ net48 は 2 項目、.NET (Core) は 2 項目目が空になることがあるため、 + # 「数値,数値」「数値,」の両方を吸収する。 + @{ Name = '処理時間'; Pattern = '(?<=\],)\d+,\d*(?=,\[commandText\])'; Replace = '' } + @{ Name = '処理時間(末尾)'; Pattern = '(?<=%-?,)\d+,\d*\s*$'; Replace = '' } + # 絶対パス(実行環境に依存する) + @{ Name = 'パス'; Pattern = '[A-Za-z]:\\\\[^\s,]+'; Replace = '' } + @{ Name = 'パス(単一)'; Pattern = '[A-Za-z]:\\[^\s,]+'; Replace = '' } + # OS が返すエラー文字列(Windows の表示言語で変わる) + # ※ .NET の CurrentUICulture ではなく OS の表示言語に従うため、設定では固定できない。 + #   開発環境は日本語、GitHub ホステッドの runner は英語になる。 + # ※ 例外が起きたこと自体は「行の存在」で分かるため、文言だけを潰す。 + #   行ごと落とすと、例外が起きなくなったときに検知できない。 + @{ Name = 'OSメッセージ' + Pattern = 'キーがありません。|Key does not exist\.|プロバイダーの公開キーは無効です。|Provider''s public key is invalid\.' + Replace = '' } + # GUID + @{ Name = 'GUID'; Pattern = '[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}'; Replace = '' } + # XML 署名の値(要素で囲まれているため、先に要素単位で潰す) + # ※ 値そのものは Base64 だが、実行のたびに変わるうえ改行を含まないため + # 汎用の Base64 パターンより先に処理する。 + @{ Name = 'XML署名値'; Pattern = '<(SignatureValue|DigestValue|Modulus|Exponent)>[^<]*'; Replace = '<$1>' } + # Base64URL の長い値(JWT・署名・鍵・IV・認証タグ等) + @{ Name = 'Base64URL'; Pattern = '[A-Za-z0-9_\-]{16,}'; Replace = '' } + # Base64 の長い値(鍵・ハッシュ等) + @{ Name = 'Base64'; Pattern = '[A-Za-z0-9+/]{16,}={0,2}'; Replace = '' } + # スレッド ID(実行ごとに変わり得る) + @{ Name = 'スレッドID'; Pattern = '(?<=\],)\[\d+\](?=,)'; Replace = '[]' } +) + +function Normalize([string[]]$lines) +{ + $result = New-Object System.Collections.Generic.List[string] + + foreach ($line in $lines) + { + $s = $line + + if ($SkipLog4netTrace -and $s -match '^log4net: ') + { + continue + } + + if ($s.Trim() -eq '') + { + continue + } + + # 非対話実行の副産物を除外する。 + # サンプルは末尾に Console.ReadKey() を持つものがあり、 + # 出力をリダイレクトして実行すると必ず例外で終わる。 + # テスト内容とは無関係なため、比較対象から外す。 + if ($s -match 'Cannot read keys when either application does not have a console' ` + -or $s -match 'ConsolePal\.ReadKey' ` + -or $s -match 'Exception\.ToString\(\) が失敗したため' ` + -or $s -match '^Unhandled exception\.' ` + -or $s -match '^\s+at .+\.Program\.Main\(') + { + continue + } + + foreach ($n in $normalizers) + { + $s = [regex]::Replace($s, $n.Pattern, $n.Replace) + } + + $result.Add($s.TrimEnd()) + } + + return , $result.ToArray() +} + +# ------------------------------------------------------------------ +# 比較 +# ------------------------------------------------------------------ +if (-not (Test-Path $Expected)) { Write-Error "期待結果ファイルが見つかりません : $Expected"; exit 2 } +if (-not (Test-Path $Actual)) { Write-Error "実行結果ファイルが見つかりません : $Actual"; exit 2 } + +# 読み込みは UTF-8 を明示する。 +# 比較対象の *.txt は BOM 無しの UTF-8 だが、Get-Content の既定エンコードは +# PowerShell のエディションで異なる。 +# Windows PowerShell 5.1 … ANSI(日本語環境では Shift_JIS) +# PowerShell 7 … UTF-8 +# 指定しないと 5.1 だけ文字化けし、同じファイルなのに差分が出る。 +$expLines = Normalize (Get-Content $Expected -Encoding UTF8) +$actLines = Normalize (Get-Content $Actual -Encoding UTF8) + +$diff = @(Compare-Object $expLines $actLines -SyncWindow 20) + +Write-Host "" +Write-Host "=== 比較結果 ===" +Write-Host (" 期待 : {0} ({1} 行)" -f $Expected, $expLines.Count) +Write-Host (" 実測 : {0} ({1} 行)" -f $Actual, $actLines.Count) +Write-Host "" + +if ($diff.Count -eq 0) +{ + Write-Host " OK : 正規化後の差分はありません。" -ForegroundColor Green + if ($PassThru) { [pscustomobject]@{ Result = "OK"; DiffCount = 0 } } + exit 0 +} + +Write-Host (" NG : 正規化後も {0} 件の差分があります。" -f $diff.Count) -ForegroundColor Yellow +Write-Host " 退行/期待結果の陳腐化/テスト データの汚染のいずれかを確認してください。" +Write-Host "" + +$show = if ($ShowAll) { $diff } else { $diff | Select-Object -First 20 } +foreach ($d in $show) +{ + $mark = if ($d.SideIndicator -eq '<=') { '期待のみ' } else { '実測のみ' } + $text = $d.InputObject + if ($text.Length -gt 160) { $text = $text.Substring(0, 160) + ' ...' } + Write-Host (" [{0}] {1}" -f $mark, $text) +} + +if (-not $ShowAll -and $diff.Count -gt 20) +{ + Write-Host (" ... 他 {0} 件(全件表示は -ShowAll)" -f ($diff.Count - 20)) +} + +if ($PassThru) { [pscustomobject]@{ Result = "NG"; DiffCount = $diff.Count } } +exit 1 diff --git a/root/programs/RELEASE.md b/root/programs/RELEASE.md new file mode 100644 index 000000000..3de3df9f4 --- /dev/null +++ b/root/programs/RELEASE.md @@ -0,0 +1,383 @@ +# RELEASE.md — リリース チェックリスト + +対象: `root/programs/CS`(C# 側) +配置: `root/programs` +本書は、リリース時に何を・どの順で確認し、**どこまでを機械が行い、どこからを人が行うか**を 1 枚にまとめたもの。 + +> **一次情報は本書ではない。** 迷ったら次を見ること。 +> +> | 内容 | 一次情報 | +> |---|---| +> | ビルド構成・バージョン管理 | [`CS/Frameworks/ANALYSIS.md`](CS/Frameworks/ANALYSIS.md) 7 章 | +> | 全ビルドの実行と判定 | [`BUILDING.md`](BUILDING.md) | +> | 単体テストの実行と判定 | [`TESTING.md`](TESTING.md) | +> | サンプルの疎通確認 | [`SMOKETEST.md`](SMOKETEST.md) | +> | NuGet パッケージ化・公開の手順 | [`CS/NuGet/README.md`](CS/NuGet/README.md) | + +--- + +## 1. 全体の流れ + +| # | フェーズ | 手段 | 実施者 | +|---|---|---|---| +| 0 | 準備 | 手作業 | 人(エージェントは充足状況の確認・報告まで) | +| 1 | 検証(ビルド・単体テスト・疎通) | `1_BuildAll.ps1` / `2_RunAllTests.ps1` / `3_SmokeTest.ps1` | **エージェント可** | +| 2 | 検証(UI 系・ツール) | 手作業(GUI 操作) | 人(自動化は見送り。7 節) | +| 3 | パッケージ化 | `CS\0_Release4Nuget.bat` → `_NuGetPack.bat` | エージェント可(**指示があれば**) | +| 4 | 公開 | `_NuGetPush.bat` + Wiki 手順 | **人のみ** | +| 5 | 後始末 | 手作業 | 人(エージェントは差分の報告まで) | + +### エージェントが実行してよい範囲 + +**取り消しにくい・外部に出る・システム設定を変えるものは人が行う。** + +この線引きは `AGENTS.md`(git 操作をしない/公開リポジトリへの投稿は承認を得てから)と同じ考え方。 + +| 人が行うフェーズ | 人が行う理由 | +|---|---| +| 0 準備 | `Start-Service` `aspnet_state` は**システム設定の変更**。DB の初期化も同様。
    エージェントは不足を検知して**対処方法とともに報告する**に留める | +| 2 検証(UI 系) | GUI 操作のため | +| 4 公開 | `_NuGetPush.bat` は**外部公開で取り消しが困難**。かつ API キーを扱う | +| 5 後始末 | revert の確定はワーキング ツリーの検収と同じ扱い | + +フェーズ 1 をエージェントが実行してよいのは、**失敗しても被害が無く、結果がワーキング ツリーに残るだけ**だから。 + +フェーズ 3 は成果物をローカルに作るだけだが、`CS\z_Common.bat` の `DEBUG_TYPE` 変更を伴い、 +フェーズ 4 と地続きのため、**指示があったときだけ**実行する。 + +**フェーズ 1 は 3 本を順に実行するだけで済む。** + +```powershell +cd root\programs +.\1_BuildAll.ps1 # 全ビルド +``` + +```powershell +.\2_RunAllTests.ps1 # 単体テスト +``` + +```powershell +.\3_SmokeTest.ps1 # サンプルの疎通 +``` + +クリーン ビルドから通しで **約 9.5 分**。 +`2_RunAllTests.ps1` と `3_SmokeTest.ps1` は終了コードだけで合否が分かるが、 +`1_BuildAll.ps1` は既知の署名エラーで 1 になるため、内容の確認が要る(3 節)。 + +--- + +## 2. フェーズ 0 : 準備 + +### 環境 + +- [ ] **Visual Studio を閉じた** + … `1_DeleteDir.bat` が `.vs` を削除するため +- [ ] **SQL Server の Northwind に接続できる** +- [ ] **Northwind が初期状態**(`Shippers` 3 件 / `Orders` 830 件) + … 汚れている場合の戻し方は [`TESTING.md`](TESTING.md) 「テスト データの戻し方」 + … `Orders2`(Northwind 標準ではない)は `3_SmokeTest.ps1` が無ければ作るため、事前準備は不要 +- [ ] **サービスが開始されている**(`Start-Service`、`aspnet_state`、要管理者権限) + - Start-Service … アプリが 使うデータストア(Dockerコンテナ)を起動、初期化する。 + - aspnet_state … net48 の Web アプリが使うASP.NET 状態サービスを起動する。 +- [ ] **IIS Express がインストールされている** + +### バージョン番号 + +- [ ] **`0_SetVersion.ps1` でバージョンを更新した** + + ```powershell + cd root\programs + .\0_SetVersion.ps1 -Version 3.3.0-alpha1 -WhatIf # 変更内容の確認 + .\0_SetVersion.ps1 -Version 3.3.0-alpha1 # 実行 + ``` + + … **バージョンの定義箇所は 2 系統に分かれており、手作業では追随を忘れやすい**ため、 + 一括で更新する(#531) + + | 更新先 | 書き込む値 | + |---|---| + | `CS/Frameworks/Infrastructure/Directory.Build.props` の `OpenTouryoVersion` | `3.3.0-alpha1`(指定値そのまま) | + | net48 6 本の `Properties\AssemblyInfo.cs` の `AssemblyVersion` | `3.3.0.0`(サフィックスを落とし 4 桁目に `0`) | + + … net48 の対象は**パッケージに入る 6 本**。 + `DamPstGrS` は net48 が無く、`Business` は非パッケージかつ別系統のため対象外 + + ``` + Public / Public.Security / Framework / Framework.RichClient + Public\Db\DamManagedOdp / Public\Db\DamMySQL + ``` + + … **該当行が見つからなければ NG で停止する**(黙って素通りさせない)。 + 同じ版で再実行しても「変更なし」になる +- [ ] **`Business` 系は 1.0.0 のまま**であることを確認した + … 意図的に別系統。`0_SetVersion.ps1` は触らない +- [ ] **nuspec の `` が csproj の `PackageReference` と一致している** + … 依存を増減したら nuspec 側も合わせる。相互依存の版は `$version$` で自動追随 + +> **プレリリース版は、サフィックス付きで指定する**(`3.3.0-alpha1`)。 +> サフィックスは `OpenTouryoVersion` にだけ入り、**アセンブリの版には入らない。** +> SDK 形式 csproj の `` も、`AssemblyVersion` / `FileVersion` には +> `VersionPrefix`(`3.3.0`)を、`InformationalVersion` には全体を割り当てる。 +> その挙動に合わせてある。 +> +> [`CS/NuGet/README.md`](CS/NuGet/README.md) 1 節(0)の +> 「α・β版などを使用して 2 回以上繰り返す」は、次のように回す。 +> +> ```powershell +> .\0_SetVersion.ps1 -Version 3.3.0-alpha1 # プレ公開(develop 段階) +> .\0_SetVersion.ps1 -Version 3.3.0 # 本番(master マージ+タグ後) +> ``` + +> **`OpenTouryoVersion` はアセンブリに焼き込まれる。** +> `*_netcore100.csproj` が `$(OpenTouryoVersion)` で参照するため、 +> **書き換えたら必ずリビルド(フェーズ 3 の `0_Release4Nuget.bat`)が要る。** +> 先にパッケージ化すると、古いアセンブリに新しい版番号が付く。 + +> **`_NuGetPack.bat` が、net48 の `AssemblyVersion` と `OpenTouryoVersion` の +> 一致を検査して、ずれていれば停止する**(#531)。 +> 追随を忘れたまま公開すると、**同じパッケージの net48 と net10.0 で +> アセンブリの版が食い違い、公開後には直せない。** +> +> ``` +> NG Public : 3.0.0 expected 3.1.0 +> [ERROR] The net48 AssemblyVersion does not match 3.1.0 +> ``` +> +> **`0_SetVersion.ps1` を使っていれば、この検査に引っかかることはない。** +> 手で書き換えた場合や、片方だけ revert した場合の保険である。 + +> **`_NuGetPack.bat` は、詰めたアセンブリの版も検査する**(#531)。 +> 上の検査は**ソースどうしを突き合わせているだけ**なので、 +> `0_SetVersion.ps1` の後に `0_Release4Nuget.bat` を飛ばしても通ってしまう。 +> `in\` へ複製した後の**実際の DLL** を見て、ずれていれば停止する。 +> +> ``` +> NG in\net48\OpenTouryo.Public.dll : 3.3.0.0 expected 3.4.0.x +> [ERROR] The packaged assemblies do not carry 3.4.0 +> so the rebuild was skipped. Run CS\0_Release4Nuget.bat, +> ``` +> +> **`_T_NuGetPack.bat`(テスト用)には、この検査は無い。** +> テスト用パッケージは版を**引数で受け取り**、`OpenTouryoVersion` を読まない。 +> 版はパッケージに名前を付けるだけで、**アセンブリには書き込まれない**ため、 +> 食い違いようがない。 + +> **補足 : パッケージの版とアセンブリの版は、一致しなくてよい**(NuGet の制約ではなく慣習)。 +> テスト公開した `Erutcurtsarfni.Oyruot.Public 3.3.0-alpha2` は、 +> パッケージが `3.3.0-alpha2`、中の DLL が `3.0.0.0` で、正常に動作した。 +> +> **検査が見ているのは、パッケージの版とアセンブリの版の一致ではなく、 +> 同じパッケージに入る net48 と net10.0 のアセンブリどうしが揃っているか**である。 + +> `Directory.Build.props` の XML コメントに `--`(ハイフン 2 個)を書くと +> MSBuild がプロジェクトの読み込みに失敗する。区切り線に使わないこと。 + +--- + +## 3. フェーズ 1 : 検証(自動) + +| スクリプト | 見るもの | 期待値 | 文書 | +|---|---|---|---| +| `1_BuildAll.ps1` | ビルドが通るか | エラー 0 件 | [`BUILDING.md`](BUILDING.md) | +| `2_RunAllTests.ps1` | 出力が前回と同じか | HEAD の `Result*.txt` | [`TESTING.md`](TESTING.md) | +| `3_SmokeTest.ps1` | 起動して想定どおり動くか | 定義側の判定条件 | [`SMOKETEST.md`](SMOKETEST.md) | + +- [ ] **`1_BuildAll.ps1` のエラーが「既知の 1 件」だけである** + … `-SkipClean` は**使わない**。前回の成果物が残っていると通ったように見える +- [ ] **`2_RunAllTests.ps1` が終了コード 0**(8 ケース) +- [ ] **`3_SmokeTest.ps1` が終了コード 0**(22 件) + +> **`1_BuildAll.ps1` は現状ここで終了コード 1 になる。** +> `WSClnt_sample (net48)` の ClickOnce 署名エラー(`MSB3482`)が残るため。 +> **終了コードだけで判断せず、エラー一覧が下記 1 件だけであることを確認すること**(4 節)。 +> +> ``` +> [WSClnt_sample (net48)] ... error MSB3482: 署名中にエラーが発生しました: +> ... WSClientWinCone_sample.exe の署名に失敗しました。 +> SignTool Error: No certificates were found that met all the given criteria. +> ``` +> +> 証明書をストアに入れた環境では 0 になる。 +> +> `-IgnoreErrors "MSB3482"` を付けると判定から外れて 0 になる(除外内容は一覧に残る)。 +> **リリース判定では付けないこと。** 目視で 1 件だけであることを確かめるのが本筋で、 +> この引数は人が見ない CI([`BUILDING.md`](BUILDING.md) 9 節)のためのもの。 + +所要時間の実測(クリーン ビルドから通しで **約 9.5 分**)。 + +| スクリプト | 所要 | +|---|---| +| `1_BuildAll.ps1`(31 ステップ) | 5.8 分 | +| `2_RunAllTests.ps1`(8 ケース) | 1.3 分 | +| `3_SmokeTest.ps1`(22 件) | 2.3 分 | + +### 順序を守る + +**`1_BuildAll.ps1` → `2_RunAllTests.ps1` → `3_SmokeTest.ps1` の順で行う。** +`1_BuildAll.ps1` はクリーンを行い、`4_Build_CopyAssemblies.bat` がテストとサンプルの +参照先(`Build_net48` / `Build_netcore100`)を更新するため、 +逆順では古いアセンブリを見ることになる。 + +### NG が出たときの切り分け + +| スクリプト | NG の意味 | +|---|---| +| `1_BuildAll.ps1` | コンパイル エラー、または restore の失敗 | +| `2_RunAllTests.ps1` | 退行/期待結果の陳腐化/**テスト データの汚染**のいずれか | +| `3_SmokeTest.ps1` | 起動時の失敗(構成・ネイティブ DLL・前提サービス)が多い | + +`2_RunAllTests.ps1` の「実測のみ/期待のみ」に**件数の差**が出た場合は、 +まずテスト データの汚染を疑う(`TESTING.md` 5 節)。 + +### `Result*.txt` の扱い + +`2_RunAllTests.ps1` はワーキング ツリーの `Result*.txt` を書き換える(従来のバッチ運用と同じ)。 + +**この生 diff を目視してはいけない。** 実行日時が全行に入るため、 +内容が同じでも**ほぼ全行が差分になる**。実測では 6 ファイルで約 2,458 行。 + +```diff +-[2025/11/18 15:19:08,286],[INFO ],[1],,,,----->>,... ++[2026/08/01 22:40:19,772],[INFO ],[1],,,,----->>,... +``` + +**判定は `2_RunAllTests.ps1` の「正規化後の差分」で行う。** それが 0 なら内容は同じ。 +生 diff を読むのは、正規化後に差分が出たときだけでよい。 + +- [ ] 正規化後の差分が 0 であることを確認した +- [ ] `Result*.txt` をコミットするかどうかを判断した + … 内容が変わっていないなら**コミットしなくてよい**(日時だけの差分が積み上がるため)。 + 仕様変更で内容が変わった場合は、新しい基準としてコミットする + +--- + +## 4. フェーズ 2 : 検証(手作業) + +自動化から外した対象。**起動して主要な画面が出ることを確認する。** + +### UI 系サンプル(18 本) + +| 区分 | net48 | net10.0 | +|---|---|---| +| 2 層 C/S | `2CSClientWin_sample`
    `2CSClientWPF_sample`
    `AsyncEvent_sample`
    `CustCtrl_sample`
    `GenDaoAndBatUpd_sample`
    `TimeStamp_sample` | `2CSClientWin_sample`
    `2CSClientWPF_sample`
    `CustCtrl_sample`
    `GenDaoAndBatUpd_sample`
    `TimeStamp_sample` | +| WS クライアント | `WSClientWin_sample`
    `WSClientWPF_sample`
    `WSClientWin2_sample`
    `WSClientWinCone_sample` | `WSClientWin_sample`
    `WSClientWPF_sample`
    `WSClientWin2_sample` | + +- [ ] 2 層 C/S 系(net48 6 本 / net10.0 5 本)が起動し、CRUD 画面が操作できる +- [ ] WS クライアント系(net48 4 本 / net10.0 3 本)が起動する + +> **WS クライアントの疎通には別リポジトリが要る。** +> 呼び先の Web サービスは +> [`OpenTouryoProject/ResourceServerTemplates`](https://github.com/OpenTouryoProject/ResourceServerTemplates) +> へ移設済みで、本リポジトリだけでは接続先が無い。 + +### フレームワーク付属ツール + +| ツール | 確認内容 | +|---|---| +| `DaoGen_Tool`(墨壺) | **GUI 起動のみ**。CUI(`/HELP` `/CUI /MODE ...`)は `3_SmokeTest.ps1` が網羅済み | +| `DPQuery_Tool` | GUI 起動 | +| `EncAndDecUtil` | GUI 起動(CUI 版は `2_RunAllTests.ps1` が網羅済み) | +| `DeployZipPackWithHTTP` | GUI 起動 + **圧縮・解凍**(ZIP 部品の唯一の利用者。#528) | + +- [ ] `DaoGen_Tool` が GUI で起動し、D 層定義・SQL が生成できる + … 生成ロジック自体は CUI 側で自動確認済み。ここで見るのは **GUI が動くこと** +- [ ] `DPQuery_Tool` が GUI で起動する +- [ ] `EncAndDecUtil` が GUI で起動する +- [ ] `DeployZipPackWithHTTP` が GUI で起動し、**圧縮と解凍ができる** + … `ZipperV2` / `UnZipperV2` を使う唯一の利用者。ZIP 部品を変えたら必ず見ること。 + 設定と履歴は `current.json` / `histories.json`(旧 `.bin` は読まない) + +### 既知の環境依存(NG でも可) + +- [ ] `WSClientWinCone_sample` の ClickOnce 署名エラー(`MSB3482`)を確認した + … 拇印で証明書ストアを検索するため、当該証明書が無い環境ではビルドできない。 + **環境依存でありコード側の不具合ではない**([`BUILDING.md`](BUILDING.md) 4 節) + +--- + +## 5. フェーズ 3・4 : パッケージ化と公開 + +手順の一次情報は [`CS/NuGet/README.md`](CS/NuGet/README.md)。 +**ここに書き写すと二重管理になるため、要点と抜けやすい点だけを挙げる。** + +- [ ] **正式版は、`develop` → `master` をマージ(`--no-ff`)し、タグを打った後に詰めた** + … パッケージは**詰めた時のコミットに永久に固定される**。 + 同じバージョンは一度しか公開できないため、develop 段階で出すなら + **プレリリース版**(`3.3.0-alpha1` など)にする(`README.md` 1 節(0)・7 節) +- [ ] **そのコミットを push 済みである** + … 未 push だと Source Link が 404 になる。**公開後には直せない** +- [ ] `CS\0_Release4Nuget.bat` を実行した + … `1_DeleteDir` → `2_Build_NuGet_net48` → `1_DeleteDir` → + `2_Build_NuGet_netcore100` → `4_Build_CopyAssemblies` のみ。サンプルはビルドしない + … `DEBUG_TYPE` は**このバッチが指定する。手で書き換えない**(#531) +- [ ] `CS\NuGet\_NuGetPack.bat` でパッケージ化した + … **ビルドとパッケージ化は同じコミットで行う。** + PDB のコミットは**ビルド時**、nuspec のコミットは**パッケージ化時**に決まるため、 + 間にコミットすると食い違う(`README.md` 2 節 確認 4) + … `in\` と `out\` は**このバッチが先に消す**ので、手で片付けなくてよい + (`README.md` 6 節) +- [ ] `README.md` 2 節の**確認 5 点**を通した +- [ ] `set NUGET_API_KEY=<キー>` の上で `CS\NuGet\out\sp\_NuGetPush.bat` を実行し、push した + … 最新は `sp`(シンボル付き)のみでよい。**キーを bat に直書きしない**(#531) +- [ ] Wiki の手順(NuGet 利用リポジトリの参照貼り直し)を実施した + +--- + +## 6. フェーズ 5 : 後始末 + +**revert する項目は無くなった**(#531)。忘れやすい作業を、そもそも作らない形に変えた。 + +| 以前 revert していたもの | 現在 | +|---|---| +| `CS\z_Common.bat` の `DEBUG_TYPE` | `0_Release4Nuget.bat` が指定するので**書き換えない** | +| `_NuGetPush.bat` の API キー | **環境変数 `NUGET_API_KEY` で渡す**ので、コンソールを閉じれば消える | + +- [ ] **API キーを `Revoke` した**(`Delete` はしない) + … `Revoke` は即座に無効化するが、**行は `Revoked` として残り、 + 次回は `Regenerate` で再び使える**。スコープ(グロブ)の設定を作り直さずに済む + … `Delete` は**キーの定義ごと消える**ため、その系統をもう使わないときだけ + … 有効期限を最短にしてあるなら、失効に任せてもよい(`README.md` 8 節) +- [ ] `%AppData%\NuGet\NuGet.Config` の `` に**キーが残っていない** + … 過去に `nuget.exe SetApiKey` を使っていた場合、そこに永続化されている。 + 削除オプションが無いため、該当する `` 行を手で削除する(`README.md` 8 節) +- [ ] `git status` に意図しない変更が残っていない + … 特に `Result*.txt`(`2_RunAllTests.ps1` が再生成する)と + `CS\Frameworks\Tests\EncAndDecUtilCUI\*.cer` / `*.pfx`(Git 管理外の作業用コピー) + +--- + +## 7. 自動化の範囲と、その理由 + +| 対象 | 自動化 | 理由 | +|---|---|---| +| 全ビルド(31 ステップ) | 済 | 既存バッチを呼ぶだけで済む | +| 単体テスト(8 ケース) | 済 | 期待結果ファイルが既にあり、正規化で機械比較できる | +| バッチ・CLI サンプル(9 件) | 済 | プロセス実行のみ。DB 疎通まで確認できる | +| `DaoGen_Tool` の CUI(6 件) | 済 | #508 で CUI 化。DB → 定義 CSV → Dao・SQL まで通せる | +| Web アプリ(3 件) | 済 | ログインまで通せば認証・セッションまで確認できる | +| **UI 系サンプル(18 本)** | **見送り** | UI Automation が必要。画面定義の変更で壊れやすく維持費が高い。
    通す B 層/D 層は Web 系・バッチ系と重複し、回帰検出力の増分が小さい | +| **GUI ツール(4 本)** | **見送り** | 同上。`DaoGen_Tool` は生成ロジックを CUI 側で確認済みのため、
    手作業で見るのは GUI が起動することだけでよい。
    `DeployZipPackWithHTTP` は ZIP の圧縮・解凍まで見る(CUI が無いため) | +| **Web サービス** | **不可** | 本リポジトリにホストが無い(別リポジトリへ移設済み) | + +**自動化した対象が「起動する」ことは、手作業側の確認範囲を狭める。** +`DaoGen_Tool` は CUI で生成ロジックまで確認できるようになったため、 +GUI 側で見るのは画面が動くことだけになった。 + +--- + +## 8. エージェント向け作業チェックリスト + +- [ ] `AGENTS.md` のポリシー遵守(**git 操作をしない**) + … 検証で `Result*.txt` が書き換わるが、コミットの要否とタイミングは人が判断する +- [ ] 検証は **`1_BuildAll.ps1` → `2_RunAllTests.ps1` → `3_SmokeTest.ps1` の順**(3 節) +- [ ] `1_BuildAll.ps1` に `-SkipClean` を付けない(リリース判定では前回成果物を残さない) +- [ ] **NG を「既知」で片付けない。** 既知として扱ってよいのは + `WSClientWinCone_sample` の署名エラーと NuGet 脆弱性警告のみ(4 節・[`BUILDING.md`](BUILDING.md) 3 節) +- [ ] `2_RunAllTests.ps1` の NG は、退行/期待結果の陳腐化/テスト データの汚染を切り分けてから報告 +- [ ] **前提サービス・DB の状態を勝手に変えない。** 不足は対処方法とともに報告する + (`3_SmokeTest.ps1` が `aspnet_state` を自動起動しないのと同じ理由) +- [ ] **フェーズ 1(検証)は自分で実行してよい。** フェーズ 0・2・4・5 は人が行う(1 節) +- [ ] **公開(`_NuGetPush.bat`)は実行しない。** 外部公開で取り消しが困難、かつ API キーを扱う。 + パッケージ化(フェーズ 3)は**指示があったときだけ** +- [ ] Issue のクローズ・ラベル変更は**人が行う**。エージェントは提案に留める +- [ ] 後始末(6 節)の revert 漏れが無いか `git status` で確認して報告 diff --git a/root/programs/SMOKETEST.md b/root/programs/SMOKETEST.md new file mode 100644 index 000000000..3c7a50271 --- /dev/null +++ b/root/programs/SMOKETEST.md @@ -0,0 +1,552 @@ +# SMOKETEST.md — サンプルの疎通確認 + +対象: `root/programs/CS`(C# 側) +配置: `root/programs` +本書は、リリース時に行っていた「サンプルを幾つか見繕って手動で疎通を行う」を、 +**合否が出る形に機械化**するための手順と判定基準を記述する(#513 段階 3)。 + +--- + +## 1. 使い方 + +```powershell +cd root\programs + +# 全対象の疎通を確認する +.\3_SmokeTest.ps1 + +# 一部だけ(動作確認用) +.\3_SmokeTest.ps1 -Only "net48" +.\3_SmokeTest.ps1 -Only "Rerunnable" -SkipBuild +``` + +終了コードは `0` = 全対象 OK、`1` = NG あり。 + +| オプション | 内容 | +|---|---| +| `-Only <文字列>` | 対象名の部分一致で絞る | +| `-SkipBuild` | ビルドを省略し、既存のバイナリで疎通のみ行う | +| `-OutputDir <パス>` | ログの保存先(既定 `%TEMP%\OpenTouryoSmokeTest`) | + +--- + +## 2. 段階 1・2 との違い + +| | 見るもの | 期待値 | +|---|---|---| +| `1_BuildAll.ps1`(段階 2) | ビルドが通るか | エラー 0 件 | +| `2_RunAllTests.ps1`(段階 1) | 出力が前回と同じか | HEAD の `Result*.txt` | +| **`3_SmokeTest.ps1`(段階 3)** | **起動して想定どおり動くか** | **定義側に書いた判定条件** | + +段階 1 は回帰テスト、段階 3 は疎通テストで、目的が違う。 +疎通テストは期待結果ファイルを持たず、判定条件を `3_SmokeTest.ps1` の対象定義に書く。 + +**実行順は `1_BuildAll.ps1` → `2_RunAllTests.ps1` → `3_SmokeTest.ps1`。** +リリース時の作業全体は [`RELEASE.md`](RELEASE.md) を参照。 + +--- + +## 3. 対象(22 件) + +### バッチ(8 件) + +| 対象 | 判定 | +|---|---| +| `SimpleBatch_sample` (net48 / net10.0) | `〇件のデータがあります` が出力される | +| `RerunnableBatch_sample` (net48 / net10.0) | `Orders2` の件数が `Orders` と一致する | +| `RerunnableBatch_sample2` (net48 / net10.0) | 同上 | +| `RerunnableBatch_sample3` (net48 / net10.0) | 同上 | + +`RerunnableBatch` 系は `Orders`(830 件) を読み `Orders2` へ INSERT する。3 本の違いは +INSERT の方法(1 件ずつ/SQL 連結/INSERT 文組み立て)で、いずれも結果は同じになる。 + +**実行前に `Orders2` を空にする必要がある。** `OrderID` が主キーのため、 +残っていると重複で落ちる。スクリプトが `DELETE FROM [Orders2]` を行ってから実行する。 +実行後は 830 件=初期状態に戻るため、後始末は不要。 + +#### `Orders2` はスクリプトが作る + +**`Orders2` は Northwind 標準の表ではない。** `instnwnd.sql` に含まれないため、 +**DB を作り直すたびに消える**。そのたびに手で作るのは現実的でないので、 +事前準備の中で存在を確認し、無ければ作る。 + +``` +Orders2 がありません。作成します(...\RerunnableBatch_sample\CREATE ORDERS2.sql)。 +``` + +DDL はサンプル同梱の `CREATE ORDERS2.sql` をそのまま流す。**スクリプトに書き写さない** +(同じ DDL がサンプル配下に 9 つ重複しており、増やす意味がない)。 + +流すときの注意が 2 つある。 + +- **`GO` は自前で分割する。** `SqlClient` は `GO` を解釈できない(`sqlcmd` の + バッチ区切りであって T-SQL ではない)。このファイルは 3 バッチに分かれる。 +- **`USE [Northwind]` は流さない。** 接続先は接続文字列に従うべきで、 + 流すと接続文字列が別 DB を指していた場合にそちらへ表を作ってしまう。 + +> CI では `Set up Northwind` ステップが `instnwnd.sql` の直後に同じ DDL を流している。 +> そちらは `sqlcmd` なので `GO` をそのまま解釈できる。 + +### CLI(1 件) + +| 対象 | 判定 | +|---|---| +| `Simple_CLI` (net10.0) | `cmd1 --an-int 123` が `Sub command cmd1: 123` を出力する | + +net48 版は `System.CommandLine` / `Sharprompt` の .NET Framework サポート終了により +ドロップされている(`5_Build_CLI_sample.bat` 参照)。 +`interactive` サブコマンドは対話プロンプトを使うため対象外。 + +### DaoGen_Tool(墨壺)の CUI モード(6 件) + +#508 で追加された CUI。net48 / net10.0 それぞれ 3 件。 + +> **ツール自体の使い方は +> [`CS/Frameworks/Tools/DaoGen_Tool/README.md`](CS/Frameworks/Tools/DaoGen_Tool/README.md) が一次情報。** +> 実行ファイルの場所、ヘルプの出し方、エージェントが踏みやすい罠を記載している。 + +| 対象 | 判定 | +|---|---| +| `/HELP` | ヘルプの見出しが出力される | +| `/CUI /MODE DAODEFGEN` | DB のスキーマから定義 CSV が生成され、対象テーブルが含まれる | +| `/CUI /MODE DAOSQLGEN` | 定義 CSV から Dao(`.cs`)・動的 SQL(`.xml`)・静的 SQL(`.sql`) が生成される | + +**2 モードは連続して実行する。** `DAODEFGEN` が出力した定義 CSV を +`DAOSQLGEN` の入力に使うため、ツール単体ではなく +「DB → 定義 → 生成」の一連の流れを確認できる。 + +対象テーブルは `Shippers,Orders` の 2 つに絞っている。 +全テーブルを回しても時間がかかるだけで、疎通としては同じことを見ているため。 + +生成先は `%TEMP%\OpenTouryoSmokeTest\daogen_*`。 +実行前に前回の生成物を消す。残っていると「生成された」の判定が甘くなる。 + +> **GUI 側の確認は手作業に残る。** 引数なしで起動すると `Application.Run(new Form1())` になる。 + +#### パス区切りの注意 + +コマンドライン解析(`StringVariableOperator.GetCommandArgs`)は +**`\` をエスケープ文字として扱う**ため、パスの区切りは `/` にする。 + +``` +OK : /OUTPUT "C:/temp/out" +OK : /OUTPUT "C:\\temp\\out" +NG : /OUTPUT "C:\temp\out" ← \ が消える +``` + +ツール自身の `/HELP` にも記載されている。 + +#### 標準出力の捕捉 + +`DaoGen_Tool` は `WinExe` で、CUI 時は `AttachConsole(-1)` でコンソールに接続する。 +このため**リダイレクトの方法によって出力が取れない**。 + +| 方法 | 結果 | +|---|---| +| `Start-Process -RedirectStandardOutput` | **取れる**(現在の方式) | +| PowerShell の `& $exe ... *>&1 \| Out-File` | 取れるが、**stderr が壊れる**(下記) | +| `cmd /c "... > file"` | 取れない(0 行) | + +**`3_SmokeTest.ps1` は `Start-Process` でファイルへ直接リダイレクトする。** +パイプ(`\| Out-File`)でも出力自体は取れるが、そちらは別の問題を抱える(9 節)。 + +### DeployZipPackWithHTTP の CUI モード(4 件) + +| 対象 | 判定 | +|---|---| +| `DeployZip /MFTGEN` (net48 / net10.0) | マニュフェストが生成され、**MD5 が同梱のものと一致する** | +| `DeployZip 配置` (net48 / net10.0) | **配置結果が圧縮前のフォルダと全ファイル一致する** | + +`#528` で `/ZIPGEN`(ZIP 生成)と `/MFTGEN`(マニュフェスト生成)を追加し、 +**圧縮 → マニュフェスト → 配布 → 配置**を CUI で通せるようになった。 +前段の出力を後段の入力に使う点は `DaoGen_Tool` と同じ。 + +**配布物(ZIP)は追跡していない。** `Pre` で `FormAppRoot` から毎回作る。 + +``` +/ZIPGEN /TOPONLY → root.zip(ルート直下だけ、書庫内ルート無し) +/ZIPGEN /ROOTINZIP aaa → aaa.zip (フォルダごと、書庫内ルート = aaa) +``` + +**両方のモードを通る。** GUI のチェック ボックス +(「個別のフォルダ圧縮」/「ルート フォルダからの圧縮」)に対応する分岐である。 + +`Sample/FormAppRoot` が配布前の姿なので、**配置結果を MD5 で突き合わせられる**(21 ファイル)。 + +**ここだけ ZIP 部品(`ZipperV2` / `UnZipperV2`)を通る。** +単体テスト(`TestCode/TestZipV2.cs`)は部品の振る舞いを見るが、 +配布フロー全体を通すのはこの 2 件だけ。 + +#### マニュフェストの MD5 は計算し直して突き合わせる + +```powershell +$want = $md5s[$i].Substring(4).Trim() +$got = [Convert]::ToBase64String($md5.ComputeHash([IO.File]::ReadAllBytes($path))) +``` + +**作り置きの ZIP を追跡していた頃は、ここで気付けなかった。** +`FormAppRoot` を直したのに ZIP を作り直さないと MD5 が合わなくなるが、 +比較相手も作り置きだと両方が古いままで通ってしまう。 + +#### 配信は IIS Express で立てる + +Web アプリと違い**対象は EXE** なので、本文側の Web ホスト起動の仕組みには乗らない。 +`Pre` で起動し、`Verify` の最後で止める。 + +**起動待ちにコンテンツを要求してはいけない。** 404 でも「起動している」ため、 +応答の内容で判定すると、ファイルが無いときに待ち続け、 +**IIS Express が残って次回のポート登録を塞ぐ**(`0x800700b7`)。TCP で繋がるかだけを見る。 + +#### 配置先は `-OutputDir` の下 + +同梱のマニュフェストは `c:\FormAppRoot\` を指すが、**疎通確認で環境を汚さない**よう、 +`$OutputDir\deploy_\ins` を指すマニュフェストを作り直してから配布する。 + +#### `/NB` を必ず付ける + +マニュフェストの `exe` 行のアセンブリを、**配置後に起動してしまう**ため。 +起動すると GUI が開き、非対話の実行が止まる。 + +> 引数の渡し方に癖がある(`\` がエスケープされる・`/INSDIR` だけは `\` を残す・ +> 空白を含む値は自分で引用符を付ける)。 +> **一次情報は [`Tools/DeployZipPackWithHTTP/README.md`](CS/Frameworks/Tools/DeployZipPackWithHTTP/README.md) の 3.4 節。** + +#### 古いビルドに新しいスイッチを渡すと、以前は GUI が開いた + +**引数があるのにどのモードにも当たらない場合、GUI へ落ちる実装だった**(#528 で修正)。 +非対話では画面が出たまま止まるため、疎通確認や CI が停止する。 +現在は**エラーで終わる**(終了コード 1)。 + +`/ZIPGEN` を実装した直後、`.NET 10` 側を建て直さずに回して実際に踏んだ。 +**片方のビルドだけを更新しない**こと。 + +### Web アプリ(3 件) + +| 対象 | ホスト | 認証の実装 | 判定 | +|---|---|---|---| +| `MVC_Sample` (net48) | IIS Express | FormsAuthentication | ログイン後 `/Crud1/Index` が 200 | +| `WebForms_Sample` (net48) | IIS Express | FormsAuthentication | ログイン後 `menu.aspx` が 200 | +| `MVC_Sample` (net10.0) | Kestrel | Cookie 認証 | ログイン後 `/Crud1/Index` が 200 | + +**3 つとも確認の深さを揃えている。** 入口ページが 200 を返すだけでは +ホスティングと構成しか確認できないため、いずれも**ログインを通し、 +認証が要る画面に到達できること**まで見る。 + +1. ログイン画面を GET … 画面が出ること。ページが発行した状態を取り出す + (MVC は `__RequestVerificationToken`、WebForms は `__VIEWSTATE` 等) +2. ログインを POST … 偽造防止の検証を通ること +3. 認証が要る画面を GET … **未認証なら 302 になるので、200 なら認証が通っている** + +これでホスティング・構成・ルーティング・認証・セッションまでを一度に確認できる。 +いずれのサンプルも「ユーザー名が空でなければ認証する」実装のため、資格情報は不要。 + +> **未認証時に 302 が返ることは実測で確認済み。** 200 が偶然でないことの裏付けになる。 +> +> ``` +> MVC_Sample (net48) 未認証で /Crud1/Index → 302 +> WebForms_Sample 未認証で /Aspx/start/menu.aspx → 302 +> ``` + +`WebForms_Sample` は `Web.config` の `` で全画面が要認証になっており、 +ログイン後は `` の画面へ遷移する。 +ポストバックには画面が発行した `__VIEWSTATE` / `__VIEWSTATEGENERATOR` / `__EVENTVALIDATION` を +そのまま返す必要があり、コントロール名はマスタ ページ配下のため +`ctl00$ContentPlaceHolder_A$` が付く。 + +### 対象外 + +| 対象 | 理由 | +|---|---| +| `2CS_sample` 系(11 本) | WinForms / WPF。UI Automation が必要で、画面変更に弱く維持費が高い | +| `WSClient_sample` 系(7 本) | 同上 | +| Web サービス(`ASPNETWebService`) | **別リポジトリへ移設済み**。本リポジトリにホストが無い | + +`CS/Samples/WS_sample/WSServer_sample` はクラス ライブラリ(B層・D層)で、 +これを載せる Web サービスは +[`OpenTouryoProject/ResourceServerTemplates`](https://github.com/OpenTouryoProject/ResourceServerTemplates) +へ移設されている。このため本リポジトリだけでは HTTP 疎通ができない。 + +WinForms / WPF 系は、リリース チェックリスト(段階 4)の**手作業項目**として残す。 + +--- + +## 4. 前提条件 + +- **SQL Server の Northwind に接続できる**こと + - 接続文字列は `CS\Samples\Bat_sample\SimpleBatch_sample\App.config` の + `ConnectionString_SQL` を読む。ここで別途ハードコードすると追随できなくなるため +- **IIS Express** がインストールされていること(net48 の Web アプリ) +- **ASP.NET 状態サービスが開始されている**こと(net48 の Web アプリ) + +> **GitHub Actions でも実行している。** 前提の揃え方(SQL Server の導入と Northwind の +> ロード、`C:\root`、ロケール、`aspnet_state` の開始)は +> [`BUILDING.md`](BUILDING.md) 9 節が一次情報。 +> IIS Express は `windows-latest` に同梱されているため、追加の導入は要らない。 + +### ASP.NET 状態サービス + +`MVC_Sample` / `WebForms_Sample` の `Web.config` は `StateServer` を使う。 + +```xml + +``` + +サービスが止まっていると、ログインの POST が **500** になる。 + +``` +System.Web.HttpException: セッション状態要求をセッション状態サーバーに対して作成できませんでした。 +``` + +`3_SmokeTest.ps1` は実行前に確認し、止まっていれば「前提未達」として対処方法を示す。 + +```powershell +Start-Service aspnet_state # 管理者権限が必要 +``` + +**スクリプトはサービスを自動起動しない。** システムの状態を変える操作であり、 +リリース判定のために黙って環境を書き換えるべきではないため。 + +--- + +## 5. 判定基準 + +対象ごとに次のいずれかで判定する。 + +| 種別 | 判定 | +|---|---| +| 出力の照合 | 標準出力が `Expect` の正規表現に一致するか | +| 追加検証 | `Verify` のスクリプト ブロックが `$true` を返すか(DB の件数など) | +| Web の疎通 | `Flow` のスクリプト ブロックが `Ok = $true` を返すか | + +いずれの場合も、**出力に未処理例外が含まれていれば NG**。ただし次は除外する。 + +- **`Console.ReadKey()` 由来の例外** + … サンプルは末尾に `Console.ReadKey()` を持つものがあり、出力をリダイレクトすると + 必ず例外で終わる。テスト内容とは無関係 + +--- + +## 6. ビルドについて + +**リポジトリ既定のビルド バッチを呼ぶ。** 理由は `2_RunAllTests.ps1` と同じで、 +`csproj` を直接 MSBuild すると `nuget.exe restore` が行うネイティブ DLL の配置が漏れ、 +**ビルドは成功するのに実行時に落ちる**(`TESTING.md` の「ビルドをバッチに委ねている理由」)。 + +### `1_BuildAll.ps1` の後にバイナリが残らない理由 + +`0_ExecAllBat.bat` は途中で `1_DeleteDir.bat` を繰り返し実行し、 +配下の `bin` / `obj` / `packages` 等を**再帰的に**削除する。 + +``` +… net48 サンプルをビルド … +Clean (core サンプル) ← ここで net48 サンプルの bin も消える +… Core サンプルをビルド … +``` + +このため `1_BuildAll.ps1` の完走後に残るのは最後にビルドされた Core サンプルだけで、 +net48 サンプルのバイナリは残らない。`3_SmokeTest.ps1` が自分でビルドするのはこのため。 + +--- + +## 7. 修正の経緯 : バッチ サンプルが実行時に落ちていた + +着手時、net48 のバッチ サンプル 4 本がすべて起動直後に落ちていた。 + +``` +System.DllNotFoundException + 場所 Microsoft.Data.SqlClient.SNINativeManagedWrapperX64.SNIInitialize(IntPtr) +``` + +原因は、`5_Build_Bat_sample.bat` と `6_Build_WSSrv_sample.bat` に +**`nuget.exe restore` が無かった**こと。`Microsoft.Data.SqlClient` は SNI を +ネイティブ DLL で持つため、restore を経ないと `bin` に配置されない。 + +**ビルドは成功する**ため、段階 2(ビルドの合否判定)では検出できない。 +疎通テストで初めて表面化する種類の不具合である。 + +他の 11 バッチと同じ形式で `nuget.exe restore ... %NUGET_MSBUILD%` を追加した。 + +--- + +## 7.2 修正の経緯 : 対象の起動方法を `Start-Process` にした + +**当初は PowerShell のパイプで実行していた。** + +```powershell +& $exe @($t.Args) *>&1 | Out-File $out -Encoding UTF8 +``` + +この形は 2 つの問題を抱えていて、**対症療法を 3 回繰り返しても直らなかった。** + +### ① stdin を与えないと止まる + +サンプルは終了前に `Console.ReadKey()` を呼ぶ。stdin がコンソールのままだと +**本当にキー入力を待つ**。実測で `SimpleBatch_sample (net48)` が **386 秒**かかった。 + +**CI では stdin が元からリダイレクトされているため顕在化しない。** 実機だけで止まる。 + +### ② stderr が壊れる + +パイプで受けると、native の stderr が `ErrorRecord` になり**コンソール幅で折り返される。** +折り返しは**語の途中にも入る**。 + +``` +Cannot read keys when either application does not h ave a console ... + ↑ 単語が割れている +``` + +**空白を畳んでも復元できない**(折り返しは何かを置き換えたのではなく、挿入されたため)。 +幅は環境ごとに違うので、判定側の除外規則をいくら調整しても直らない。 + +### 現在の方式 + +**`Start-Process` でファイルへ直接リダイレクトする。** PowerShell を経由しないので、 +出力は生のまま残り、環境による差も出ない。 + +```powershell +Start-Process $exe -ArgumentList $argList -NoNewWindow -Wait ` + -WorkingDirectory (Split-Path $exe) ` + -RedirectStandardInput $emptyIn -RedirectStandardOutput $out -RedirectStandardError $err +``` + +`-RedirectStandardInput` には**空ファイル**を渡す(実在するファイルが要る)。 + +> **読み戻しには `-Encoding UTF8` を必ず付ける。** +> `Start-Process` は子プロセスの生バイトをそのまま書くため **BOM が付かない**。 +> Windows PowerShell 5.1 の `Get-Content` は BOM が無いと既定の ANSI(CP932)で読むため、 +> **日本語の期待値だけが一致しなくなる**(ASCII の期待値は通るので気付きにくい)。 +> 従来の `Out-File -Encoding UTF8` は BOM 付きだったため、たまたま成立していた。 + +**副次的に、`DaoGen_Tool` 実行時の画面の乱れも解消した。** +`AttachConsole(-1)` が親コンソールへ直接書き込んでいたのが原因で、 +独立したリダイレクト先を持つようになったため起きなくなった。 + +--- + +## 8. 実行結果の例 + +``` +対象 結果 内容 +---- ---- ---- +SimpleBatch_sample (net48) OK 3件のデータがあります +RerunnableBatch_sample (net48) OK +RerunnableBatch_sample2 (net48) OK +RerunnableBatch_sample3 (net48) OK +SimpleBatch_sample (net10.0) OK 3件のデータがあります +RerunnableBatch_sample (net10.0) OK +RerunnableBatch_sample2 (net10.0) OK +RerunnableBatch_sample3 (net10.0) OK +Simple_CLI (net10.0) OK Sub command cmd1: 123 +DaoGen_Tool /HELP (net48) OK DaoGen_Tool(D層自動生成ツール/墨壺) +DaoGen_Tool DAODEFGEN (net48) OK 生成が完了しました。 +DaoGen_Tool DAOSQLGEN (net48) OK 生成が完了しました。 +DaoGen_Tool /HELP (net10.0) OK DaoGen_Tool(D層自動生成ツール/墨壺) +DaoGen_Tool DAODEFGEN (net10.0) OK 生成が完了しました。 +DaoGen_Tool DAOSQLGEN (net10.0) OK 生成が完了しました。 +DeployZip /MFTGEN (net48) OK マニュフェスト ファイルを生成しました。 +DeployZip 配置 (net48) OK 履歴に新規追加しました。 +DeployZip /MFTGEN (net10.0) OK マニュフェスト ファイルを生成しました。 +DeployZip 配置 (net10.0) OK 履歴に新規追加しました。 +MVC_Sample (net48) OK ログイン後 /Crud1/Index = 200 +WebForms_Sample (net48) OK ログイン後 menu.aspx = 200 +MVC_Sample (net10.0) OK ログイン後 /Crud1/Index = 200 + + 全対象 OK +``` + +全 22 件(ビルド 7 バッチ + 疎通 22 件)で **約 2.3 分**。 + +### リダイレクトの扱い + +`Invoke-WebRequest` は `-MaximumRedirection 0` で 3xx を受け取ると、 +`-SkipHttpErrorCheck` を付けていても +「The maximum redirection count has been exceeded」で終了エラーになる。 + +ログイン成功時は `FormsAuthentication` が 302 を返すため、これに該当する。 +`3_SmokeTest.ps1` は `Invoke-Http` で捕まえ、3xx を正常な結果として扱う。 +素の `Invoke-WebRequest` を使うと、**判定は通るのにエラーが表示される**状態になる。 + +--- + +## 9. 対象を追加するとき + +`3_SmokeTest.ps1` の `$targets` に定義を足す。 + +| 項目 | 内容 | +|---|---| +| `Name` | 表示名 | +| `Bat` | ビルドに使うバッチ(`root\programs\CS` 配下) | +| `Exe` | 実行ファイル。`.dll` なら `dotnet` で実行する | +| `Args` | コマンドライン引数 | +| `Pre` | 実行前の準備(スクリプト ブロック) | +| `Expect` | 標準出力に対する正規表現 | +| `Verify` | 追加の検証(スクリプト ブロック) | +| `Kind` | `Web` を指定すると Web アプリ扱い | +| `WebHost` | `IISExpress` または `Kestrel` | +| `Site` / `Port` / `Flow` / `Need` | Web アプリ用 | + +**判定条件は「動いていれば必ず満たす」ものにする。** +実行のたびに変わる値(件数以外の可変値、日時など)を条件に入れると、 +環境差で落ちるだけの脆いテストになる。 + +### `Args` は `Pre` より前に組み立てられる + +対象定義(`$targets`)は**スクリプトの読み込み時に評価される**。 +`Pre` が作るフォルダを `Args` の組み立てで参照すると、**まだ存在しない。** + +```powershell +NG : $zips = Get-ChildItem (Join-Path $OutputDir "deploy_net48\web") ... ← Pre がまだ動いていない +OK : $zips = Get-ChildItem $deploySampleWeb ... ← リポジトリ側から採る +``` + +実行時に決めたいなら、`Args` ではなく `Pre` の中で `$script:` 変数に入れて渡す。 + +### 対象が EXE でも Web サーバが要ることがある + +`Kind = "Web"` は**対象自身が Web アプリ**のときの仕組みで、 +「EXE の相手として Web サーバを立てたい」場合には使えない。 +`Pre` で起動し、`Verify` の最後で止める(`DeployZipPackWithHTTP` がこの形)。 + +**起動待ちに、特定のコンテンツを要求してはいけない。** +404 でも「起動している」ため、応答の内容で待つと、 +ファイルが無いときに待ち続けたうえで**プロセスが残る**。 +残った IIS Express は URL の登録を握るので、 +**次回以降の起動が `0x800700b7`(既に存在する)で失敗し続ける。** + +```powershell +# TCP で繋がるかだけを見る。開始前に前回の残りも止める。 +$client = New-Object System.Net.Sockets.TcpClient +$client.Connect("localhost", $port) +``` + +### `dotnet` への引数の渡し方 + +`/DAP` のように `/` で始まる引数は `--` で区切って渡す必要がある。 +一方 `System.CommandLine` を使う CLI では `--` 以降が未解析トークン扱いになり、 +**サブコマンドが認識されなくなる**。`3_SmokeTest.ps1` は引数を見て自動で切り替える。 + +### PowerShell 5.1 と 7 の両対応 + +**両方で動くこと。** 開発時に `pwsh`(7)だけで確認すると、 +利用者が `powershell.exe`(5.1)で実行したときに落ちる。 + +> **規約の実体は +> [`CODING.md`](CODING.md) の 5 節**にある。 +> 落とし穴の一覧と対処方法は、そちらを参照すること。 + +本スクリプト群は、次の 4 点を**実際に踏んだ**うえで対処してある。 +同種のスクリプトを追加・変更するときの実例として挙げる。 + +| 事象 | 踏んだ箇所 | +|---|---| +| BOM 無しで構文エラー・文字化け | 5 本すべて(`0_RunAll.ps1` ほか) | +| `Get-Content` の既定エンコード差で、同じファイルなのに差分が出る | `CompareResult.ps1` | +| `-SkipHttpErrorCheck` が 5.1 に無く、HTTP が常に失敗 | `3_SmokeTest.ps1` の `Invoke-Http` | +| `chcp` による画面クリアと、ログの文字化け | 3 本すべて(冒頭でコード ページを切り替え) | + + +### PowerShell から `.bat` を呼ぶときの注意 + +`TESTING.md` と同じく、`NoDefaultCurrentDirectoryInExePath` を解除している。 +解除しないと、バッチ内でパス区切りを含まない名前で起動している exe が動かない。 diff --git a/root/programs/TESTING.md b/root/programs/TESTING.md new file mode 100644 index 000000000..e864dfb47 --- /dev/null +++ b/root/programs/TESTING.md @@ -0,0 +1,327 @@ +# TESTING.md — 単体テストの実行と判定 + +対象: `root/programs/CS/Frameworks/Tests`(C# 側) +配置: `root/programs` +本書は、リリース時に行っていた「単体テスト スクリプトの実行結果を diff で目視」を、 +**機械判定に置き換える**ための手順と判定基準を記述する(#513 段階 1)。 + +リリース時の作業全体は [`RELEASE.md`](RELEASE.md) を参照。 +実行順は `1_BuildAll.ps1` → `2_RunAllTests.ps1` → `3_SmokeTest.ps1`。 + +--- + +## 1. 使い方 + +```powershell +cd root\programs + +# ビルド バッチを実行し、再生成された結果を HEAD 版と比較して一覧表示する +.\2_RunAllTests.ps1 + +# バッチを実行せず、いま手元にある結果ファイルだけを比較する +.\2_RunAllTests.ps1 -SkipBuild + +# 個別に比較する +.\CompareResult.ps1 -Expected -Actual TestCode\Result48.txt +.\CompareResult.ps1 -Expected -Actual TestBatch\ResultSimpleBatch48.txt -SkipLog4netTrace +``` + +終了コードは `0` = 全 OK、`1` = NG あり、`2` = ファイル無し。 + +--- + +## 2. 何を何と比較しているか + +**従来の運用をそのまま機械化している。** 置き換えたのは最後の「目視」だけ。 + +`y_Build_TestCode*.bat` は「ビルド → テスト実行 → **結果を `Result*.txt` へ出力**」まで行う。 +この `Result*.txt` は Git 管理下にあり、バッチを実行すると上書きされる。 +つまり従来の手順は次のとおりだった。 + +1. バッチを実行して `Result*.txt` を再生成する +2. `git diff` で「前回のリリース時の結果」との差分を目視する + +`2_RunAllTests.ps1` はこの構造を変えず、2 を機械比較に置き換える。 + +| | 実体 | 取得方法 | +|---|---|---| +| **期待値** | HEAD にコミットされている `Result*.txt` | `git show HEAD:`(参照系のみ) | +| **実測値** | バッチが再生成したワーキング ツリーの `Result*.txt` | バッチの実行 | + +> **副作用**: ワーキング ツリーの `Result*.txt` が書き換わる。これは従来のバッチ運用と同じ。 + +**生 `git diff` を目視してはいけない。** 実行日時が全行に入るため、 +内容が同じでも**ほぼ全行が差分になる**(実測で 6 ファイル約 2,458 行)。 + +```diff +-[2025/11/18 15:19:08,286],[INFO ],[1],,,,----->>,... ++[2026/08/01 22:40:19,772],[INFO ],[1],,,,----->>,... +``` + +判定は本スクリプトの**正規化後の差分**で行う。0 なら内容は同じ。 +生 diff を読むのは、正規化後に差分が出たときだけでよい。 +`Result*.txt` のコミットは、内容が変わった(新しい基準にしたい)ときだけでよい。 + +### 対象テスト(8 ケース) + +| テスト | 結果ファイル(=期待値) | ビルド バッチ | 備考 | +|---|---|---|---| +| TestCode (net48) | `TestCode/Result48.txt` | `y_Build_TestCode_Public.bat` | 部品層の総合テスト(約 2,500 行)。**DB に接続しない** | +| TestCode (net10.0) | `TestCode/ResultCore100.txt` | 同上 | 同上 | +| TestDataAccess (net48) | `TestDataAccess/Result48.txt` | `y_Build_TestCode_DataAccess.bat` | データ アクセス(#520)。**実行モードで対象 DBMS が変わる** | +| TestDataAccess (net10.0) | `TestDataAccess/ResultCore100.txt` | 同上 | 同上 | +| SimpleBatch (net48) | `TestBatch/ResultSimpleBatch48.txt` | `y_Build_TestCode_Batch.bat` | **DB 接続あり**(Northwind) | +| SimpleBatch (net10.0) | `TestBatch/ResultSimpleBatchCore100.txt` | 同上 | 同上 | +| EncAndDecUtilCUI (net48) | `EncAndDecUtilCUI/Result48.txt` | `y_Build_TestCode_SecCUI.bat` | 暗号・JWT・XML 署名 | +| EncAndDecUtilCUI (net10.0) | `EncAndDecUtilCUI/ResultCore100.txt` | 同上 | 同上 | + +`EncAndDecUtilCUI/ResultCore100OnLinux.txt` は Linux 実行時の期待結果のため、 +Windows からの `2_RunAllTests.ps1` の対象外。 + +### `TestCode` / `TestDataAccess` は詳細を別文書に持つ + +**「何をテストしているか」「ケースを書き足すときの決まり」は各プロジェクトの +`README.md` が一次情報。** 本書はここに写さない(二重管理になるため)。 + +| 文書 | そちらで扱うもの | +|---|---| +| [`TestCode/README.md`](CS/Frameworks/Tests/TestCode/README.md) | `Test*.cs` と対象名前空間の対応、環境依存の値を出さないための決まり、記録している「仕様」(読み違えやすい挙動) | +| [`TestDataAccess/README.md`](CS/Frameworks/Tests/TestDataAccess/README.md) | 実行モードと対象 DBMS、更新系・動的パラメタライズドクエリのケース設計の根拠、クロス DB テストの実施手順 | + +`TestCode` と `TestDataAccess` を分けているのは、**`TestDataAccess` が DB を前提にする**ため。 +混ぜると、DB が無い環境では `TestCode` ごと動かなくなる。 + +### `TestDataAccess` の実行モード + +**クロス DB は CI では実行できない。** LocalServicesOnDocker の各 DBMS は Linux コンテナで、 +`windows-latest` は Linux コンテナを動かせないため([`BUILDING.md`](BUILDING.md) 9 節)。 +このため `/MODE` で対象を切り替える。**期待値は `SQLONLY`(SQL Server のみ)で記録している。** + +``` +TestDataAccessFx.exe /MODE SQLONLY … SQL Server だけ(既定。CI はこちら) +TestDataAccessFx.exe /MODE LOCAL … ローカルで起動している DBMS をすべて +``` + +> **「接続するテスト」と一括りにはできない。** `TestDataAccess` の中でも、 +> SQL を組み立てるだけで接続を必要としないものがある。詳細は上記の README。 + +### ビルドをバッチに委ねている理由 + +`csproj` / `sln` を直接 MSBuild してはならない。 +`nuget.exe restore` が行う**ネイティブ DLL の配置が漏れる**ためで、 +ビルドは成功するのに実行時に落ちる、という分かりにくい失敗になる。 + +``` +System.DllNotFoundException + at Microsoft.Data.SqlClient.SNINativeManagedWrapperX64.SNIInitialize(IntPtr) +``` + +`Microsoft.Data.SqlClient` は SNI をネイティブ DLL で持ち、 +`bin\Debug\Microsoft.Data.SqlClient.SNI.x64.dll` 等が必要になる。 +「何をどうビルドするか」の正はバッチ側に置く。 + +### PowerShell から `.bat` を呼ぶときの注意 + +PowerShell は子プロセスに `NoDefaultCurrentDirectoryInExePath=1` を渡す。 +一方バッチは、出力フォルダへ `cd` したうえでパス区切りを含まない名前で実行している。 + +```bat +cd "Frameworks\Tests\TestBatch\SimpleBatch\bin\Debug" +SimpleBatch.exe /Dap SQL ... > ..\..\..\ResultSimpleBatch48.txt +``` + +この変数が効いていると次のようになり、**結果ファイルが空のまま、バッチは成功したように進む**。 + +``` +'SimpleBatch.exe' is not recognized as an internal or external command, +``` + +`2_RunAllTests.ps1` は、バッチを直接実行した場合と同じ条件にするため、この変数を解除している。 + +--- + +## 3. 前提条件 + +- **Frameworks をビルド済み**であること(`Build_net48` / `Build_netcore100` が存在) +- **SQL Server の Northwind に接続できる**こと(SimpleBatch が使用) +- **Northwind のテスト データが標準状態**であること(後述の「4. テスト データ」) + +> **GitHub Actions でも実行している。** 前提の揃え方(SQL Server の導入、Northwind の +> ロード、照合順序)は [`BUILDING.md`](BUILDING.md) 9 節が一次情報。 +> **期待値は開発環境で生成されたもの**なので、CI 側の環境がずれると差分が出る。 +> そのため CI は期待値と実測値の両方を artifact に残す。 + +### テスト証明書について + +`EncAndDecUtilCUI` の csproj は `*.cer` / `*.pfx` を `CopyToOutputDirectory` しているため、 +**これらが無いとビルドが `MSB3030` で失敗する**。 + +これらは **Git 管理外の作業用コピー**であり、**正本はリポジトリ内の +`root/files/resource/X509/`**(10 件が Git 管理下)にある。 + +`y_Build_TestCode_SecCUI.bat` は先頭で `copy_cert.bat` を呼ぶが、こちらは `C:\root\files\...` +を参照するため、リポジトリだけを clone した環境では配置できない。 +`2_RunAllTests.ps1` はリポジトリ内の正本から不足を**自動で配置**するため、手動操作は不要。 +個別にビルドする場合のみ、次のいずれかを実行する。 + +```powershell +# リポジトリ内の正本から配置(推奨・配置場所に依存しない) +Copy-Item ..\..\..\..\files\resource\X509\SHA*.??? EncAndDecUtilCUI\ + +# あるいは同梱のバッチ(C:\root\files\resource\X509\ を参照する) +cd EncAndDecUtilCUI +.\copy_cert.bat +``` + +`copy_cert.bat` は `C:\root\files\...` を参照するが、そちらは Samples の**実行時**要件であり、 +単体テストのビルドには不要。リポジトリ内の正本から取る方が確実。 + +--- + +## 4. なぜ「目視」だったのか(正規化の必要性) + +期待結果と実行結果には、**実行のたびに変わる値**が多数含まれる。 +そのため素の diff では必ず差分が出る。実測値は次のとおり。 + +| テスト | 素の diff | 正規化後 | +|---|---|---| +| TestCode (net48) | 10 件 | **0 件** | +| TestCode (net10.0) | 11 件 | **0 件** | +| EncAndDecUtilCUI (net48) | 52 件 | **0 件** | +| EncAndDecUtilCUI (net10.0) | 52 件 | **0 件** | + +`CompareResult.ps1` は次を正規化してから比較する。 + +| 種別 | 例 | +|---|---| +| 日時 | `[2026/08/01 14:39:50,027]` → `` | +| 処理時間 | アクセス ログ末尾の `234,125` → `` | +| 絶対パス | `C:\OpenTouryo\...` → `` | +| GUID | → `` | +| XML 署名値 | `...` → `` | +| Base64URL | JWT・JWE の IV・認証タグ・鍵 → `` | +| Base64 | 鍵・ハッシュ → `` | + +加えて、次の行は比較対象から除外する。 + +- **空行** +- **`-SkipLog4netTrace` 指定時の `log4net: ` 行** + … `TestBatch` は 149 行中 145 行が log4net の内部トレースで、判定は残り 4 行 +- **非対話実行の副産物** + … サンプルは末尾に `Console.ReadKey()` を持つものがあり、 + 出力をリダイレクトすると必ず例外で終わる。テスト内容とは無関係 + +--- + +## 5. 判定基準 + +**正規化後に残った差分は「実質的な差分」**であり、次のいずれかを意味する。 + +1. **退行** … コードの不具合。要調査 +2. **期待結果ファイルの陳腐化** … 仕様変更に追随していない。期待結果を更新する +3. **テスト データの汚染** … DB のレコードが増減している。データを戻す + +### 差分の「件数」は当てにならないことがある + +**テストを追加したときなど、大きな挿入があると件数が実態より大きく出る。** + +`CompareResult.ps1` は `Compare-Object -SyncWindow 20` で比較する。 +**挿入した行数が同期窓(20 行)を超えると、以降の行が対応付かなくなり、 +変わっていない行まで左右に並ぶ。** + +実測(#522 でテストを 3 本追加したとき)。 + +| | 値 | +|---|---| +| 実際に増えた行数 | **119 行** | +| 表示された差分件数 | **309 件** | + +**合否(OK / NG)は正しい。** 誤るのは件数と一覧の見え方だけ。 + +#### 「追加しかしていない」ことの確かめ方 + +件数を当てにせず、**生の行集合で突き合わせる。** +`HEAD` にあって実測に無い行が(日時などの揮発値を除いて)無ければ、 +消えた出力は無い=追加のみと分かる。 + +```powershell +$new = Get-Content <実測> -Encoding UTF8 +$old = (git show "HEAD:<リポジトリ相対パス>") -split "`n" | ForEach-Object { $_.TrimEnd("`r") } +$old | Where-Object { $new -notcontains $_ } +``` + +> ここは**正規化前の生の行**を比べるため、日時を含む行は必ず残る +> (`TestOutputLog` の `LogIF.*Log` など)。それ以外が出なければ追加のみ。 + +`3` の実例(2026-08-01 に発生。復旧済み): + +``` +SimpleBatch (net48 / net10.0) + [実測のみ] 4件のデータがあります + [期待のみ] 3件のデータがあります +``` + +Northwind の `Shippers` は標準で 3 件だが、`ShipperID=4` に `Speedy Express` の重複が +存在していた。CRUD サンプルの「追加」操作で挿入されたものと見られる。 + +このように、**件数などテスト対象の出力そのものは正規化してはならない**。 +正規化すると、退行とデータ汚染のいずれも検出できなくなる。 + +**テスト データを汚す操作を行った後は、DB を戻してから単体テストを実行すること。** + +```sql +-- 確認(標準は 3 件) +SELECT ShipperID, CompanyName FROM Shippers ORDER BY ShipperID; +``` + +### テスト データの戻し方 + +DB コンテナは**永続ボリュームを使用していない**(`docker-compose.yml` の +`./sqlserver/mssql-db:/var/opt/mssql` はコメントアウト)。 +Northwind は起動のたびに `start-up.sh` が再作成するため、 +**コンテナを作り直せば初期データに戻る**。 + +`LocalServicesOnDocker` の PowerShell 版スクリプトを使用する +(**DB の初期化完了待ちを行う**ため、`.bat` 版よりテスト用途に適している)。 + +| 環境 | 使用するスクリプト | +|---|---| +| Rancher Desktop 導入時(Windows から `docker` が使える) | `Stop-Services.ps1` → `Start-Services.ps1` | +| WSL2 内の Docker を使う場合 | `Stop-Services_wsl2.ps1` → `Start-Services_wsl2.ps1` | + +```powershell +cd +.\Stop-Services.ps1 # docker compose down(コンテナを破棄) +.\Start-Services.ps1 # docker compose up -d + DB 初期化完了待ち +``` + +> **`docker restart` では戻らない。** 同一コンテナが再開されるだけで書き込み層が保持されるため。 +> コンテナの破棄(`down`)と再作成(`up`)が必要。 +> なお compose には `restart: always` が指定されているため、ホスト再起動でも戻らない。 + +初期化完了待ちを省略したい場合は `-NoWait` を指定できるが、 +その場合は Northwind のロード完了前にテストが始まり得るため、テスト用途では非推奨。 + +コンテナを作り直さず、個別に戻すこともできる。 + +```sql +DELETE FROM Shippers WHERE ShipperID > 3; +``` + +### 期待結果に含まれる「正常な失敗」 + +`EncAndDecUtilCUI` の期待結果には `False` を含む行が **3 件**含まれる。 +これはプラットフォーム非対応等による既知の失敗であり、**正常**。 +実測でも同数であることを確認すること(`CompareResult.ps1` は行単位で比較するため自動的に検出される)。 + +--- + +## 6. 正規化ルールを追加するとき + +新しい非決定値が現れた場合は、`CompareResult.ps1` の `$normalizers` に追加する。 + +**追加してよいのは「実行のたびに変わる値」だけ**。 +テスト対象の出力(件数・判定結果・型名など)を正規化してはならない。 +差分を消すために安易にパターンを広げると、退行を検出できなくなる。 + +判断に迷う場合は、**同じ環境で 2 回実行して差分が出る値かどうか**を確認するとよい。 diff --git a/root/programs/VB/10_Build_WebApp_sample.bat b/root/programs/VB/10_Build_WebApp_sample.bat index fbd9753a8..3491239d9 100644 --- a/root/programs/VB/10_Build_WebApp_sample.bat +++ b/root/programs/VB/10_Build_WebApp_sample.bat @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of WebForms_Sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\WebApp_sample\WebForms_Sample\WebForms_Sample.sln" +..\nuget.exe restore "Samples\WebApp_sample\WebForms_Sample\WebForms_Sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\WebApp_sample\WebForms_Sample\WebForms_Sample.sln" pause @@ -26,7 +26,7 @@ pause rem -------------------------------------------------- rem Batch build of MVC_Sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\WebApp_sample\MVC_Sample\MVC_Sample.sln" +..\nuget.exe restore "Samples\WebApp_sample\MVC_Sample\MVC_Sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\WebApp_sample\MVC_Sample\MVC_Sample.sln" pause diff --git a/root/programs/VB/1_DeleteDir.bat b/root/programs/VB/1_DeleteDir.bat index 30e06eed3..09d8d4f74 100644 --- a/root/programs/VB/1_DeleteDir.bat +++ b/root/programs/VB/1_DeleteDir.bat @@ -5,10 +5,10 @@ set DIRECTORIES=packages, obj, bin, bld, Temp, Build, PrecompiledWeb, .vs @echo Delete the %DIRECTORIES% folders. @echo -------------------------------------------------- -@rem カンマをスペースに変換 +@rem Turn the commas into spaces. set w1=%DIRECTORIES:,= % -@rem 連続したスペースを、スペース1個に変換 +@rem Collapse runs of spaces into a single space. set w2=%w1: = % for %%a in ( %w2% ) do ( @@ -24,10 +24,10 @@ set DIRECTORIES=Build, Build_net45, Build_net46, Build_net47, Build_net48, Build @echo Delete the %DIRECTORIES% folders. @echo -------------------------------------------------- -@rem カンマをスペースに変換 +@rem Turn the commas into spaces. set w1=%DIRECTORIES:,= % -@rem 連続したスペースを、スペース1個に変換 +@rem Collapse runs of spaces into a single space. set w2=%w1: = % for %%a in ( %w2% ) do ( diff --git a/root/programs/VB/3_Build_Business_net48.bat b/root/programs/VB/3_Build_Business_net48.bat index eb2b99deb..b22584bff 100644 --- a/root/programs/VB/3_Build_Business_net48.bat +++ b/root/programs/VB/3_Build_Business_net48.bat @@ -15,16 +15,11 @@ set CURRENT_DIR="%~dp0" @rem -------------------------------------------------- call %CURRENT_DIR%z_Common.bat -rem -------------------------------------------------- -rem Change the packages.config. -rem -------------------------------------------------- -call %CURRENT_DIR%z_ChangePackages_net48.bat - rem -------------------------------------------------- rem Build the Infrastructures rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Infrastructure\Business_net48.sln" +..\nuget.exe restore "Frameworks\Infrastructure\Business_net48.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Infrastructure\Business_net48.sln" pause diff --git a/root/programs/VB/5_Build_CLI_sample.bat b/root/programs/VB/5_Build_CLI_sample.bat deleted file mode 100644 index 76ec3394b..000000000 --- a/root/programs/VB/5_Build_CLI_sample.bat +++ /dev/null @@ -1,27 +0,0 @@ -setlocal - -@rem -------------------------------------------------- -@rem Turn off the echo function. -@rem -------------------------------------------------- -@echo off - -@rem -------------------------------------------------- -@rem Get the path to the executable file. -@rem -------------------------------------------------- -set CURRENT_DIR="%~dp0" - -@rem -------------------------------------------------- -@rem Execution of the common processing. -@rem -------------------------------------------------- -call %CURRENT_DIR%z_Common.bat - -rem -------------------------------------------------- -rem Batch build of Simple_CLI. -rem -------------------------------------------------- -..\nuget.exe restore "Samples\CLI_sample\Simple_CLI\Simple_CLI.sln" -%BUILDFILEPATH% %COMMANDLINE% "Samples\CLI_sample\Simple_CLI\Simple_CLI.sln" - -pause - -rem ------------------------------------------------------- -endlocal diff --git a/root/programs/VB/7_Build_Framework_WS.bat b/root/programs/VB/7_Build_Framework_WS.bat index 82d12f01a..349f072cf 100644 --- a/root/programs/VB/7_Build_Framework_WS.bat +++ b/root/programs/VB/7_Build_Framework_WS.bat @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of ServiceInterface(ASPNETWebService). rem -------------------------------------------------- -..\nuget.exe restore "Frameworks\Infrastructure\ServiceInterface\ASPNETWebService\ASPNETWebService.sln" +..\nuget.exe restore "Frameworks\Infrastructure\ServiceInterface\ASPNETWebService\ASPNETWebService.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Infrastructure\ServiceInterface\ASPNETWebService\ASPNETWebService.sln" pause @@ -34,6 +34,7 @@ pause rem -------------------------------------------------- rem Batch build of ServiceInterface(WCFService). rem -------------------------------------------------- +..\nuget.exe restore "Frameworks\Infrastructure\ServiceInterface\WCFService\WCFService.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Frameworks\Infrastructure\ServiceInterface\WCFService\WCFService.sln" pause diff --git a/root/programs/VB/8_Build_WSClntWin_sample.bat b/root/programs/VB/8_Build_WSClntWin_sample.bat index 63ff8d5e0..86b450e38 100644 --- a/root/programs/VB/8_Build_WSClntWin_sample.bat +++ b/root/programs/VB/8_Build_WSClntWin_sample.bat @@ -18,7 +18,7 @@ call %CURRENT_DIR%z_Common.bat rem -------------------------------------------------- rem Batch build of WSClientWin_sample. rem -------------------------------------------------- -..\nuget.exe restore "Samples\WS_sample\WSClient_sample\WSClientWin_sample\WSClientWin_sample.sln" +..\nuget.exe restore "Samples\WS_sample\WSClient_sample\WSClientWin_sample\WSClientWin_sample.sln" %NUGET_MSBUILD% %BUILDFILEPATH% %COMMANDLINE% "Samples\WS_sample\WSClient_sample\WSClientWin_sample\WSClientWin_sample.sln" pause diff --git a/root/programs/VB/Frameworks/Infrastructure/Business/packages.config b/root/programs/VB/Frameworks/Infrastructure/Business/packages.config deleted file mode 100644 index 146e9779b..000000000 --- a/root/programs/VB/Frameworks/Infrastructure/Business/packages.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/root/programs/VB/Frameworks/Infrastructure/Business/packages_net48.config b/root/programs/VB/Frameworks/Infrastructure/Business/packages_net48.config deleted file mode 100644 index 146e9779b..000000000 --- a/root/programs/VB/Frameworks/Infrastructure/Business/packages_net48.config +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/root/programs/VB/Frameworks/Infrastructure/BusinessRichClient_net48.sln b/root/programs/VB/Frameworks/Infrastructure/BusinessRichClient_net48.sln index e42ea8841..77ab85108 100644 --- a/root/programs/VB/Frameworks/Infrastructure/BusinessRichClient_net48.sln +++ b/root/programs/VB/Frameworks/Infrastructure/BusinessRichClient_net48.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30717.126 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Business.RichClient_net48", "Business\RichClient\Business.RichClient_net48.vbproj", "{7649D699-681D-4BE0-9A36-24B0815ABCEF}" EndProject diff --git a/root/programs/VB/Frameworks/Infrastructure/Business_net48.sln b/root/programs/VB/Frameworks/Infrastructure/Business_net48.sln index 44420de97..ae647b765 100644 --- a/root/programs/VB/Frameworks/Infrastructure/Business_net48.sln +++ b/root/programs/VB/Frameworks/Infrastructure/Business_net48.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30717.126 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Business_net48", "Business\Business_net48.vbproj", "{BCB5C7D0-FBE4-43E2-8BED-096700A6A187}" EndProject diff --git a/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/ASPNETWebService.sln b/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/ASPNETWebService.sln index 9123b07dc..a5281c2dd 100644 --- a/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/ASPNETWebService.sln +++ b/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/ASPNETWebService.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ASPNETWebService", "ASPNETWebService\ASPNETWebService.vbproj", "{CD8E53D2-B177-494B-AE08-1CEEF98E43D7}" EndProject diff --git a/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/ASPNETWebService/Web.config b/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/ASPNETWebService/Web.config index f166dff22..b668bfc3c 100644 --- a/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/ASPNETWebService/Web.config +++ b/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/ASPNETWebService/ASPNETWebService/Web.config @@ -188,4 +188,13 @@
    + + + + + + + + diff --git a/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/WCFService/WCFService.sln b/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/WCFService/WCFService.sln index 3ae9c5375..f2ce8ac5a 100644 --- a/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/WCFService/WCFService.sln +++ b/root/programs/VB/Frameworks/Infrastructure/ServiceInterface/WCFService/WCFService.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WCFService", "WCFService.vbproj", "{48114116-045D-4BB9-93FD-61306697F589}" EndProject diff --git a/root/programs/VB/Samples/2CS_sample/2CSClientWPF_sample/2CSClientWPF_sample.sln b/root/programs/VB/Samples/2CS_sample/2CSClientWPF_sample/2CSClientWPF_sample.sln index 5747b660d..5fb4dd51a 100644 --- a/root/programs/VB/Samples/2CS_sample/2CSClientWPF_sample/2CSClientWPF_sample.sln +++ b/root/programs/VB/Samples/2CS_sample/2CSClientWPF_sample/2CSClientWPF_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "2CSClientWPF_sample", "2CSClientWPF_sample.vbproj", "{3D1A8517-4939-424F-80D5-13E022870858}" EndProject diff --git a/root/programs/VB/Samples/2CS_sample/2CSClientWin_sample/2CSClientWin_sample.sln b/root/programs/VB/Samples/2CS_sample/2CSClientWin_sample/2CSClientWin_sample.sln index edb87e973..5059da6f0 100644 --- a/root/programs/VB/Samples/2CS_sample/2CSClientWin_sample/2CSClientWin_sample.sln +++ b/root/programs/VB/Samples/2CS_sample/2CSClientWin_sample/2CSClientWin_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "2CSClientWin_sample", "2CSClientWin_sample.vbproj", "{188A545F-5667-4349-949C-F1372AB592D5}" EndProject diff --git a/root/programs/VB/Samples/2CS_sample/AsyncEvent_sample/AsyncEvent_sample.sln b/root/programs/VB/Samples/2CS_sample/AsyncEvent_sample/AsyncEvent_sample.sln index 256a8c864..a178a2764 100644 --- a/root/programs/VB/Samples/2CS_sample/AsyncEvent_sample/AsyncEvent_sample.sln +++ b/root/programs/VB/Samples/2CS_sample/AsyncEvent_sample/AsyncEvent_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WindowsFormsApplication", "WindowsFormsApplication\WindowsFormsApplication.vbproj", "{F7C3BD4A-F362-4BF2-A3E5-0327038DF0D3}" EndProject diff --git a/root/programs/VB/Samples/2CS_sample/CustCtrl_sample/CustCtrl_sample.sln b/root/programs/VB/Samples/2CS_sample/CustCtrl_sample/CustCtrl_sample.sln index 880f5dee1..597bbf786 100644 --- a/root/programs/VB/Samples/2CS_sample/CustCtrl_sample/CustCtrl_sample.sln +++ b/root/programs/VB/Samples/2CS_sample/CustCtrl_sample/CustCtrl_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "CustCtrl_sample", "CustCtrl_sample.vbproj", "{43441376-87E2-4668-8722-8A094AE5C179}" EndProject diff --git a/root/programs/VB/Samples/2CS_sample/GenDaoAndBatUpd_sample/GenDaoAndBatUpd_sample.sln b/root/programs/VB/Samples/2CS_sample/GenDaoAndBatUpd_sample/GenDaoAndBatUpd_sample.sln index b36045efd..81fb35bc1 100644 --- a/root/programs/VB/Samples/2CS_sample/GenDaoAndBatUpd_sample/GenDaoAndBatUpd_sample.sln +++ b/root/programs/VB/Samples/2CS_sample/GenDaoAndBatUpd_sample/GenDaoAndBatUpd_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "GenDaoAndBatUpd_sample", "GenDaoAndBatUpd_sample.vbproj", "{BEE90CB9-1CDA-4914-BF07-786242CF425B}" EndProject diff --git a/root/programs/VB/Samples/2CS_sample/TimeStamp_sample/TimeStamp_sample.sln b/root/programs/VB/Samples/2CS_sample/TimeStamp_sample/TimeStamp_sample.sln index 299ca2036..73bd30aa0 100644 --- a/root/programs/VB/Samples/2CS_sample/TimeStamp_sample/TimeStamp_sample.sln +++ b/root/programs/VB/Samples/2CS_sample/TimeStamp_sample/TimeStamp_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "TimeStamp_sample", "TimeStamp_sample.vbproj", "{6FEA6EAD-BE15-46A0-A978-D2BA436C7EA6}" EndProject diff --git a/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample/RerunnableBatch_sample.sln b/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample/RerunnableBatch_sample.sln index 3934a3017..e76627730 100644 --- a/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample/RerunnableBatch_sample.sln +++ b/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample/RerunnableBatch_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "RerunnableBatch_sample", "RerunnableBatch_sample.vbproj", "{22C1AE38-FC51-41A6-870B-8B180B73CE67}" EndProject diff --git a/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample2/RerunnableBatch_sample2.sln b/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample2/RerunnableBatch_sample2.sln index 40291fca1..f3a85ed22 100644 --- a/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample2/RerunnableBatch_sample2.sln +++ b/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample2/RerunnableBatch_sample2.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "RerunnableBatch_sample2", "RerunnableBatch_sample2.vbproj", "{22C1AE38-FC51-41A6-870B-8B180B73CE67}" EndProject diff --git a/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample3/RerunnableBatch_sample3.sln b/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample3/RerunnableBatch_sample3.sln index 4d7dfeda7..125ccaf67 100644 --- a/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample3/RerunnableBatch_sample3.sln +++ b/root/programs/VB/Samples/Bat_sample/RerunnableBatch_sample3/RerunnableBatch_sample3.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "RerunnableBatch_sample3", "RerunnableBatch_sample3.vbproj", "{22C1AE38-FC51-41A6-870B-8B180B73CE67}" EndProject diff --git a/root/programs/VB/Samples/Bat_sample/SimpleBatch_sample/SimpleBatch_sample.sln b/root/programs/VB/Samples/Bat_sample/SimpleBatch_sample/SimpleBatch_sample.sln index 40e593416..147d792c3 100644 --- a/root/programs/VB/Samples/Bat_sample/SimpleBatch_sample/SimpleBatch_sample.sln +++ b/root/programs/VB/Samples/Bat_sample/SimpleBatch_sample/SimpleBatch_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SimpleBatch_sample", "SimpleBatch_sample.vbproj", "{AC32DA05-D3CA-4AD3-BC48-0746B457712D}" EndProject diff --git a/root/programs/VB/Samples/CLI_sample/DAG_Login_CLI/README.md b/root/programs/VB/Samples/CLI_sample/DAG_Login_CLI/README.md deleted file mode 100644 index 9597c69bf..000000000 --- a/root/programs/VB/Samples/CLI_sample/DAG_Login_CLI/README.md +++ /dev/null @@ -1,4 +0,0 @@ -DAG : OAuth 2.0 Device Authorization Grant - -System.CommandLineのbetaが解除され、Ctrl-Cで -CancellationTokenがハングする問題が修正されたら.NET5版から移植する。 \ No newline at end of file diff --git a/root/programs/VB/Samples/CLI_sample/LIR_Login_CLI/README.md b/root/programs/VB/Samples/CLI_sample/LIR_Login_CLI/README.md deleted file mode 100644 index f1fb33853..000000000 --- a/root/programs/VB/Samples/CLI_sample/LIR_Login_CLI/README.md +++ /dev/null @@ -1,4 +0,0 @@ -LIR : Loopback Interface Redirection of OAuth 2.0 for Native Apps - -System.CommandLineのbetaが解除され、Ctrl-Cで -CancellationTokenがハングする問題が修正されたら.NET5版から移植する。 \ No newline at end of file diff --git a/root/programs/VB/Samples/CLI_sample/Simple_CLI/README.md b/root/programs/VB/Samples/CLI_sample/Simple_CLI/README.md deleted file mode 100644 index 7abd73014..000000000 --- a/root/programs/VB/Samples/CLI_sample/Simple_CLI/README.md +++ /dev/null @@ -1,2 +0,0 @@ -System.CommandLine と Sharprompt を使用したCLIのサンプル / テンプレ -Sharpromptが.NET Fxのサポート終了したので、Simple_CLIをドロップした。 \ No newline at end of file diff --git a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample.sln b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample.sln index 39d8aa40f..196241256 100644 --- a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample.sln +++ b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WSClientWPF_sample", "WSClientWPF_sample.vbproj", "{5B5899DA-98C9-47B7-8832-A21768D788B0}" EndProject diff --git a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample_all.sln b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample_all.sln index 773f0a3bd..c069ce9fa 100644 --- a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample_all.sln +++ b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWPF_sample/WSClientWPF_sample_all.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WSClientWPF_sample", "WSClientWPF_sample.vbproj", "{5B5899DA-98C9-47B7-8832-A21768D788B0}" EndProject diff --git a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin2_sample/WSClientWin2_sample.sln b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin2_sample/WSClientWin2_sample.sln index 0ab460e90..fd2d7b989 100644 --- a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin2_sample/WSClientWin2_sample.sln +++ b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin2_sample/WSClientWin2_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WSClientWin2_sample", "WSClientWin2_sample.vbproj", "{FBA01A43-1A3F-4C92-ABD1-59C51005A084}" EndProject diff --git a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample.sln b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample.sln index d57fa8578..1cabb9b65 100644 --- a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample.sln +++ b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WSClientWin_sample", "WSClientWin_sample.vbproj", "{FBA01A43-1A3F-4C92-ABD1-59C51005A084}" EndProject diff --git a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample_all.sln b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample_all.sln index a998b2910..ace5eabd9 100644 --- a/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample_all.sln +++ b/root/programs/VB/Samples/WS_sample/WSClient_sample/WSClientWin_sample/WSClientWin_sample_all.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WSClientWin_sample", "WSClientWin_sample.vbproj", "{FBA01A43-1A3F-4C92-ABD1-59C51005A084}" EndProject diff --git a/root/programs/VB/Samples/WS_sample/WSServer_sample/WSServer_sample.sln b/root/programs/VB/Samples/WS_sample/WSServer_sample/WSServer_sample.sln index a096765e1..f27fff403 100644 --- a/root/programs/VB/Samples/WS_sample/WSServer_sample/WSServer_sample.sln +++ b/root/programs/VB/Samples/WS_sample/WSServer_sample/WSServer_sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WSServer_sample", "WSServer_sample.vbproj", "{15F78DB3-7AB0-4ADF-ADCA-48AFBD54C31E}" EndProject diff --git a/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample.sln b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample.sln index 9e830ef29..a26f2553b 100644 --- a/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample.sln +++ b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.13.35931.197 d17.13 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "MVC_Sample", "MVC_Sample\MVC_Sample.vbproj", "{A71DCE14-B551-44F4-BA4B-B12F41D01EC4}" EndProject diff --git a/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.js b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.js new file mode 100644 index 000000000..85a9b1dad --- /dev/null +++ b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.js @@ -0,0 +1,205 @@ +// Unobtrusive Ajax support library for jQuery +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// @version v3.2.6 +// +// Microsoft grants you the right to use these script files for the sole +// purpose of either: (i) interacting through your browser with the Microsoft +// website or online service, subject to the applicable licensing or use +// terms; or (ii) using the files as included with a Microsoft product subject +// to that product's license terms. Microsoft reserves all other rights to the +// files not expressly granted by Microsoft, whether by implication, estoppel +// or otherwise. Insofar as a script file is dual licensed under GPL, +// Microsoft neither took the code under GPL nor distributes it thereunder but +// under the terms set out in this paragraph. All notices and licenses +// below are for informational purposes only. + +/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */ +/*global window: false, jQuery: false */ + +(function ($) { + var data_click = "unobtrusiveAjaxClick", + data_target = "unobtrusiveAjaxClickTarget", + data_validation = "unobtrusiveValidation"; + + function getFunction(code, argNames) { + var fn = window, parts = (code || "").split("."); + while (fn && parts.length) { + fn = fn[parts.shift()]; + } + if (typeof (fn) === "function") { + return fn; + } + argNames.push(code); + return Function.constructor.apply(null, argNames); + } + + function isMethodProxySafe(method) { + return method === "GET" || method === "POST"; + } + + function asyncOnBeforeSend(xhr, method) { + if (!isMethodProxySafe(method)) { + xhr.setRequestHeader("X-HTTP-Method-Override", method); + } + } + + function asyncOnSuccess(element, data, contentType) { + var mode; + + if (contentType.indexOf("application/x-javascript") !== -1) { // jQuery already executes JavaScript for us + return; + } + + mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase(); + $(element.getAttribute("data-ajax-update")).each(function (i, update) { + var top; + + switch (mode) { + case "BEFORE": + $(update).prepend(data); + break; + case "AFTER": + $(update).append(data); + break; + case "REPLACE-WITH": + $(update).replaceWith(data); + break; + default: + $(update).html(data); + break; + } + }); + } + + function asyncRequest(element, options) { + var confirm, loading, method, duration; + + confirm = element.getAttribute("data-ajax-confirm"); + if (confirm && !window.confirm(confirm)) { + return; + } + + loading = $(element.getAttribute("data-ajax-loading")); + duration = parseInt(element.getAttribute("data-ajax-loading-duration"), 10) || 0; + + $.extend(options, { + type: element.getAttribute("data-ajax-method") || undefined, + url: element.getAttribute("data-ajax-url") || undefined, + cache: (element.getAttribute("data-ajax-cache") || "").toLowerCase() === "true", + beforeSend: function (xhr) { + var result; + asyncOnBeforeSend(xhr, method); + result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(element, arguments); + if (result !== false) { + loading.show(duration); + } + return result; + }, + complete: function () { + loading.hide(duration); + getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(element, arguments); + }, + success: function (data, status, xhr) { + asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html"); + getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(element, arguments); + }, + error: function () { + getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"]).apply(element, arguments); + } + }); + + options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" }); + + method = options.type.toUpperCase(); + if (!isMethodProxySafe(method)) { + options.type = "POST"; + options.data.push({ name: "X-HTTP-Method-Override", value: method }); + } + + // change here: + // Check for a Form POST with enctype=multipart/form-data + // add the input file that were not previously included in the serializeArray() + // set processData and contentType to false + var $element = $(element); + if ($element.is("form") && $element.attr("enctype") == "multipart/form-data") { + var formdata = new FormData(); + $.each(options.data, function (i, v) { + formdata.append(v.name, v.value); + }); + $("input[type=file]", $element).each(function () { + var file = this; + $.each(file.files, function (n, v) { + formdata.append(file.name, v); + }); + }); + $.extend(options, { + processData: false, + contentType: false, + data: formdata + }); + } + // end change + + $.ajax(options); + } + + function validate(form) { + var validationInfo = $(form).data(data_validation); + return !validationInfo || !validationInfo.validate || validationInfo.validate(); + } + + $(document).on("click", "a[data-ajax=true]", function (evt) { + evt.preventDefault(); + asyncRequest(this, { + url: this.href, + type: "GET", + data: [] + }); + }); + + $(document).on("click", "form[data-ajax=true] input[type=image]", function (evt) { + var name = evt.target.name, + target = $(evt.target), + form = $(target.parents("form")[0]), + offset = target.offset(); + + form.data(data_click, [ + { name: name + ".x", value: Math.round(evt.pageX - offset.left) }, + { name: name + ".y", value: Math.round(evt.pageY - offset.top) } + ]); + + setTimeout(function () { + form.removeData(data_click); + }, 0); + }); + + $(document).on("click", "form[data-ajax=true] :submit", function (evt) { + var name = evt.currentTarget.name, + target = $(evt.target), + form = $(target.parents("form")[0]); + + form.data(data_click, name ? [{ name: name, value: evt.currentTarget.value }] : []); + form.data(data_target, target); + + setTimeout(function () { + form.removeData(data_click); + form.removeData(data_target); + }, 0); + }); + + $(document).on("submit", "form[data-ajax=true]", function (evt) { + var clickInfo = $(this).data(data_click) || [], + clickTarget = $(this).data(data_target), + isCancel = clickTarget && (clickTarget.hasClass("cancel") || clickTarget.attr('formnovalidate') !== undefined); + evt.preventDefault(); + if (!isCancel && !validate(this)) { + return; + } + asyncRequest(this, { + url: this.action, + type: this.method || "GET", + data: clickInfo.concat($(this).serializeArray()) + }); + }); +}(jQuery)); diff --git a/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.min.js b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.min.js new file mode 100644 index 000000000..ae780ac8a --- /dev/null +++ b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Scripts/jquery.unobtrusive-ajax.min.js @@ -0,0 +1,16 @@ +// Unobtrusive Ajax support library for jQuery +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// @version v3.2.6 +// +// Microsoft grants you the right to use these script files for the sole +// purpose of either: (i) interacting through your browser with the Microsoft +// website or online service, subject to the applicable licensing or use +// terms; or (ii) using the files as included with a Microsoft product subject +// to that product's license terms. Microsoft reserves all other rights to the +// files not expressly granted by Microsoft, whether by implication, estoppel +// or otherwise. Insofar as a script file is dual licensed under GPL, +// Microsoft neither took the code under GPL nor distributes it thereunder but +// under the terms set out in this paragraph. All notices and licenses +// below are for informational purposes only. +!function(t){function a(t,a){for(var e=window,r=(t||"").split(".");e&&r.length;)e=e[r.shift()];return"function"==typeof e?e:(a.push(t),Function.constructor.apply(null,a))}function e(t){return"GET"===t||"POST"===t}function r(t,a){e(a)||t.setRequestHeader("X-HTTP-Method-Override",a)}function n(a,e,r){var n;r.indexOf("application/x-javascript")===-1&&(n=(a.getAttribute("data-ajax-mode")||"").toUpperCase(),t(a.getAttribute("data-ajax-update")).each(function(a,r){switch(n){case"BEFORE":t(r).prepend(e);break;case"AFTER":t(r).append(e);break;case"REPLACE-WITH":t(r).replaceWith(e);break;default:t(r).html(e)}}))}function i(i,u){var o,c,d,s;if(o=i.getAttribute("data-ajax-confirm"),!o||window.confirm(o)){c=t(i.getAttribute("data-ajax-loading")),s=parseInt(i.getAttribute("data-ajax-loading-duration"),10)||0,t.extend(u,{type:i.getAttribute("data-ajax-method")||void 0,url:i.getAttribute("data-ajax-url")||void 0,cache:"true"===(i.getAttribute("data-ajax-cache")||"").toLowerCase(),beforeSend:function(t){var e;return r(t,d),e=a(i.getAttribute("data-ajax-begin"),["xhr"]).apply(i,arguments),e!==!1&&c.show(s),e},complete:function(){c.hide(s),a(i.getAttribute("data-ajax-complete"),["xhr","status"]).apply(i,arguments)},success:function(t,e,r){n(i,t,r.getResponseHeader("Content-Type")||"text/html"),a(i.getAttribute("data-ajax-success"),["data","status","xhr"]).apply(i,arguments)},error:function(){a(i.getAttribute("data-ajax-failure"),["xhr","status","error"]).apply(i,arguments)}}),u.data.push({name:"X-Requested-With",value:"XMLHttpRequest"}),d=u.type.toUpperCase(),e(d)||(u.type="POST",u.data.push({name:"X-HTTP-Method-Override",value:d}));var p=t(i);if(p.is("form")&&"multipart/form-data"==p.attr("enctype")){var f=new FormData;t.each(u.data,function(t,a){f.append(a.name,a.value)}),t("input[type=file]",p).each(function(){var a=this;t.each(a.files,function(t,e){f.append(a.name,e)})}),t.extend(u,{processData:!1,contentType:!1,data:f})}t.ajax(u)}}function u(a){var e=t(a).data(d);return!e||!e.validate||e.validate()}var o="unobtrusiveAjaxClick",c="unobtrusiveAjaxClickTarget",d="unobtrusiveValidation";t(document).on("click","a[data-ajax=true]",function(t){t.preventDefault(),i(this,{url:this.href,type:"GET",data:[]})}),t(document).on("click","form[data-ajax=true] input[type=image]",function(a){var e=a.target.name,r=t(a.target),n=t(r.parents("form")[0]),i=r.offset();n.data(o,[{name:e+".x",value:Math.round(a.pageX-i.left)},{name:e+".y",value:Math.round(a.pageY-i.top)}]),setTimeout(function(){n.removeData(o)},0)}),t(document).on("click","form[data-ajax=true] :submit",function(a){var e=a.currentTarget.name,r=t(a.target),n=t(r.parents("form")[0]);n.data(o,e?[{name:e,value:a.currentTarget.value}]:[]),n.data(c,r),setTimeout(function(){n.removeData(o),n.removeData(c)},0)}),t(document).on("submit","form[data-ajax=true]",function(a){var e=t(this).data(o)||[],r=t(this).data(c),n=r&&(r.hasClass("cancel")||void 0!==r.attr("formnovalidate"));a.preventDefault(),(n||u(this))&&i(this,{url:this.action,type:this.method||"GET",data:e.concat(t(this).serializeArray())})})}(jQuery); \ No newline at end of file diff --git a/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Views/Shared/_Layout.cshtml b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Views/Shared/_Layout.cshtml index 781f02a0c..91b3a57ea 100644 --- a/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Views/Shared/_Layout.cshtml +++ b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Views/Shared/_Layout.cshtml @@ -69,10 +69,10 @@ @if (User.Identity.IsAuthenticated) { @* 各メニューは、ユーザーが認証されている時だけ表示する *@ -
  • +
  • メニュー1
  • -
  • +
  • メニュー2
  • } diff --git a/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Web.config b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Web.config index 2f4dc7567..217308637 100644 --- a/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Web.config +++ b/root/programs/VB/Samples/WebApp_sample/MVC_Sample/MVC_Sample/Web.config @@ -146,6 +146,13 @@ http://msdn2.microsoft.com/ja-jp/library/1d3t3c61.aspx http://msdn2.microsoft.com/ja-jp/library/1d3t3c61(VS.80).aspx --> + + + + diff --git a/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample.sln b/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample.sln index a3a3f0655..59f5d70c7 100644 --- a/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample.sln +++ b/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.13.35931.197 d17.13 +# Visual Studio Version 18 +VisualStudioVersion = 18.1.11312.151 d18.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "WebForms_Sample", "WebForms_Sample\WebForms_Sample.vbproj", "{CD8E53D2-B177-494B-AE08-1CEEF98E43D7}" EndProject diff --git a/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Scripts/touryo/common.js b/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Scripts/touryo/common.js index d9584cf27..7b2a6aa61 100644 --- a/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Scripts/touryo/common.js +++ b/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/Scripts/touryo/common.js @@ -44,6 +44,9 @@ //* 2019/03/04 西野 大介 二重送信防止のブラウザ判定処理を修正 //* 2019/03/04 西野 大介 WebForms版とMVC版のDiffを取り易く修正。 //* 2020/03/19 西野 大介 モダン・ブラウザ・サポート(2017/04/20)の制限事項解除 +//* 2026/08/01 玄人 幸道 業務モーダル画面を閉じた際に親画面がPost Backされない問題に対応 +//* (unloadイベントがブラウザ側で無効化されたため、 +//*  window.closedのポーリングによる終了検知を併用する) //********************************************************************************** // --------------------------------------------------------------- @@ -582,6 +585,46 @@ function Fx_InitPseudoDialog() { } +// --------------------------------------------------------------- +// 擬似DialogのiframeへURLを設定してよいかを判定 +// --------------------------------------------------------------- +// 引数 url +// 戻り値 true : 設定してよい / false : 設定しない +// --------------------------------------------------------------- +// このURLはフレームワーク(ShowModalScreen)が組み立てており、 +// 利用者の入力は入ってこない。AppScanのテストもクリアしている。 +// ここでの検証は、サンプルを手本にしたコードが動的なURLを +// 流し込んだ場合に備える多層防御である。 +// ・javascript: / data: / vbscript: … スクリプト実行を防ぐ +// ・//evil.example.com … 別オリジンの表示を防ぐ +// 相対URL(Aspx/... や /App/... )だけを通す。 +// --------------------------------------------------------------- +function Fx_IsSafeDialogUrl(url) { + + if (typeof url !== "string" || url === "") { + return false; + } + + // 前後の空白と制御文字を除いてから判定する + // ("java\tscript:" のような細工を防ぐ)。 + var u = url.replace(/[\u0000-\u0020]/g, ""); + + // スキーム付きは、http / https だけを通す。 + var scheme = u.match(/^([A-Za-z][A-Za-z0-9+.-]*):/); + if (scheme) { + var s = scheme[1].toLowerCase(); + return (s === "http" || s === "https"); + } + + // "//host/path" はプロトコル相対=別オリジンになり得るので通さない。 + if (u.indexOf("//") === 0) { + return false; + } + + // ここまで来たものは相対URL。 + return true; +} + // --------------------------------------------------------------- // Pseudo Dialog表示 // --------------------------------------------------------------- @@ -603,7 +646,16 @@ function Fx_DisplayPseudoDialog(ajaxPseudoDialog, url) { for (var i = 0; i < elementChildren.length; i++) { if (elementChildren[i].id === "FxIFrame") { - elementChildren[i].src = url; + // URLを検証してから設定する(CodeQL: DOM text reinterpreted as HTML)。 + if (Fx_IsSafeDialogUrl(url)) { + elementChildren[i].src = url; + } + else { + // 通さなかったことが分かるようにする(画面は空のままになる)。 + if (window.console && window.console.error) { + window.console.error("Fx_DisplayPseudoDialog: unsafe url was blocked."); + } + } } } @@ -938,11 +990,24 @@ function Fx_CallbackOfBusinessModalScreen() { // --------------------------------------------------------------- function Fx_CallbackOfBusinessModalScreen2() { + // ↓↓↓【追加】↓↓↓ + // unloadイベントとポーリングの両方から呼ばれる可能性があるため、二重実行を防ぐ。 + if (Fx_BusinessPseudoModelDialog === null + || Fx_BusinessPseudoModelDialog === undefined) { + return; + } + // ↑↑↑【追加】↑↑↑ + // イベントを外す if (Fx_BusinessPseudoModelDialog.closed) { // 閉じている。 $(Fx_BusinessPseudoModelDialog).off("unload"); //, Fx_CallbackOfBusinessModalScreen); Fx_BusinessPseudoModelDialog = null; + + // ↓↓↓【追加】↓↓↓ + // 終了検知のポーリングも解除する。 + Fx_ClearWatcherOfBusinessModalScreen(); + // ↑↑↑【追加】↑↑↑ } else { // 閉じていない。 // unloadのCallbackを"再度"仕掛ける。 @@ -1129,8 +1194,61 @@ function Fx_SetCallbackOfBusinessModalScreen() { // --------------------------------------------------------------- function Fx_SetCallbackOfBusinessModalScreen2() { $(Fx_BusinessPseudoModelDialog).on("unload", Fx_CallbackOfBusinessModalScreen); + + // ↓↓↓【追加】↓↓↓ + // unloadイベントは、モダン・ブラウザ側で無効化が進んでおり発火しないことがある + // (Chromeでは document.featurePolicy.allowsFeature("unload") が false になる)。 + // このため、window.closed のポーリングでも子画面の終了を検知する。 + Fx_SetWatcherOfBusinessModalScreen(); + // ↑↑↑【追加】↑↑↑ } +// ↓↓↓【追加】↓↓↓ + +// Business疑似Model(実体はModeless)Screenの終了監視タイマ +var Fx_WatcherOfBusinessPseudoModelDialog = null; + +// --------------------------------------------------------------- +// モダンブラウザ版(window.closedのポーリングによる終了検知を仕掛ける) +// --------------------------------------------------------------- +// 引数 - +// 戻り値 - +// --------------------------------------------------------------- +function Fx_SetWatcherOfBusinessModalScreen() { + + // 多重に仕掛けない。 + Fx_ClearWatcherOfBusinessModalScreen(); + + Fx_WatcherOfBusinessPseudoModelDialog = setInterval( + function () { + if (Fx_BusinessPseudoModelDialog === null + || Fx_BusinessPseudoModelDialog === undefined + || Fx_BusinessPseudoModelDialog.closed) { + + // 閉じられたので、監視を終了して後処理を実行する。 + Fx_ClearWatcherOfBusinessModalScreen(); + Fx_CallbackOfBusinessModalScreen(); + } + }, + TimeLag4BusinessPseudoModelDialog); +} + +// --------------------------------------------------------------- +// モダンブラウザ版(終了検知のポーリングを解除する) +// --------------------------------------------------------------- +// 引数 - +// 戻り値 - +// --------------------------------------------------------------- +function Fx_ClearWatcherOfBusinessModalScreen() { + + if (Fx_WatcherOfBusinessPseudoModelDialog !== null) { + clearInterval(Fx_WatcherOfBusinessPseudoModelDialog); + Fx_WatcherOfBusinessPseudoModelDialog = null; + } +} + +// ↑↑↑【追加】↑↑↑ + //********************************************************************************** // フレームワーク機能(Ajax Extension) //********************************************************************************** diff --git a/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/web.config b/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/web.config index 5d2dbb8f9..43c39cb56 100644 --- a/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/web.config +++ b/root/programs/VB/Samples/WebApp_sample/WebForms_Sample/WebForms_Sample/web.config @@ -142,6 +142,13 @@ http://msdn2.microsoft.com/ja-jp/library/1d3t3c61.aspx http://msdn2.microsoft.com/ja-jp/library/1d3t3c61(VS.80).aspx --> + + + + + diff --git a/root/programs/VB/z_ChangePackages_net48.bat b/root/programs/VB/z_ChangePackages_net48.bat deleted file mode 100644 index 2e9eba484..000000000 --- a/root/programs/VB/z_ChangePackages_net48.bat +++ /dev/null @@ -1 +0,0 @@ -copy /Y "Frameworks\Infrastructure\Business\packages_net48.config" "Frameworks\Infrastructure\Business\packages.config" diff --git a/root/programs/VB/z_Common.bat b/root/programs/VB/z_Common.bat index fa944d38b..a3aa0f1af 100644 --- a/root/programs/VB/z_Common.bat +++ b/root/programs/VB/z_Common.bat @@ -1,5 +1,12 @@ @rem -------------------------------------------------- @rem Execution of the common processing. +@rem +@rem Kept in step with CS\z_Common.bat. Fix both when changing either. +@rem +@rem NOTE: keep this file pure ASCII (#532). +@rem Non-ASCII text is decoded with the console code page, which can +@rem misalign the parser and execute the tail of an @rem line. +@rem chcp inside the file makes it worse, so it is not used here. @rem -------------------------------------------------- @rem -------------------------------------------------- @@ -36,18 +43,128 @@ if exist "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Curre set BUILDFILEPATH17="C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe" ) -set BUILDFILEPATH=%BUILDFILEPATH17% +if exist "C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe" ( + set BUILDFILEPATH18="C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe" +) + +echo BUILDFILEPATH2.0 %BUILDFILEPATH2.0% +echo BUILDFILEPATH3.5 %BUILDFILEPATH3.5% +echo BUILDFILEPATH4.0 %BUILDFILEPATH4.0% +echo BUILDFILEPATH15 %BUILDFILEPATH15% +echo BUILDFILEPATH16 %BUILDFILEPATH16% +echo BUILDFILEPATH17 %BUILDFILEPATH17% +echo BUILDFILEPATH18 %BUILDFILEPATH18% + +@rem -------------------------------------------------- +@rem Resolve MSBuild with vswhere, independently of the VS edition. +@rem The fixed paths above only look for Community, so this also finds +@rem Professional / Enterprise / BuildTools. +@rem -------------------------------------------------- +set VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +set BUILDFILEPATH= + +if exist %VSWHERE% ( + for /f "usebackq tokens=*" %%i in ( + `%VSWHERE% -latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe` + ) do set BUILDFILEPATH="%%i" +) + +@rem -------------------------------------------------- +@rem Fallback, for when vswhere is missing or resolves nothing. +@rem -------------------------------------------------- +if not defined BUILDFILEPATH set BUILDFILEPATH=%BUILDFILEPATH18% +if not defined BUILDFILEPATH set BUILDFILEPATH=%BUILDFILEPATH17% +if not defined BUILDFILEPATH set BUILDFILEPATH=%BUILDFILEPATH16% + +echo BUILDFILEPATH %BUILDFILEPATH% + +@rem -------------------------------------------------- +@rem Stop when nothing was found. +@rem Carrying on with an empty value makes "/p:Configuration=..." run as +@rem the command itself, which is hard to diagnose. +@rem -------------------------------------------------- +if not defined BUILDFILEPATH ( + echo [ERROR] MSBuild.exe was not found. + echo Check the Visual Studio or Build Tools installation. + exit /b 1 +) + +@rem -------------------------------------------------- +@rem The MSBuild passed to nuget.exe restore. +@rem +@rem nuget.exe detects MSBuild on its own, but when another product that +@rem ships MSBuild is installed - SQL Server Management Studio, say - it +@rem can pick that one instead. +@rem e.g. "Using MSBuild version ... from 'C:\Program Files\Microsoft SQL +@rem Server Management Studio 22\Release\MSBuild\Current\bin'." +@rem +@rem That MSBuild has no Microsoft.WebApplication.targets for web apps, and +@rem the project.assets.json it writes does not match the real build, so +@rem errors like these follow. +@rem error MSB4226: The imported project "...WebApplications\ +@rem Microsoft.WebApplication.targets" was not found. +@rem error : Your project file doesn't list 'win' as a "RuntimeIdentifier". +@rem +@rem The folder resolved above is therefore passed explicitly. The build +@rem batches pass it as: nuget.exe restore "....sln" %NUGET_MSBUILD% +@rem -------------------------------------------------- +for %%i in (%BUILDFILEPATH%) do set MSBUILDDIR=%%~dpi + +@rem Strip the trailing backslash. In -MSBuildPath "...\" the \" would be +@rem read as an escape and the argument would break. +if defined MSBUILDDIR set MSBUILDDIR=%MSBUILDDIR:~0,-1% + +set NUGET_MSBUILD=-MSBuildPath "%MSBUILDDIR%" + +echo NUGET_MSBUILD %NUGET_MSBUILD% @echo -------------------------------------------------- @echo The choice of build configuration (Debug / Release). +@echo BUILD_CONFIG names the configuration (Debug or Release). +@echo DEBUG_TYPE is full, pdbonly, portable, embedded or none. +@echo https://learn.microsoft.com/dotnet/csharp/language-reference/compiler-options/code-generation#debugtype @echo -------------------------------------------------- set BUILD_CONFIG=Debug -set VisualStudioVersion=17.0 + +@rem -------------------------------------------------- +@rem DEBUG_TYPE honours the value the caller has already set, as on the CS +@rem side (#531). VB publishes no NuGet packages today, so nothing passes +@rem portable yet, but the two files are kept in step. +@rem -------------------------------------------------- +if not defined DEBUG_TYPE set DEBUG_TYPE=full + +@rem -------------------------------------------------- +@rem VisualStudioVersion comes from the same VS as the MSBuild resolved +@rem above. +@rem +@rem A web app vbproj builds its targets path from this value. +@rem $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) +@rem +@rem +@rem A fixed value breaks on a machine that only has another VS version. +@rem e.g. windows-latest on GitHub Actions is VS 2022 = 17.x, so passing +@rem 18.0 makes it look for v18.0\WebApplications\ and fail MSB4226. +@rem -------------------------------------------------- +set VSVER_MAJOR= + +if exist %VSWHERE% ( + for /f "usebackq tokens=1 delims=." %%i in ( + `%VSWHERE% -latest -products * -requires Microsoft.Component.MSBuild -property installationVersion` + ) do set VSVER_MAJOR=%%i +) + +@rem Fall back to the previous value when vswhere is missing or resolves +@rem nothing. +if not defined VSVER_MAJOR set VSVER_MAJOR=18 + +set VisualStudioVersion=%VSVER_MAJOR%.0 +echo VisualStudioVersion %VisualStudioVersion% @echo -------------------------------------------------- @echo Creating a build command. @echo -------------------------------------------------- -set COMMANDLINE=/p:Configuration=%BUILD_CONFIG% -v:d +@set COMMANDLINE=/p:Configuration=%BUILD_CONFIG% -v:d +set COMMANDLINE=/p:Configuration=%BUILD_CONFIG% /p:DebugType=%DEBUG_TYPE% -v:d @echo -------------------------------------------------- @echo Set the proxy settings of Nuget. diff --git a/root/programs/VB/z_Common2.bat b/root/programs/VB/z_Common2.bat index a7c6d4661..4aa58775c 100644 --- a/root/programs/VB/z_Common2.bat +++ b/root/programs/VB/z_Common2.bat @@ -10,17 +10,35 @@ reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" @rem -------------------------------------------------- @rem Specifying Build tool. @rem -------------------------------------------------- -set BUILDFILEPATH2.0="%PROGRAM_FILES%\Microsoft Visual Studio 8\Common7\IDE\devenv.com" -set BUILDFILEPATH3.5="%PROGRAM_FILES%\Microsoft Visual Studio 9.0\Common7\IDE\devenv.com" -set BUILDFILEPATH4.0="%PROGRAM_FILES%\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com" -set BUILDFILEPATH4.5="%PROGRAM_FILES%\Microsoft Visual Studio 11.0\Common7\IDE\devenv.com" +@rem 8=VS2005/.NET2.0, 9=VS2008/.NET3.5, 10= 2010/.NET4.0, +@rem 11=VS2012/.NET4.5, 12=VS2013/.NET4.5.1, 14=VS2015/.NET4.6, +@rem 15=VS2017/.NET4.6.2, 16=VS2019/.NET4.7.2/.NETCore3.x, +@rem 17=VS2022/.NET4.8/.NET6, 18=VS2026/.NET4.8/.NET10 + +set BUILDFILEPATH2.0 ="%PROGRAM_FILES%\Microsoft Visual Studio 8\Common7\IDE\devenv.com" +set BUILDFILEPATH3.5 ="%PROGRAM_FILES%\Microsoft Visual Studio 9.0\Common7\IDE\devenv.com" +set BUILDFILEPATH4.0 ="%PROGRAM_FILES%\Microsoft Visual Studio 10.0\Common7\IDE\devenv.com" +set BUILDFILEPATH4.5 ="%PROGRAM_FILES%\Microsoft Visual Studio 11.0\Common7\IDE\devenv.com" set BUILDFILEPATH4.5.1="%PROGRAM_FILES%\Microsoft Visual Studio 12.0\Common7\IDE\IDE\devenv.com" -set BUILDFILEPATH4.6="%PROGRAM_FILES%\Microsoft Visual Studio 14.0\Common7\IDE\devenv.com" -set BUILDFILEPATH4.7="%PROGRAM_FILES%\Microsoft Visual Studio\2017\Community\Common7\IDE\devenv.exe" -set BUILDFILEPATH4.8="%PROGRAM_FILES%\Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.exe" -set BUILDFILEPATH6.0="%PROGRAM_FILES%\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" +set BUILDFILEPATH4.6 ="%PROGRAM_FILES%\Microsoft Visual Studio 14.0\Common7\IDE\devenv.com" +set BUILDFILEPATH4.7 ="%PROGRAM_FILES%\Microsoft Visual Studio\2017\Community\Common7\IDE\devenv.exe" +set BUILDFILEPATH4.8 ="%PROGRAM_FILES%\Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.exe" +set BUILDFILEPATH6.0 ="%PROGRAM_FILES%\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe" +set BUILDFILEPATH10.0 ="%PROGRAM_FILES%\Microsoft Visual Studio\18\Community\Common7\IDE\devenv.exe" + +echo BUILDFILEPATH2.0 %BUILDFILEPATH2.0% +echo BUILDFILEPATH3.5 %BUILDFILEPATH3.5% +echo BUILDFILEPATH4.0 %BUILDFILEPATH4.0% +echo BUILDFILEPATH4.5 %BUILDFILEPATH4.0% +echo BUILDFILEPATH4.5.1 %BUILDFILEPATH4.5.1% +echo BUILDFILEPATH4.6 %BUILDFILEPATH4.6% +echo BUILDFILEPATH4.7 %BUILDFILEPATH4.7% +echo BUILDFILEPATH4.8 %BUILDFILEPATH4.8% +echo BUILDFILEPATH6.0 %BUILDFILEPATH6.0% +echo BUILDFILEPATH10.0 %BUILDFILEPATH10.0% -set BUILDFILEPATH=BUILDFILEPATH6.0 +set BUILDFILEPATH=BUILDFILEPATH10.0 +echo BUILDFILEPATH %BUILDFILEPATH% @echo -------------------------------------------------- @echo The choice of build configuration (Debug / Release). diff --git a/root/programs/1_DeleteDir.bat b/root/programs/bak/1_DeleteDir.bat similarity index 81% rename from root/programs/1_DeleteDir.bat rename to root/programs/bak/1_DeleteDir.bat index c15ae227c..c4ce3eaa7 100644 --- a/root/programs/1_DeleteDir.bat +++ b/root/programs/bak/1_DeleteDir.bat @@ -5,10 +5,10 @@ set DIRECTORIES=packages, obj, bin, bld, Temp, PrecompiledWeb, MigrationBackup, @echo Delete the %DIRECTORIES% folders. @echo -------------------------------------------------- -@rem カンマをスペースに変換 +@rem Turn the commas into spaces. set w1=%DIRECTORIES:,= % -@rem 連続したスペースを、スペース1個に変換 +@rem Collapse runs of spaces into a single space. set w2=%w1: = % for %%a in ( %w2% ) do ( @@ -25,10 +25,10 @@ set DIRECTORIES=Build, Build_net45, Build_net46, Build_net47, Build_net48, Build @echo Delete the %DIRECTORIES% folders. @echo -------------------------------------------------- -@rem カンマをスペースに変換 +@rem Turn the commas into spaces. set w1=%DIRECTORIES:,= % -@rem 連続したスペースを、スペース1個に変換 +@rem Collapse runs of spaces into a single space. set w2=%w1: = % for %%a in ( %w2% ) do ( diff --git a/root/programs/1_DeleteFile.bat b/root/programs/bak/1_DeleteFile.bat similarity index 100% rename from root/programs/1_DeleteFile.bat rename to root/programs/bak/1_DeleteFile.bat diff --git a/root/programs/9_CICD.bat b/root/programs/bak/9_CICD.bat similarity index 100% rename from root/programs/9_CICD.bat rename to root/programs/bak/9_CICD.bat diff --git a/root/programs/9_LogMonitoring.ps1 b/root/programs/bak/9_LogMonitoring.ps1 similarity index 100% rename from root/programs/9_LogMonitoring.ps1 rename to root/programs/bak/9_LogMonitoring.ps1 diff --git a/root/programs/BackupCICDLog/z_GrepResult1.bat b/root/programs/bak/BackupCICDLog/z_GrepResult1.bat similarity index 100% rename from root/programs/BackupCICDLog/z_GrepResult1.bat rename to root/programs/bak/BackupCICDLog/z_GrepResult1.bat diff --git a/root/programs/BackupCICDLog/z_GrepResult2.bat b/root/programs/bak/BackupCICDLog/z_GrepResult2.bat similarity index 100% rename from root/programs/BackupCICDLog/z_GrepResult2.bat rename to root/programs/bak/BackupCICDLog/z_GrepResult2.bat diff --git a/root/programs/BackupCICDLog/z_GrepResult3.bat b/root/programs/bak/BackupCICDLog/z_GrepResult3.bat similarity index 100% rename from root/programs/BackupCICDLog/z_GrepResult3.bat rename to root/programs/bak/BackupCICDLog/z_GrepResult3.bat diff --git a/root/programs/bak/Readme.txt b/root/programs/bak/Readme.txt new file mode 100644 index 000000000..ad01c458e --- /dev/null +++ b/root/programs/bak/Readme.txt @@ -0,0 +1 @@ +もともと programs 直下に置いていたものが、エージェンティックなリリースワークの新設で二軍落ち。 \ No newline at end of file