TFS 2018 のリリース管理を使用して、IISにデプロイする
またも、3か月近く間が空いてしまいました。ネタはたまっているので、間隔をなるべくおかずに書いて行きたいものです。
以下の記事では、ビルド時のオプションで発行まで行いましたが、今回はリリース管理機能を使ってIISにデプロイしてみました。
ググってみると、以下のサイトに情報を発見。
IIS Web App ManageとIIS Web App Deployというものが用意されているらしい。
リリース定義の作成
リリース定義を新規作成すると、テンプレートの選択で「IIS Web サイトと SQL Database の配置」があったので、これを適用しました。
すると、新しいリリース定義の画面になり、タスクタブを表示するとIIS Deploymentが出来て、その下にIIS Web App ManageとIIS Web App Deployがあり、IIS Deploymentと同じレベルにSQL Deploymentが出来て、その下にSQL DB Deployがありました。
データベースは既に作成済なので、SQL Deploymentは不要。このまま削除しても良いけれど、リリース定義のテンプレートをよく見ると「IIS Web サイトの配置」があったので、このテンプレートでリリース定義を作り直しました。
さらに上記サイト*1によると、IIS Web App Manageは、IISのWebサイト作成に使用するようだ。今回は既に動いているWebアプリケーションのデプロイ方法を変更するので、IISの設定は変更しないため、タスクは削除しました。
各種パラメータの設定
必要なパラメータを設定します。
まず、配置プロセスで環境名とWebサイト名を設定した。Webサイト名は、動いているアプリケーションのIISのWebサイト名を設定。
次に、IIS Deploymentで表示名はそのままにして、配置グループの入力が必要になりました。配置グループはまだ作成していなかったので、歯車ボタンか、リリースタブの並びの配置グループをクリックして配置グループを新規作成しました。
配置グループ作成後に表示される登録スクリプトをコピーして、配置するサーバ上で「管理者 PowerShell コマンド プロンプト」から実行してもらうとターゲットタブに対象サーバが表示されます。
ちなみに登録スクリプトを表示する場合は、詳細タブを表示するか登録リンクをクリックすればよいです。
配置グループを作成すると、配置プールが一緒に作成されます。これは他のプロジェクトでも同じサーバに配置をしたい場合に使用することが出来ます。配置グループの詳細タブの配置プールの管理リンクから表示することが出来ます。
次は、IIS Web App Deployで仮想アプリケーションにアプリケーション名を入力します。パッケージまたはフォルダーはそのままにします。それ以外は特に入力していません。
パイプラインの設定
パイプラインの設定の前に、ビルドの定義を変更し、Web Deployではなく、Web デプロイ パッケージに変更します。 MSBuild引数に以下の値を設定します。
設定した値:
/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactstagingdirectory)\\"
PackageLocationで$(build.artifactstagingdirectory)
を使用すことで、その後の成果物の発行タスクでビルド結果がTFSに登録されるようにしています。
ハイプラインの設定に戻り、成果物のソースの種類でビルドを選択し、ソースとして、使用しているビルド定義を選択します。
成果物の継続的配置トリガーを有効にし、環境の配置前の条件でトリガーにリリース後を選択する。承認などは設定していません。
上記の設定を行うと、ビルド成功後に、リリース管理機能によって、サーバへのデプロイが行われるようになります。
以上。
動作環境:
- TFS 2018 Update 3
- 配置先サーバ:Windows Server 2016
- ビルドエージェントの動作するPC:Windows 10 Pro 1809以降
- 開発環境:Visual Studio 2017
- ASP.NET MVC 5
ASP.NET MVCでjQuery DataTablesを使用する
何番煎じなのかわかりませんが、jQuery DataTablesを使ってみたので、メモを残しておきます。試したバージョンは、1.10.12。
公式サイト:
ASP.NET MVCでは、NuGetを使用して導入します。jQueryはバージョン2系でも問題ありませんでした。バージョン3系は試していません。
基本的な使い方
thead、tbodyタグで作成したテーブルのtableタグにid属性(mytable)を設定し、画面上もしくは外部のjsファイルで、以下のようにidを指定してDataTableメソッド呼び出すだけです。
$(function () { $('#mytable').DataTable(); });
ASP.NET MVCでは、jsファイルやcssファイルはバンドル機能を使って配布されるので、BundleConfig.csに追記しないと参照できません。
bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( "~/Scripts/bootstrap.js", "~/Scripts/respond.js", "~/Scripts/DataTables/jquery.dataTables.js", //←追加 "~/Scripts/DataTables/dataTables.bootstrap.js")); //←追加 bundles.Add(new StyleBundle("~/Content/css").Include( "~/Content/bootstrap.css", "~/Content/DataTables/css/dataTables.bootstrap.css", //←追加 "~/Content/site.css"));
日本語化
CDN上のファイルを参照する方法が良く紹介されていますが、社内システム等で外部へのアクセスを避けたい場合もあるので、CDNを使わない方法で行きます。
先ほどのDataTableメソッドの前に以下を記述することで、デフォルトメッセージを日本語で上書きします。
// デフォルトの設定を変更 $.extend($.fn.dataTable.defaults, { language: { "sEmptyTable": "テーブルにデータがありません", "sInfo": " _TOTAL_ 件中 _START_ から _END_ まで表示", "sInfoEmpty": " 0 件中 0 から 0 まで表示", "sInfoFiltered": "(全 _MAX_ 件より抽出)", "sInfoPostFix": "", "sInfoThousands": ",", "sLengthMenu": "_MENU_ 件表示", "sLoadingRecords": "読み込み中...", "sProcessing": "処理中...", "sSearch": "検索:", "sZeroRecords": "一致するレコードがありません", "oPaginate": { "sFirst": "先頭", "sLast": "最終", "sNext": "次", "sPrevious": "前" }, "oAria": { "sSortAscending": ": 列を昇順に並べ替えるにはアクティブにする", "sSortDescending": ": 列を降順に並べ替えるにはアクティブにする" } } }); $('#mytable').DataTable();
sSearchの値が、検索テキストボックスの左側の文字列ですが、画面よって変えたい場合もあると思います。その場合は、DataTableメソッド呼び出し時の引数で指定することが出来ます。
$('#mytable').DataTable({ language: { "sSearch": "絞り込み:" } });
列の設定
特定の列を検索対象から外したり、ソートできないようにしたり、非表示にしたりしたい場合は、columnDefsというプロパティに設定します。
$('#mytable').DataTable({ language: { "sSearch": "絞り込み:" }, columnDefs: [ //targetsは0始まり { targets: 0, width: 43, searchable: false, orderable: false }, //1列目 検索対象外、ソート不可 { targets: 1, width: 85, orderable: false }, //2列目 検索対象、ソート不可 { targets: 2, visible: false }, //3列目 非表示 ] });
パフォーマンスについて
HTMLを全て読み込んだ後、JavaScriptでページネーションや検索の制御をしているため、表示するレコード数が多いほど遅くなります。
試してみたところ12列の表で、1000行くらいまでがストレスなく表示できる感じでした。
以上です。
SQL ServerのCHECK制約の設定方法
簡単な入力制限であれば、テーブルにCHECK制約をつける手もあるかなと思い、SQL ServerのCHECK制約の設定方法について調査しました。
SSDT(サーバーエクスプローラー)
- SSDTは、テーブル定義画面でCHECK 制約を追加できる。
- CHECK制約の対象カラムは、カラムを選択した時に、CHECK制約がハイライトされる。
- CHECK制約は、CREATE TABLEのCONSTRAINT句で記述する。
SQLにALTER TABLEを書いても実行できたが、テーブル定義画面を閉じて開くとCREATE TABLE文に戻ってしまった。
SSDT(オブジェクトエクスプローラー)
- テーブル定義画面を開く前に、制約だけを開くと、ALTER TABLE形式のSQLが表示される。
SSMS
- デザイン画面では、CHECK制約は表示されない。
- 制約を開くと、制約編集用の画面が表示される。
- 「テーブルをスクリプト化」で、ALTER TABLE形式のSQLが表示される。
- 制約に対して「制約をスクリプト化」をしてもALTER TABLE形式のSQLが表示される。
Code First(Entity Framework 6.2)
- CHECK 制約を記述出来ないため、DBを再作成するとCHECK 制約は消える。
- CHECK 制約を設定したい場合は、DBInitilizerクラスで、DB再作成後にALTER TABLE形式のSQLを実行する必要がある。
以上
(まとめ)Redmineチケットの帳票出力にSSRSを使用する
これまで書いてきた記事を読めば、Redmineチケットの帳票出力にSQL Server Report Services(SSRS)を使用する事が出来ます。
出来る事ならRedmineのワークフローを使用して、Web上(Redmine上)で完結する事が望ましいのでしょうが、そうも行かない事もあると思います。
そんな時に、Redmineを使用するのをあきらめてしまうのではなく、紙と併用して使っても良いのではないかと思いました。
RedmineのPDF作成機能や、ブラウザによる印刷では、レイアウトの調整は出来ないので(view customize pluginで印刷用にゴリゴリ画面を書き換えたくは無いですよね?)、何か良い方法はないかと思いたどり着きました。
後から参照しやすいように、各記事へのリンクをまとめます。
SQL Server Reporting Services(SSRS)のデータソースで外部サービスを設定する - redwarrior’s diary
SSRSのコンポーネントで条件を指定して、同じデータセットからレコード別の値を取得する - redwarrior’s diary
チケット内容の出力であれば、テキストボックスが主になるので上記で済むと思いますが、一覧を使用したい場合は以下を参照してください。
SSRSで表や、一覧を使用してデータセットの内容を一覧表示する - redwarrior’s diary
以上。
SSRSで表や、一覧を使用してデータセットの内容を一覧表示する
前回の記事で、テキストボックスにデータセットの値を表示しました。
今回は、データセットのレコードを繰り返し表示する方法として、SQL Server Reporting Services(SSRS)のコンポーネントである表(テーブル)と一覧の 使い方を紹介します。
公式サイトは以下の通りです。
上記を既に読んでいるのであれば、ここから先を読んでもあまり得るものはないでしょう。ただ公式は情報量が多くて読み通すのに時間がかかるため、最低限のざっくりした内容を書きたいと思います。
SSRSの表(テーブル)の使い方について
表(テーブル)は、データセットのレコードを最も簡単に繰り返し表示できるコンポーネントです。
表(テーブル)を配置したらセルの右上のアイコンをクリックして、データソース、データセット、カラムを順番に選択します。列を追加した場合は、データセットのカラムを選択するだけです。
列の挿入・削除、見出し行(ヘッダー)や行の挿入・削除も右クリックメニューで行う事ができます。
これでデータセットのレコード数だけ行が表示されます。
SSRSの一覧の使い方について
名前だけで考えると表よりも一覧の方が単純そうに感じますが、SSRSではそうでもありません。配置しただけでは、表コンポーネントのようにカラムを選択するアイコンは出てきません。
一覧は、繰り返し表示する中身を自由にレイアウトする事ができるコンポーネントです。一覧で表示されたエリアに、テキストボックスや表を自由に配置した後、テキストボックス/表の値としてデータセットのカラムの選択ができます。
選択したデータセットのレコード数だけレイアウトした内容で行が表示されます。
まとめ
データセットのレコードを繰り返し表示する方法として、「表」と「一覧」を紹介しました。 集計機能が不要で、一覧形式で表示したいだけであれば「表」と「一覧」だけで十分なので、「マトリックス」は使用していません。
以上です。
(追伸)記事を書くために調べた所、「表」のセル内に「表」や「一覧」や「テキストボックス」を埋め込んで自由にレイアウトができる事がわかりました。
SSRSのコンポーネントで条件を指定して、同じデータセットからレコード別の値を取得する
前回の記事では、データセットのフィルターを使用してカスタムフィールドを絞り込むという方法を紹介しましたが、
カスタムフィールドの値を表示するテキストボックスを複数用意して、それぞれ別のカスタムフィールドの値を表示したい
という場合は、カスタムフィールドの数だけデータセットが必要になってしまいます。
そしてデータセット毎にデータを取得するため、データセットが外部サービスを参照している場合、データセットの数だけリクエストが発生します。
これは出来れば避けたい。どうすれば良いでしょうか?
データセットでフィルターを使用せず(複数レコードのまま)に、コンポーネントで式を使用し、条件を指定して値を取得すると良いです。
具体例
例えばテキストボックスの場合、テキストボックスの中ではなく、テキストボックス全体を選択すると右クリックメニューに式が表示されます。そこで式を選択すると式の入力画面になります。*1
式では関数を使用して、レコードを絞り込むことが出来ます。主に使うのは、First関数とLookup関数。
First関数
データセットにレコードが1件しか含まれていない場合や、先頭のレコードだけで良い場合は、First関数を使用します。
=First(Fields!value.Value, "データセット名")
第1引数=値に使用するカラム(value)、第2引数=対象のデータセット名
Lookup関数
条件を指定してレコードを取得するのには、LookUp関数を使用します。カスタムフィールドをidで絞り込み、入力値(value)を表示したい場合は、以下のように記述します。
=Lookup("1",Fields!id.Value,Fields!value.Value, "データセット名")
第1引数=条件値(idカラムの値)、第2引数=条件に使用するカラム(id)、第3引数=値に使用するカラム(value)、第4引数=対象のデータセット名
データセット名を同じ値にして、テキストボックスごとにidの値を変更することで、同じデータセットを使用しつつ、それぞれ別のカスタムフィールド値を表示することが出来ました。
以上。
*1:テキストが既に入力されていると式を入力する事が出来ないのでテキストは空にしておきます。
SSRSのデータセットにRedmineのチケット情報を読み込む
前の記事で、データソースにRedmine Rest Api を指定したので、これを使用して、データセットにチケット情報を読み込む方法を調査しました。Visual Studio上でプレビューして動作を確認しています。
検証環境
- SQL Server 2017 Standard の Reporting Services
- Visual Studio 2017 Professional
- Redmine 3.4.8
データセットの読み込み
実は、データソースに指定したURLが、チケット番号を指定して情報を取得するAPIのURLなので、データセットではデータソースを選択するだけで、いくらかの情報は取得できます。
しかし、余分な情報はデータセットの時点で削っておきたい!XMLデータの場合は、SQLの代わりに要素パス構文というのを使用します。
詳しい内容は、リンク先を読んでもらうとして、今回は「カスタムフィールドの一覧を取得する」データセットと「チケットのステータスを取得する」データセットの二つを作成しました。
カスタムフィールドの一覧を取得する
要素パス構文で記述したクエリ
issue {}/custom_fields {}/custom_field {@id,@name}/value
実行結果(カスタムフィールド数分表示される)
id | name | value |
---|---|---|
1 | カスタムフィールド名A | カスタムフィールド値1 |
2 | カスタムフィールド名B | カスタムフィールド値2 |
チケットのステータスを取得する
要素パス構文で記述したクエリ
issue {id,subject,created_on,updated_on}/status {@name}
実行結果
id | subject | created_on | updated_on | name |
---|---|---|---|---|
100 | チケット名1 | チケット作成日時 | チケット更新日時 | ステータス値 |
データの絞り込み
チケットのステータスを取得するクエリは、1レコードしか返ってこないけれど、カスタムフィールドの一覧を取得するクエリは複数レコード返ってきます。1つのカスタムフィールドの値を取得したい場合もあるでしょう。
要素パス構文には、条件による絞り込みの機能は無さそうなので、この場合、データセットのフィルターを使用します。データセットのプロパティからフィルターを開いて「id = 数値」のように指定して絞り込む事が出来ます。
以上です。