Web Deployの整理
ASP.NET MVC 5 の Web Deploy について自分用にまとめたメモ。
2018/12/11 追記
作業手順の順番を変更しました。
旧)Web Deploy 3.6のインストール→管理サービスのインストール
新)管理サービスのインストール→Web Deploy 3.6のインストール
対象環境
Web Deployment Agent Service と Web Management Service どちらを使う?(サーバー側)
Web Deployment Agent Service=Remote Agent Service
- 日本語では「Web 配置エージェントサービス」とか「リモート エージェント サービス」と呼ばれる。
- Windows Server 2003/IIS 6 は、これ一択。
- Web Deployのインストール時に、選択する必要あり。
- 管理者のみ使用可能。
参照URL:Introduction to Web Deploy | Microsoft Docs
Web Management Service(WMSVC)=IISの管理サービス
- 日本語では「Web 管理サービス」「IIS 管理サービス」と呼ばれる。
- Windows Server 2008/IIS 7 から登場した。
- サーバーOSに搭載されている。(参照URLより。最新OSは確認していない)
- 設定を行うことで、管理者以外も使用可能。
参照URL:Visual Studio 2010 [発行]機能で配置可能とするためのサーバー設定 – monoe's blog
Visual Studio と WebMatrix どちらを使う?(クライアント側)
Visual Studioで公開する場合
Visual Studioの公開(発行)は、Web Deployment Agent Service、Web Management Service の両方を使用可能。
WebMatrixで公開する場合
WebMatrixのWeb Deployは、Web Management Serviceを使用する。
Web Deployを行うユーザーは、Windowsユーザー(ドメインユーザー)とIISの内部ユーザー(IISマネージャー ユーザー)どちらを使う?
Windows ユーザーを使用する場合
特に追加の設定なし
IIS 内で完結するユーザー(IISマネージャー ユーザー)を使用する場合
「IIS マネージャー ユーザー」を選択して、ユーザーを追加する。
参照URL:IIS 7の新しい運用形態 | Think IT(シンクイット)
実際に選択したのは?
サーバー側:Web Management Service
Web Management Serviceの方が新しく、機能も充実しているので、使わない手はない。
クライアント側:Visual Studio
Visual Studioを使用して開発しているため。
Web Deployを行うユーザー:Windowsユーザー(ドメインユーザー)
ドメインユーザー以外は、Web Deployを行わないため。
作業手順
上記条件でWeb Deployを行う場合のサーバー側の作業手順を以下にまとめる。
.NET Framework 4.6のインストール
サーバーマネージャーを起動し、[サーバーの役割] で [Web サーバー(IIS)] > [管理ツール] > [管理サービス] をインストール
Web Deploy 3.6のインストール
セットアップの種類で「完全」を選択する。
もしくは、リモート エージェント サービスは不要なのでインストールしない。それ以外はインストールする。IIS マネージャーを起動し、[管理サービス] で [リモート接続を有効にする] をチェックする。
Web Deployに必要。有効にしないとローカルコンピューターからしか管理サービスに接続できない。Web Deploy対象のサイトを右クリックし、[展開] > [Web 配置による発行の有効化] を行う。
- ユーザーを入力する。プルダウンに無い場合は右側のボタンを押下して選択する。
- 保存先を指定する。
保存された設定ファイルは、開発環境でインポート出来る。
「管理サービスの委任」の設定が行われる。(一部の設定は、「接続の検証」時に行われているかもしれない)
ユーザーのアクセス許可を設定する必要はあるか?
[Web 配置による発行の有効化] で選択したユーザーは設定されているので、新たに設定する必要はない。
管理サービスの委任を設定する必要はあるか?
[Web 配置による発行の有効化] で選択したユーザーは設定されているので、新たに設定する必要はない。
フォルダのアクセス権限を編集する必要はあるか?
[Web 配置による発行の有効化] を行ったサイトのフォルダ(Default Web Siteならば、wwwrootフォルダ)に対して、選択したユーザーにはフルコントロールが与えられるので、新たに設定する必要はない。
参照URL:
Visual StudioのWeb発行がどうしても上手くいきません
https://officeyuai.net/%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E9%96%8B%E7%99%BA/net-mvc/mvc_trable1/
その他・関連用語
Windows Process Activation Service(Windows プロセス アクティブ化サービス:WAS)
WCFでHTTPだけでなく、他プロトコルの通信もサポートするためのもの。Web Deployment Agent Serviceと勘違いしやすい。ポート80をリッスンしている。
World Wide Web Publishing Service(World Wide Web 発行サービス:W3SVC)
IISを起動・停止するためのサービス。Web Management Serviceと勘違いしやすい。
git-flow や GitHub Flow を運用しやすいようにアレンジして使っていました
ちょっと前の開発プロジェクトで使っていたGitを使用したワークフローについて書いてみます。
ざっくり言うと、リポジトリを一つしか使用しない git-flow って感じです。もしくはルールを追加した GitHub Flow でしょうか。
以下、箇条書きで書きます。
master, develop, featureブランチを用意します。機能を実装するときは、developerブランチからfeatureブランチ配下に「今日の日付+バックログ項目やタスクのID」という命名でブランチを作成します。
featureブランチは実装中、ある程度のまとまりでサーバーにプッシュします。実装完了後は、サーバー上でプルリクエストを作成してレビューを行い、レビューが完了したらdevelopブランチにマージします。
リリースを行う時は、最新のdevelopブランチから、release作業用ブランチを作成して、リリース準備作業を行ったらmasterブランチ(とdevelopブランチ)にマージし、masterブランチをサーバーにプッシュしてから、masterブランチにてリリースデプロイを行います。
コードレビューは、既に書きましたがfeatureブランチからdeveloperブランチへのマージ時に行います。リリース作業のチェックは、プッシュ後にmasterブランチで確認します。
ツールは、git-flow関連はSourceTreeを使っていて、それ以外は必要に応じてコマンドラインなども使用していました。
プルリクエストを作成するまでは、featureブランチは担当者専用のブランチなので、ローカルのブランチでコミットの順番を入れ替えたり、集約してコミットログを整理した後、サーバーに強制プッシュすることもOKです。
CI/CDを行うとしたら、feature->developへのマージ後や、masterのプッシュ後になると思います。
プロジェクトは変わってしまったのですが、中々良く出来ていると思ったので、覚えている限り書いてみました。
(小ネタ)Microsoft の Markdown ガイダンス
ELMAH と Glimpse を組み合わせて使用する
ASP.NET でデバッグ作業目的に使用するツールとして、ELMAH と Glimpse がある。
ELMAH に関しては、「プログラミングMicrosoft ASP.NET MVC 第3版ASP.NET MVC 5 対応版」で知りました。
Glimpse については、以下のサイトで知りました。
両方とも便利そうなので、合わせて導入しようとしたら、ちょっとコツが必要だったので記録に残す。
インストール方法
ELMAH
NuGetでELMAH.MVCをインストールする。
Glimpse
NuGetでGlimpse.Mvc5、Glimpse.EF6をインストールする。
ELMAHとGlimpseを組み合わせる
GlimpseからELMAHを参照できるようにするツールをインストールする。具体的には、NuGetでGlimpse.Elmahをインストールする。
この状態で、ELMAHを参照しようとすると以下のJavaScriptエラーがVisual Studio上で発生します。
[続行する]をクリックすれば、いちおう画面を見ることは出来ます。また、GlimpseのElmahタブからも概要は見れます。
しかし、やはりエラーメッセージは無くしておきたい。
対処方法
エラー内容からELMAHの画面で発生しているようなので、Glimpseの対象からELMAHを外します。以下のようにurisタグで指定したパスを除外できます。
<glimpse defaultRuntimePolicy="On" endpointBaseUri="~/Glimpse.axd"> <!-- For more information on how to configure Glimpse, please visit http://getglimpse.com/Help/Configuration or access {your site}/Glimpse.axd for even more details and a Configuration Tool to support you. --> <runtimePolicies> <uris> <add regex=".*/elmah"/> </uris> </runtimePolicies> </glimpse>
これでELMAHのページを直接開いた場合も、GlimpseからELMAHのページを開いた場合もエラーがなくなります。
盲点
ここまで設定して導入したELMAHですが、Glimpseに比べて実はあまり使っていません。
なぜかというと、運用フェイズに入っていないと言うのもありますが、Unity(DIコンテナの方)を使うと、スタックトレースがDI対象のインターフェースまでしか出ないため、YSOD(Yellow Screen of Death)を見てもエラーが特定できないためです。
それでも、いつエラーが起きたかを後から見返せるので、設定しておいて損はないと思います。
動作環境
- Visual Studio 2015 Professional
- ASP.NET MVC 5.2.3
- Entity Framework 6.1.3
- Elmah.Mvc 2.1.2
- Glimpse.Mvc5 1.5.3
- Glimpse.EF6 1.6.5
- Glimplse.Elmah 1.1.1
AutoMapper は使わない!
ASP.NET MVC で開発をしている時に気になってくるのが、Entity Framework で作成したエンティティと画面で使用するモデル(ViewModel)の詰め替えをどうするかということ。
少しググってみると、AutoMapper を使用すると良いと出てくる。プロパティを一つずつコピーするのはいかにも冗長な作業でなんとかしたいと思うのはわかるし、一行でプロパティのコピーが出来るのは便利だと思う。ただし、これはやりたくない。
.NET ではなく Java の話だけど、DXO(Data Exchange Object)というものが話題になったことがあった。その時に DBFlute というフレームワークを作っている id:jflute さんの書いていたことが印象に残っている。
DXO を提供するツールを使うことで開発は少し削減されるかもしれないが、エラー発生時にデバッグで悩んでしまえばトータルではマイナスになるという趣旨の内容だったと思う。
その後調べた範囲では DXO を使ったツールはそれほど流行らなかったようで、この主張は的を得ていると思った。
AutoMapper はその時の DXO を .NET で実現するものだと思えるので、使わない方が良いと思っている。
しかし、冗長なコードを書くのもまた面倒なのでどうしたものかなと思い、でも、C# には LINQ があるからそんなに冗長にはならないのではないかとも思った。
今回、実際に試してみた結果、想像以上にスッキリと書けて、マジで AutoMapper は使わなくても良いと思えたので、ここに方法を記す。
前置きがものすごい長くなったが、ソースコードで表すとこんな感じ。
モデルクラス(Book.cs)
public class Book { public string Title { get; set; } public Author author { get; set; } }
モデルクラス(Author.cs)
public class Author { public string FirstName { get; set; } public string LastName { get; set; } }
ViewModel(BookViewModel.cs)
public class BookViewModel { public string Title { get; set; } public string AuthorName { get; set; } }
詰め替え処理
//単独オブジェクト BookViewModel vmodel = BuildViewModel(book); //コレクション IEnumerable<BookViewModel> vmodels = books.Select(BuildViewModel); //booksはIEnumerable<Book> //詰め替えを行うメソッド private static BookViewModel BuildViewModel(Book book) { return new BookViewModel { Title = book.Title, AuthorName = book.FirstName + " " + book.LastName, }; }
staticの詰め替え用のメソッドを用意する必要はあるが、呼び出す側は単独オブジェクトだろうが、コレクションだろうが1行で済む。
プロパティ名の異なるクラス間の変更や、コレクションの変更では、AutoMapperでも対応付けるための記述が必要になるので、AutoMapperを使って手間を省けるのはプロパティが同じクラス間だけなのではと思う。
プロジェクト都合にも寄るのかもしれないけど、デバッグ時のわかりやすさと天秤にかけると、自分はAutoMapperはいらないかなと思った。
ASP.NET MVC でテキストボックスとラベルに別の書式を使用する
ASP.NET MVCでは、ビューヘルパーを使用することで、テキストボックス等のフォーム部品をシンプルに記述することが出来ますよね。
さらに、***Forメソッドを使用すると、モデルクラスのプロパティを扱うことが出来て、EditorForメソッドやDisplayForメソッドではプロパティに指定した属性によってデフォルトの表示を変更することが出来ます。
例えば、以下のように日付や小数点の書式を指定したりします。(ASP.NET MVC5で確認しました。)
モデルクラス
[DisplayName("公開日")] [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}", ApplyFormatInEditMode = true)] public DateTime Published { get; set; } [DisplayName("小数点を含む数値")] [DisplayFormat(DataFormatString = "{0:0.000}", ApplyFormatInEditMode = true)] public decimal Value { get; set; }
ビュー(編集画面)
@Html.EditorFor(model => model.Published) @Html.EditorFor(model => model.Value)
ビュー(一覧画面)
@Html.DisplayFor(model => model.Published) @Html.DisplayFor(model => model.Value)
この場合、ApplyFormatInEditModeが true に設定されているので、テキストボックスにも、ラベル(プロパティの値を文字列として出力することをここでは指します)にも同じ書式で表示されます。(公開日:2016/08/22、小数点を含む数値:1089.123)
課題
仕様変更で、テキストボックスとラベルで別の書式を使用することになりました。どうすれば良いでしょう?
ちなみに、以下のようにモデルに複数する方法はDisplayFormat属性が重複するのでダメでした。
[DisplayName("公開日")] [DisplayFormat(DataFormatString = "{0:yyyy年MM月dd日}", ApplyFormatInEditMode = false)] //表示はyyyy年MM月dd日にしたい [DisplayFormat(DataFormatString = "{0:yyyy/MM/dd}", ApplyFormatInEditMode = true)] public DateTime Published { get; set; } [DisplayName("小数点を含む数値")] [DisplayFormat(DataFormatString = "{0:#,0.000}", ApplyFormatInEditMode = false)] //表示はカンマ区切りにしたい [DisplayFormat(DataFormatString = "{0:0.000}", ApplyFormatInEditMode = true)] public decimal Value { get; set; }
対処法
調べた結果、以下の方法で書式を分けることが出来ました。2か所変更します。
- モデルのDisplayFormat属性のApplyFormatInEditModeをfalseにする
- EditorForメソッドを使用せず、TextBoxForで書式を指定する。
変更後はこうなります。ビュー(一覧画面)に変更はありません。
モデルクラス
[DisplayName("公開日")] [DisplayFormat(DataFormatString = "{0:yyyy年MM月dd日}", ApplyFormatInEditMode = false)] //表示はyyyy年MM月dd日にしたい public DateTime Published { get; set; } [DisplayName("小数点を含む数値")] [DisplayFormat(DataFormatString = "{0:#,0.000}", ApplyFormatInEditMode = false)] //表示はカンマ区切りにしたい public decimal Value { get; set; }
ビュー(編集画面)
@Html.TextBoxFor(model => model.Published, "{0:yyyy/MM/dd}") //入力はyyyy/MM/dd @Html.TextBoxFor(model => model.Value, "{0:0.000}") //入力はカンマ区切りなし
これでテキストボックスとラベルに別の書式を設定することが出来ました。
応用編
ビューを修正したくない場合は、独自テンプレートを用意することでビューの修正を無しにできます。
DateTime.cshtml
@model DateTime? @Html.TextBoxFor(model => model, "{0:yyyy/MM/dd}") //入力はyyyy/MM/dd
decimal.cshtml
@model decimal? @Html.TextBoxFor(model => model, "{0:0.000}") //入力はカンマ区切りなし
大した修正ではないですが、知っておくと地味に役立ちます。
ASP.NET MVC で備考入力欄を作成する方法のまとめ
久しぶりの更新になってしまった。ブログを書く時間を意識してとるように気をつけよう。
入力フォームを作る時に、大体作ることになる備考入力欄について、ASP.NET MVC での実装方法のポイントをまとめてみました。
はじめに
ASP.NET MVC 5で動作を確認しています。Scaffolding機能を使用して、Model,Controller,Viewを作成しておいてください。
備考を格納するプロパティはstring型を想定しています。
textareaタグで表示する
デフォルトではテキストボックス(<input type="text">)で表示されるのを、テキストエリア(<textarea>)で表示するように変更します。
[方法] モデルクラスのプロパティにDataType.MultilineTextを指定したDataType属性を設定します。
public class Member { //他のプロパティは省略 [DisplayName("備考")] [DataType(DataType.MultilineText)] public string Note { get; set; }
複数行で表示する
textareaタグで表示しただけでは、見た目がテキストボックスと変わらないため複数行での入力をできるようにします。
[方法] ビュー(cshtml)のHtml.EditorForメソッドの引数にrowsを追加します。今回は4行で表示します。
@Html.EditorFor(model => model.Note, new { htmlAttributes = new { @class = "form-control", rows = "4" } })
備考欄にフォーカスした時に文字入力を日本語入力に変更する
見た目は良くなりました。数値を入力するテキストボックス等から、備考欄にフォーカスが移った場合は日本語入力が可能になっていると便利なので設定を行います。
[方法] ビュー(cshtml)のHtml.EditorForメソッドの引数にスタイルシートとしてime-mode: active;
を設定します。
@Html.EditorFor(model => model.Note, new { htmlAttributes = new { @class = "form-control", rows = "4", style = "ime-mode: active;" } })
あるいは直接指定せずに、Site.css
(元から用意されているcssファイル)に書き込んだ方が便利かもしれません。
textarea.form-control { ime-mode: active; }
ime-modeは他にも値があるので、テキストボックスとテキストエリアに別の値を設定することで、フォーム入力少し便利になりそうです。
参考サイト: