redwarrior’s diary

C#, ASP.NET, WEB, G*などの雑多な情報

NLogを使用して、ログの出力先を切り替える(TFSのリリース管理を使用する版)

Visual Studioからの発行について、以前に以下の記事を書きました。

redwarrior.hateblo.jp

ひとつ前の記事でリリース管理について書きました。

redwarrior.hateblo.jp

リリース管理を使用して、ログの出力先を切り替えたいと思ったので、やり方を調べました。

ポイントは以下の2つ
  • NLog.Extended を使用して、appSettingsに設定した値を出力先に使用する
  • TFSのリリース管理で、appSettingsの値を置き換える

NLog.Extended を使用して、appSettingsに設定した値を出力先に使用する

NLog.Extendedは、v4.0.0.1を使用しました。

Web.configを以下のように編集します。

<appSettings>
  <add key="webpages:Version" value="3.0.0.0" />
  <add key="webpages:Enabled" value="false" />
  <add key="ClientValidationEnabled" value="true" />
  <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  <add key="LogDir" value="c:/inetpub/logs/AppLogs"/>    <!-- この行を追加 -->
</appSettings>
~中略~
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true">
  <targets>
    <!-- 変更前
    <target xsi:type="File" name="f" fileName="c:/inetpub/logs/AppLogs/app.log"
            layout="${longdate} [${uppercase:${level:padding=-5}}][${logger:shortName=True}] ${message} ${exception:format=tostring}"
            archiveEvery="Day"
            archiveFileName="c:/inetpub/logs/AppLogs/app_{#}.log"
            archiveNumbering="Date"
            archiveDateFormat="yyyyMMdd"
            maxArchiveFiles="30"
            keepFileOpen="true">
    </target>
    -->
    <!-- 変更後 -->
    <target xsi:type="File" name="f" fileName="${appsetting:name=LogDir}/app.log"
            layout="${longdate} [${uppercase:${level:padding=-5}}][${logger:shortName=True}] ${message} ${exception:format=tostring}"
            archiveEvery="Day"
            archiveFileName="${appsetting:name=LogDir}/app_{#}.log"
            archiveNumbering="Date"
            archiveDateFormat="yyyyMMdd"
            maxArchiveFiles="30"
            keepFileOpen="true">
    </target>
  </targets>
  <rules>
    <logger name="*" minlevel="Trace" writeTo="f" />
  </rules>
</nlog>

targetタグのfileName、archiveFileNameを、appSettingsに設定したLogDirを使って書き換えています。

TFSのリリース管理で、appSettingsの値を置き換える

リリース管理のタスクで、XML変数置換にチェックをつけて、変数タブでLogDir変数を追加します。

f:id:redwarrior:20191227194826p:plain

f:id:redwarrior:20191227194456p:plain

これで、TFSでリリースする時にログの出力先を変更することが出来ました。

ちなみに、これに書き換えた後にVisual Studioからの発行する場合は、同様にappSettingsを置き換えるようにWeb.***.configの修正が必要になります。

以上

動作環境:

TFS 2018 のリリース管理を使用して、IISにデプロイする

またも、3か月近く間が空いてしまいました。ネタはたまっているので、間隔をなるべくおかずに書いて行きたいものです。

以下の記事では、ビルド時のオプションで発行まで行いましたが、今回はリリース管理機能を使ってIISにデプロイしてみました。

redwarrior.hateblo.jp

ググってみると、以下のサイトに情報を発見。

stackoverflow.com

IIS Web App ManageIIS Web App Deployというものが用意されているらしい。

リリース定義の作成

リリース定義を新規作成すると、テンプレートの選択で「IIS Web サイトと SQL Database の配置」があったので、これを適用しました。

f:id:redwarrior:20191221154900p:plain

すると、新しいリリース定義の画面になり、タスクタブを表示するとIIS Deploymentが出来て、その下にIIS Web App ManageIIS Web App Deployがあり、IIS Deploymentと同じレベルにSQL Deploymentが出来て、その下にSQL DB Deployがありました。

f:id:redwarrior:20191221154921p:plain

データベースは既に作成済なので、SQL Deploymentは不要。このまま削除しても良いけれど、リリース定義のテンプレートをよく見ると「IIS Web サイトの配置」があったので、このテンプレートでリリース定義を作り直しました。

さらに上記サイト*1によると、IIS Web App Manageは、IISのWebサイト作成に使用するようだ。今回は既に動いているWebアプリケーションのデプロイ方法を変更するので、IISの設定は変更しないため、タスクは削除しました。

f:id:redwarrior:20191221155056p:plain

各種パラメータの設定

必要なパラメータを設定します。

まず、配置プロセスで環境名とWebサイト名を設定した。Webサイト名は、動いているアプリケーションのIISのWebサイト名を設定。

次に、IIS Deploymentで表示名はそのままにして、配置グループの入力が必要になりました。配置グループはまだ作成していなかったので、歯車ボタンか、リリースタブの並びの配置グループをクリックして配置グループを新規作成しました。

f:id:redwarrior:20191221155416p:plain

配置グループ作成後に表示される登録スクリプトをコピーして、配置するサーバ上で「管理者 PowerShell コマンド プロンプト」から実行してもらうとターゲットタブに対象サーバが表示されます。
ちなみに登録スクリプトを表示する場合は、詳細タブを表示するか登録リンクをクリックすればよいです。

f:id:redwarrior:20191221155908p:plain

配置グループを作成すると、配置プールが一緒に作成されます。これは他のプロジェクトでも同じサーバに配置をしたい場合に使用することが出来ます。配置グループの詳細タブの配置プールの管理リンクから表示することが出来ます。

次は、IIS Web App Deployで仮想アプリケーションにアプリケーション名を入力します。パッケージまたはフォルダーはそのままにします。それ以外は特に入力していません。

パイプラインの設定

パイプラインの設定の前に、ビルドの定義を変更し、Web Deployではなく、Web デプロイ パッケージに変更します。 MSBuild引数に以下の値を設定します。

f:id:redwarrior:20191221160219p:plain

設定した値:

/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactstagingdirectory)\\"

PackageLocationで$(build.artifactstagingdirectory)を使用すことで、その後の成果物の発行タスクでビルド結果がTFSに登録されるようにしています。

ハイプラインの設定に戻り、成果物のソースの種類でビルドを選択し、ソースとして、使用しているビルド定義を選択します。

成果物の継続的配置トリガーを有効にし、環境の配置前の条件でトリガーにリリース後を選択する。承認などは設定していません。

f:id:redwarrior:20191221160646p:plain f:id:redwarrior:20191221160659p:plain

上記の設定を行うと、ビルド成功後に、リリース管理機能によって、サーバへのデプロイが行われるようになります。

以上。

動作環境:

ASP.NET MVCでjQuery DataTablesを使用する

何番煎じなのかわかりませんが、jQuery DataTablesを使ってみたので、メモを残しておきます。試したバージョンは、1.10.12。

公式サイト:

datatables.net

ASP.NET MVCでは、NuGetを使用して導入します。jQueryはバージョン2系でも問題ありませんでした。バージョン3系は試していません。

www.nuget.org

基本的な使い方

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で印刷用にゴリゴリ画面を書き換えたくは無いですよね?)、何か良い方法はないかと思いたどり着きました。

後から参照しやすいように、各記事へのリンクをまとめます。

  1. SQL Server Reporting Services(SSRS)のデータソースで外部サービスを設定する - redwarrior’s diary

  2. SSRSのデータセットにRedmineのチケット情報を読み込む - redwarrior’s diary

  3. SSRSのコンポーネントで条件を指定して、同じデータセットからレコード別の値を取得する - redwarrior’s diary

チケット内容の出力であれば、テキストボックスが主になるので上記で済むと思いますが、一覧を使用したい場合は以下を参照してください。

SSRSで表や、一覧を使用してデータセットの内容を一覧表示する - redwarrior’s diary

以上。

SSRSで表や、一覧を使用してデータセットの内容を一覧表示する

前回の記事で、テキストボックスにデータセットの値を表示しました。

今回は、データセットのレコードを繰り返し表示する方法として、SQL Server Reporting Services(SSRS)のコンポーネントである表(テーブル)と一覧の 使い方を紹介します。

公式サイトは以下の通りです。

docs.microsoft.com

上記を既に読んでいるのであれば、ここから先を読んでもあまり得るものはないでしょう。ただ公式は情報量が多くて読み通すのに時間がかかるため、最低限のざっくりした内容を書きたいと思います。

SSRSの表(テーブル)の使い方について

表(テーブル)は、データセットのレコードを最も簡単に繰り返し表示できるコンポーネントです。

表(テーブル)を配置したらセルの右上のアイコンをクリックして、データソース、データセット、カラムを順番に選択します。列を追加した場合は、データセットのカラムを選択するだけです。

f:id:redwarrior:20190712114159p:plain
コンポーネント

列の挿入・削除、見出し行(ヘッダー)や行の挿入・削除も右クリックメニューで行う事ができます。

これでデータセットのレコード数だけ行が表示されます。

SSRSの一覧の使い方について

名前だけで考えると表よりも一覧の方が単純そうに感じますが、SSRSではそうでもありません。配置しただけでは、表コンポーネントのようにカラムを選択するアイコンは出てきません。

一覧は、繰り返し表示する中身を自由にレイアウトする事ができるコンポーネントです。一覧で表示されたエリアに、テキストボックスや表を自由に配置した後、テキストボックス/表の値としてデータセットのカラムの選択ができます。

f:id:redwarrior:20190712120110p:plain
一覧コンポーネント

選択したデータセットのレコード数だけレイアウトした内容で行が表示されます。

まとめ

データセットのレコードを繰り返し表示する方法として、「表」と「一覧」を紹介しました。 集計機能が不要で、一覧形式で表示したいだけであれば「表」と「一覧」だけで十分なので、「マトリックス」は使用していません。

以上です。

(追伸)記事を書くために調べた所、「表」のセル内に「表」や「一覧」や「テキストボックス」を埋め込んで自由にレイアウトができる事がわかりました。

SSRSのコンポーネントで条件を指定して、同じデータセットからレコード別の値を取得する

前回の記事では、データセットのフィルターを使用してカスタムフィールドを絞り込むという方法を紹介しましたが、

カスタムフィールドの値を表示するテキストボックスを複数用意して、それぞれ別のカスタムフィールドの値を表示したい

f:id:redwarrior:20190629113135p:plain
複数カスタムフィールド

という場合は、カスタムフィールドの数だけデータセットが必要になってしまいます。

そしてデータセット毎にデータを取得するため、データセットが外部サービスを参照している場合、データセットの数だけリクエストが発生します

これは出来れば避けたい。どうすれば良いでしょうか?

データセットでフィルターを使用せず(複数レコードのまま)に、コンポーネントで式を使用し、条件を指定して値を取得すると良いです。

具体例

例えばテキストボックスの場合、テキストボックスの中ではなく、テキストボックス全体を選択すると右クリックメニューに式が表示されます。そこで式を選択すると式の入力画面になります。*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:テキストが既に入力されていると式を入力する事が出来ないのでテキストは空にしておきます。