付録: Fix It サンプル アプリケーション (Building Real World Cloud Apps with Azure (Azure で実世界のクラウド アプリをビルドする))
電子書籍『Building Real World Cloud Apps with Azure』は、Scott Guthrie が開発したプレゼンテーションに基づくものです。 クラウド向けの Web アプリの開発を成功させるために役立つ 13 のパターンとプラクティスについて説明します。 電子書籍の詳細については、最初のチャプターを参照してください。
電子書籍『Building Real World Cloud Apps with Azure』のこの付録には、ダウンロードできる Fix It サンプル アプリケーションに関する追加情報を提供する以下のセクションが含まれています。
- 既知の問題
- ベスト プラクティス
- ローカル コンピューターで Visual Studio からアプリを実行する方法
- Windows PowerShell スクリプトを使用してベース アプリを Azure App Service Web Apps にデプロイする方法
- Windows PowerShell スクリプトのトラブルシューティング
- キュー処理を使用してアプリを Azure App Service Web Apps と Azure Cloud Service にデプロイする方法
既知の問題
Fix It アプリは、この電子書籍に記載されているいくつかのパターンを可能な限り簡単に説明するために開発されました。 一方で、この電子書籍は実世界で使用可能なアプリをビルドすることを題材にしているため、この Fix It コードには、リリースされるソフトウェアに対して行うレビューとテスト同様のプロセスを適用しています。 それによって多くの問題が検出されましたが、実世界で使用されているアプリケーションと同様に、これらの問題の中には修正したものもあれば、先のリリースに先送りしたものもあります。
次の一覧には、実稼働アプリケーションであれば対処すべきである一方で、特定の理由により、Fix It サンプル アプリケーションの初期リリースでは対処しないことを決定した問題が含まれています。
セキュリティ
- 存在しない所有者に、タスクを割り当てることができないようにします。
- タスクの作成者またはタスクを割り当てられたユーザーのみがそのタスクを表示、変更できるようにします。
- サインイン ページと認証 Cookie には HTTPS を使用します。
- 認証 Cookie に時間制限を指定します。
入力の検証
一般的に、実稼働アプリでは、Fix It アプリよりも多くの入力検証が実行されます。 たとえば、アップロードに使用できる画像サイズまたは画像のファイル サイズを制限する必要があります。
管理者の機能
管理者は、既存のタスクの所有権を変更できる必要があります。 たとえば、タスクの作成者が退社した場合、管理アクセスが有効になっていないと、そのタスクを管理する権限を持つ人がいなくなってしまう可能性があります。
キュー メッセージ処理
Fix It アプリでのキュー メッセージ処理は、キュー中心の作業パターンを最小限のコード量で示すことができるよう、シンプルに設計されています。 このシンプルなコードは、実稼働のアプリケーションの場合は十分とは言えません。
- このコードでは、各キュー メッセージの処理回数が最大 1 回になることが保証されません。 キューからメッセージを取得するとタイムアウト期間が発生し、その間、メッセージは他のキュー リスナーからは見えなくなります。 メッセージが削除される前にタイムアウトが切れると、メッセージは再び見えるようになります。 したがって、worker ロール インスタンスでメッセージの処理に長い時間がかかった場合、理論的には、同じメッセージが 2 回処理され、データベース内のタスクが重複する可能性があります。 この問題の詳細については、Azure Storage キューの使用に関するセクションを参照してください。
- メッセージの取得をバッチ処理することで、キュー ポーリング ロジックのコスト効率を改善することができます。 CloudQueue.GetMessageAsync を呼び出すと、そのたびにトランザクション コストが発生します。 代わりに、CloudQueue.GetMessagesAsync (複数形の 's' が含まれている点に注意) を呼び出すと、1 回のトランザクションで複数のメッセージを取得できます。 Azure Storage キューのトランザクション コストは非常に低いので、ほとんどのシナリオでコストへの影響はそれほど大きくありません。
- キュー メッセージ処理コードのループがきつくなっていると、CPU アフィニティが発生し、マルチコア VM を効率的に利用できなくなります。 タスクの並列処理を使用して、複数の非同期タスクを並列で実行するのが、より優れた設計になります。
- キュー メッセージ処理には、初歩的な例外処理しかありません。 たとえば、このコードは有害メッセージを処理しません。 (メッセージ処理によって例外が発生した場合は、エラーをログに記録してメッセージを削除する必要があります。そうしないと、worker ロールがもう一度処理を試み、ループが無期限に続行されます)。
無制限の SQL クエリ
現在の Fix It コードでは、インデックス ページのクエリから返される行の数に制限が設けられていません。 データベースに大量のタスクが入力されると、受け取る結果リストのサイズによってはパフォーマンスの問題が発生する可能性があります。 解決策は、ページングを実装することです。 例については、ASP.NET MVC アプリケーションでの Entity Framework での並べ替え、フィルター処理、ページングに関するページを参照してください。
ビュー モデルの推奨
Fix It アプリでは、FixItTask エンティティ クラスを使用して、コントローラーとビューの間で情報をやり取りします。 ベスト プラクティスは、ビュー モデルを使用することです。 ドメイン モデル (FixItTask エンティティ クラスなど) は、データの永続化に必要なものを中心に設計されていますが、ビュー モデルはデータの表示用に設計することができます。
セキュリティで保護されたイメージ BLOB の推奨
Fix It アプリは、アップロードされた画像をパブリックとして格納します。つまり、URL にたどり着いたすべてのユーザーが画像にアクセスできるということです。 画像はパブリックに置かず、セキュリティで保護することができます。
キュー用の PowerShell 自動化スクリプトがない
サンプルの PowerShell 自動化スクリプトは、Azure App Service Web Apps 上で完全に稼働する Fix It の基本バージョンのみを対象に作成されています。 キュー処理に必要な Web アプリと Cloud Service 環境の設定とデプロイ用のスクリプトは提供していません。
ユーザー入力の HTML コードに対する特別な処理
ASP.NET は、悪意のあるユーザーがユーザー入力テキスト ボックスにスクリプトを入力してクロスサイト スクリプティング攻撃を試みるさまざまな方法を自動的に防止します。 また、タスクのタイトルとメモを表示するために使用される MVC DisplayFor
ヘルパーは、ブラウザーに送信する値を自動的に HTML エンコードします。 ただし、実稼働アプリでは、追加の対策が必要になる場合があります。 詳細については、ASP.NET での要求の検証に関するページを参照してください。
ベスト プラクティス
以下では、コード レビューと Fix It アプリのオリジナル バージョンのテストで検出された後、修正された問題を示します。 これらの問題の一部は、元のコーダーが特定のベスト プラクティスを認識していなかったために発生したものもあれば、短時間で書かれ、リリース ソフトウェアとして使用されることが想定されていなかったために発生したものもあります。 このレビューとテストから得た学びが、同じように Web アプリを開発している他のユーザーに役立つ可能性がある場合に備えて、ここに問題点を列挙しておきます。
データベース リポジトリを破棄する
FixItTaskRepository
クラスでは、Entity Framework DbContext
インスタンスを破棄する必要があります。 今回は、FixItTaskRepository
クラスで IDisposable
を実装することで行いました。
public class FixItTaskRepository : IFixItTaskRepository, IDisposable
{
private MyFixItContext db = new MyFixItContext();
// other code not shown
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Free managed resources.
if (db != null)
{
db.Dispose();
db = null;
}
}
}
}
AutoFac は FixItTaskRepository
インスタンスを自動的に破棄するため、明示的に破棄する必要はありません。
もう 1 つのオプションは、DbContext
メンバー変数を FixItTaskRepository
から削除し、代わりに各リポジトリ メソッド内の using
ステートメント内にローカル DbContext
変数を作成することです。 次に例を示します。
// Alternate way to dispose the DbContext
using (var db = new MyFixItContext())
{
fixItTask = await db.FixItTasks.FindAsync(id);
}
DI でシングルトンを登録する
必要な PhotoService
クラスと Logger
クラスのインスタンスは 1 つのみであるため、依存性の注入のためにこれらのクラスを DependenciesConfig.cs にシングル インスタンスとして登録する必要があります。
builder.RegisterType<Logger>().As<ILogger>().SingleInstance();
builder.RegisterType<FixItTaskRepository>().As<IFixItTaskRepository>();
builder.RegisterType<PhotoService>().As<IPhotoService>().SingleInstance();
セキュリティ: ユーザーにエラーの詳細を表示しない
オリジナルの Fix It アプリには一般的なエラー ページがなく、すべての例外を UI にそのまま表示していたため、データベース接続エラーのような一部の例外では、完全なスタック トレースがブラウザーに表示される可能性がありました。 詳細なエラー情報は、時に悪意のあるユーザーによる攻撃を助長してしまう可能性があります。 解決策は、例外の詳細はログに記録し、ユーザーにはエラーの詳細を含まないエラー ページを表示することです。 Fix It アプリでは既にログを記録していたため、エラー ページを表示するために、Web.config ファイルに <customErrors mode=On>
を追加しました。
<system.web>
<customErrors mode="On"/>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
既定では、これによって Views\Shared\Error.cshtml にエラーが表示されるようになっています。 Error.cshtml をカスタマイズしたり、独自のエラー ページ ビューを作成して defaultRedirect
属性を追加したりすることもできます。 また、特定のエラーに対して異なるエラー ページを指定することもできます。
セキュリティ: タスクの編集を作成者にのみ許可する
[ダッシュボード インデックス] ページにはログオンしているユーザー自身によって作成されたタスクのみが表示されますが、悪意のあるユーザーが他のユーザーのタスク ID を使用して URL を作成する可能性があります。 今回は、そのような場合に 404 を返すコードを DashboardController.cs に追加しました。
public async Task<ActionResult> Edit(int id)
{
FixItTask fixittask = await fixItRepository.FindTaskByIdAsync(id);
if (fixittask == null)
{
return HttpNotFound();
}
// Verify logged in user owns this FixIt task.
if (User.Identity.Name != fixittask.Owner)
{
return HttpNotFound();
}
return View(fixittask);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(int id, [Bind(Include = "CreatedBy,Owner,Title,Notes,PhotoUrl,IsDone")]FormCollection form)
{
FixItTask fixittask = await fixItRepository.FindTaskByIdAsync(id);
// Verify logged in user owns this FixIt task.
if (User.Identity.Name != fixittask.Owner)
{
return HttpNotFound();
}
if (TryUpdateModel(fixittask, form))
{
await fixItRepository.UpdateAsync(fixittask);
return RedirectToAction("Index");
}
return View(fixittask);
}
例外を飲み込まないようにする
オリジナルの Fix It アプリは、SQL クエリの結果として発生した例外をログに記録した後、null を返していました。
catch (Exception e)
{
log.Error(e, "Error in FixItTaskRepository.FindTasksByOwnerAsync(userName={0})", userName);
return null;
}
このため、ユーザーにはあたかもクエリが成功したにも関わらず、行が返されなかったかのように表示されていました。 解決策は、例外をキャッチしてログを記録した後、再スローすることです。
catch (Exception e)
{
log.Error(e, "Error in FixItTaskRepository.FindTasksByCreatorAsync(creater={0})", creator);
throw;
}
worker ロールのすべての例外をキャッチする
worker ロールでハンドルされない例外が発生すると VM がリサイクルされるため、try-catch ブロックで実行するすべての処理をラップし、すべての例外を処理する必要があります。
エンティティ クラスの文字列プロパティの長さを指定する
コードの見た目をシンプルにするため、Fix It アプリのオリジナル バージョンでは FixItTask エンティティのフィールドの長さを指定しておらず、その結果、これらはデータベースで varchar(max) として定義されていました。 これにより、UI には任意の量の入力を指定できるようになっていました。 長さを指定すると、Web ページ上のユーザー入力とデータベース内の列サイズの両方に適用される制限が設定されます。
public class FixItTask
{
public int FixItTaskId { get; set; }
[StringLength(80)]
public string CreatedBy { get; set; }
[Required]
[StringLength(80)]
public string Owner { get; set; }
[Required]
[StringLength(80)]
public string Title { get; set; }
[StringLength(1000)]
public string Notes { get; set; }
[StringLength(200)]
public string PhotoUrl { get; set; }
public bool IsDone { get; set; }
}
変更される予定がないプライベート メンバーは読み取り専用としてマークする
たとえば、DashboardController
クラスでは FixItTaskRepository
のインスタンスが作成されますが、これは変更される予定はないので、readonly と定義しました。
public class DashboardController : Controller
{
private readonly IFixItTaskRepository fixItRepository = null;
list.Count() > 0 の代わりに list.Any() を使用する
リストに含まれる項目のうち、指定した条件に合うものが 1 つ以上あるかどうかだけを判断したい場合は、Any メソッドを使用します。これは、このメソッドでは条件に合う項目が見つかるとすぐに結果を返す一方で、Count
メソッドでは常にすべての項目を繰り返し処理する必要があるためです。 ダッシュボード Index.cshtml ファイルには、元々以下のコードが含まれていました。
@if (Model.Count() == 0) {
<br />
<div>You don't have anything currently assigned to you!!!</div>
}
これを次のように変更しました。
@if (!Model.Any()) {
<br />
<div>You don't have anything currently assigned to you!!!</div>
}
MVC ヘルパーを使用して MVC ビューで URL を生成する
ホーム ページにある [Create a Fix It (Fix It を作成する)] ボタンにおいて、Fit It アプリではアンカー要素がハード コーディングされています。
<a href="/Tasks/Create" class="btn btn-primary btn-large">Create a New FixIt »</a>
このような表示リンクやアクション リンクの場合は、以下の例のように Url.Action HTML ヘルパーを使用することをお勧めします。
@Url.Action("Create","Tasks")
worker ロールでは Thread.Sleep の代わりに Task.Delay を使用する
プロジェクトの新規作成テンプレートでは worker ロールのサンプル コードに Thread.Sleep
を使用していますが、スレッドをスリープさせると、スレッド プールによって不要なスレッドが追加で生成される可能性があります。 これを回避するには、代わりに Task.Delay を使用します。
while (true)
{
try
{
await queueManager.ProcessMessagesAsync();
}
catch (Exception ex)
{
logger.Error(ex, "Exception in worker role Run loop.");
}
await Task.Delay(1000);
}
Async Void をの使用を避ける
非同期メソッドから返す値がない場合は、void
ではなく Task
型を返すようにします。
以下の例は FixItQueueManager
クラスのものです。
// Correct
public async Task SendMessageAsync(FixItTask fixIt) { ... }
// Incorrect
public async void SendMessageAsync(FixItTask fixIt) { ... }
async void
は、最上位レベルのイベント ハンドラーにのみ使用するようにしてください。 メソッドを async void
として定義すると、呼び出し側はメソッドを待機 (await) することも、メソッドがスローする例外をキャッチすることもできなくなります。 詳細については、「非同期プログラミングのベスト プラクティス」を参照してください。
キャンセル トークンを使用して worker ロールのループから抜け出す
通常、worker ロールの Run メソッドには無限ループが含まれます。 worker ロールが停止すると、RoleEntryPoint.OnStop メソッドが呼び出されます。 このメソッドを使用して、Run メソッド内で実行されている作業を取り消し、正常に終了するようにしてください。 そうしないと、操作の途中でプロセスが終了する可能性があります。
自動 MIME スニッフィング手順をオプトアウトする
場合によっては、Internet Explorer によって、Web サーバーで指定された種類とは異なる種類の MIME が報告されることがあります。 たとえば、Internet Explorer において、HTTP 応答ヘッダー Content-Type: text/plain で配信されたファイルに HTML コンテンツが検出された場合、Internet Explorer ではそのコンテンツを HTML としてレンダリングする必要があると判断されます。 残念ながら、この "MIME スニッフィング" は、信頼できないコンテンツをホストするサーバーのセキュリティ問題にもつながる可能性があります。 この問題に対処するため、Internet Explorer 8 では MIME タイプの判定コードに多くの変更が加えられており、アプリケーション開発者が MIME スニッフィングをオプトアウトできるようになっています。 次のコードが Web.config ファイルに追加されています。
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Content-Type-Options" value="nosniff"/>
</customHeaders>
</httpProtocol>
<modules>
<remove name="FormsAuthenticationModule" />
</modules>
</system.webServer>
バンドルと縮小を有効にする
Visual Studio で新しい Web プロジェクトを作成するとき、JavaScript ファイルのバンドルと縮小は既定では有効になっていません。 そこで、BundleConfig.cs に以下のようなコード行を追加しました。
// For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for brevity/
BundleTable.EnableOptimizations = true;
}
認証 Cookie の有効期限のタイムアウトを設定する
既定では、認証 Cookie の有効期限は 2 週間です。 より短い時間の方が、より安全です。 この設定は、StartupAuth.cs で変更できます。
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
ExpireTimeSpan = System.TimeSpan.FromMinutes(20)
});
ローカル コンピューターの Visual Studio からアプリを実行する方法
Fix It アプリを実行するには、次の 2 つの方法があります。
- 新しいタスクを SQL データベースに直接書き込むベース アプリケーションを実行する。
- キューとバックエンド サービスを使用してアプリケーションを実行し、タスクを作成する。 キュー パターンについては、「キューを中心とした作業のパターン」のチャプターで説明されています。
ベース アプリケーションを実行する
- Visual Studio 2017 のインストール。
- Azure SDK for .NET for Visual Studio をインストールします。
- MSDN コード ギャラリーから .zip ファイルをダウンロードします。
- エクスプローラーで .zip ファイルを右クリックしてから [プロパティ] をクリックし、プロパティ ウィンドウで [ブロックの解除] をクリックします。
- ファイルを解凍します。
- .sln ファイルをダブルクリックして Visual Studio を起動します。
- [ツール] メニューで [NuGet パッケージ マネージャー]、[パッケージ マネージャー コンソール] の順にクリックします。
- パッケージ マネージャー コンソール (PMC) で、[復元] をクリックします。
- Visual Studio を終了します。
- [Azure ストレージ エミュレーター] を起動します。
- Visual Studio を再起動し、前の手順で閉じたソリューション ファイルを開きます。
- FixIt プロジェクトがスタートアップ プロジェクトとして設定されていることを確認したら、Ctrl キーを押しながら F5 キーを押してプロジェクトを実行します。
キュー処理を使用してアプリケーションを実行する
「ベース アプリケーションを実行する」の手順を実行したら、ブラウザーを閉じて Visual Studio を閉じます。
管理者特権で Visual Studio を起動します。 (ここでは Azure コンピューティング エミュレーターを使用しますが、これには管理者特権が必要です)。
MyFixIt プロジェクト (Web プロジェクト) のアプリケーション Web.config ファイルで、
appSettings/UseQueues
の値を "true" に変更します。<appSettings> <!-- Other settings not shown --> <add key="UseQueues" value="true"/> </appSettings>
Azure ストレージ エミュレーターがまだ実行されていない場合は、もう一度起動します。
FixIt Web プロジェクトと MyFixItCloudService プロジェクトを同時に実行します。
Visual Studio を使用:
- F5 キーを押して FixIt プロジェクトを実行します。
- ソリューション エクスプローラーで MyFixItCloudService プロジェクトを右クリックし、[デバッグ]>[新しいインスタンスを開始] の順にクリックします。
Visual Studio 2013 Express for Web を使用する場合:
ソリューション エクスプローラーで FixIt ソリューションを右クリックし、[プロパティ] をクリックします。
[マルチ スタートアップ プロジェクト] を選択します。
MyFixIt と MyFixItCloudService の [アクション] ドロップダウン リストで [開始] を選択します。
OK をクリックします。
F5 キーを押して両方のプロジェクトを実行します。
MyFixItCloudService プロジェクトを実行すると、Visual Studio によって Azure コンピューティング エミュレーターが起動されます。 ファイアウォールの構成によっては、ファイアウォール経由でエミュレーターを許可する必要があるかもしれません。
Windows PowerShell スクリプトを使用してベース アプリを Azure App Service Web Apps にデプロイする方法
「Automate Everything (すべてを自動化する)」のパターンを示すため、Fix It アプリには Azure で環境を設定し、その新しい環境にプロジェクトをデプロイするスクリプトが用意されています。 次の手順では、このようなスクリプトの使用方法について説明します。
キューを使用せずに Azure で実行する場合で、ローカルでキューを使用して実行するように変更した場合は、次の手順に進む前に UseQueues appSetting の値を false に設定してください。
これらの手順は、Fix It ソリューションをすでにダウンロードしてローカルで実行していること、ならびに Azure アカウントを所有しているか、管理権限のある Azure サブスクリプションを所有していることを前提としています。
Azure PowerShell コンソールをインストールします。 手順については、「 Azure PowerShell のインストールおよび構成方法」を参照してください。
このカスタマイズされたコンソールは、ご利用の Azure サブスクリプションで動作するように構成されています。 Azure モジュールは Program Files ディレクトリにインストールされており、Azure PowerShell コンソールを使用するたびに自動的にインポートされます。
Windows PowerShell ISE などの別のホスト プログラムで作業したい場合は、Import-Module コマンドレットを使用して Azure モジュールをインポートするか、Azure モジュール内のコマンドを使用してモジュールの自動インポートをトリガーしてください。
Azure PowerShell を [管理者として実行] オプションで起動します。
Set-ExecutionPolicy コマンドレットを実行して、Azure PowerShell 実行ポリシーを
RemoteSigned
に設定します。 ポリシーの変更を完了するには、「Y」 (Yes の意味) と入力します。PS C:\> Set-ExecutionPolicy RemoteSigned
この設定を使用すると、デジタル署名されていないローカル スクリプトを実行できるようになります。 (実行ポリシーを
Unrestricted
に設定することもできます。これにより、後に発生するブロック解除手順が不要になりますが、これはセキュリティ上の理由から推奨されません)。Add-AzureAccount
コマンドレットを実行して、お持ちのアカウントの資格情報で PowerShell を設定します。PS C:\> Add-AzureAccount
これらの資格情報は一定期間後に期限切れになるため、その際は
Add-AzureAccount
コマンドレットを再実行する必要があります。 この電子書籍の執筆時点では、資格情報の有効期限は 12 時間です。複数のサブスクリプションがある場合は、Select-AzureSubscription コマンドレットを使用して、テスト環境を作成するサブスクリプションを指定します。
Get-AzurePublishSettingsFile
とImport-AzurePublishSettingsFile
コマンドレットを使用して、同じ Azure サブスクリプションの管理証明書をインポートします。 最初のコマンドレットは証明書ファイルをダウンロードし、2 番目のコマンドレットではそれをインポートするためにファイルの場所を指定します。 >[!重要]ダウンロードしたファイルには Azure サービスの管理に使用できる証明書が含まれているため、安全な場所に保管するか、使用済みになった段階で削除するようにしてください。
PS C:\Users\username\Documents\Visual Studio 2013\Projects\MyFixIt\Automation> Get-AzurePublishSettingsFile PS C:\Users\username\Documents\Visual Studio 2013\Projects\MyFixIt\Automation> Import-AzurePublishSettingsFile "C:\Users \username\Downloads\Azure MSDN - Visual Studio Ultimate-12-14-2013-credentials.publishsettings"
この証明書は、SQL Database サーバーにファイアウォール規則を設定するために、開発用コンピューターの IP アドレスを検出する REST API 呼び出しに使用されます。
Set-Location コマンドレット (エイリアスは
cd
、chdir
、sl
です) を実行して、スクリプトが格納されているディレクトリに移動します。 (これらは、Fix It ソリューション フォルダー内の Automation フォルダーにあります。)ディレクトリ名にスペースが含まれている場合は、パスを引用符で囲みます。 たとえば、c:\Sample Apps\FixIt\Automation
ディレクトリに移動するには、次のコマンドを入力します。PS C:\> cd "c:\Sample Apps\MyFixIt\Automation"
Windows PowerShell でこれらのスクリプトを実行できるようにするには、Unblock-File コマンドレットを使用します。 (これらのスクリプトはインターネットからダウンロードされたものであるため、ブロックされています)。
警告
セキュリティ - スクリプトまたは実行可能ファイルで
Unblock-File
を実行する前に、メモ帳でファイルを開き、コマンドを調べて、悪意のあるコードが含まれていないことを確認してください。たとえば、次のコマンドは、現在のディレクトリ内のすべてのスクリプトで
Unblock-File
コマンドレットを実行します。PS C:\Sample Apps\FixIt\Automation> Unblock-File -Path .\*.ps1
ベース (キュー処理なし) Fix It アプリ用の Web アプリを作成するには、環境作成スクリプトを実行します。
必須の
Name
パラメーターはデータベースの名前を指定するもので、スクリプトによって作成されるストレージ アカウントにも使用されます。 名前は、azurewebsites.net ドメイン内でグローバルに一意である必要があります。 Fixit や Test など (または例で使用している fixitdemo など) の一意でない名前を指定した場合、New-AzureWebsite
コマンドレットは競合を報告する内部エラーで失敗します。 このスクリプトでは、Web アプリ、ストレージ アカウント、データベースの名前要件に準拠するために、名前が小文字に変換されます。必須の
SqlDatabasePassword
パラメーターは、SQL Database 用に作成される管理者アカウントのパスワードを指定します。 このパスワードには、XML の特殊文字 (& <> ;) を含めないでください。 これは、スクリプトの記述方法の制限であり、Azure の制限ではありません。たとえば、"fixitdemo" という名前の Web アプリを作成し、SQL Server の管理者パスワードを "Passw0rd1" とする場合は、次のコマンドを入力します。
PS C:\Sample Apps\FixIt\Automation> .\New-AzureWebsiteEnv.ps1 -Name fixitdemo <required params here>
名前は azurewebsites.net ドメイン内で一意である必要があり、パスワードは SQL Database で要求されるパスワードの複雑さを満たしていなければなりません。 (例にある Passw0rd1 は要件を満たしています)。
コマンドは "." で始まる点に注意してください。 悪意のあるスクリプト実行を防ぐために、Windows PowerShell では、スクリプトの実行時にスクリプト ファイルへの完全修飾パスを指定する必要があります。 ドットを使用して現在のディレクトリ (".") を示すか、次のように完全修飾パスを指定できます。
PS C:\Temp\FixIt\Automation> C:\Temp\FixIt\Automation\New-AzureWebsiteEnv.ps1 -Name fixitdemo -SqlDatabasePassword Pas$w0rd
スクリプトの詳細については、
Get-Help
コマンドレットを使用してください。PS C:\Sample Apps\FixIt\Automation> Get-Help -Full .\New-AzureWebsiteEnv.ps1
Get-Help コマンドレットの
Detailed
、Full
、Parameters
、Examples
パラメーターを使用して、返されるヘルプをフィルター処理できます。スクリプトが失敗するか、"New-AzureWebsite : Call Set-AzureSubscription and Select-AzureSubscription first" などのエラーが発生した場合、Azure PowerShell の構成が完了していない可能性があります。
スクリプトが完了したら、「Automate Everything (すべてを自動化する)」のチャプターにあるように、Azure 管理ポータルを使用して作成されたリソースを確認できます。
FixIt プロジェクトを新しい Azure 環境にデプロイするには、AzureWebsite.ps1 スクリプトを使用します。 次に例を示します。
PS C:\Sample Apps\FixIt\Automation> .\Publish-AzureWebsite.ps1 ..\MyFixIt\MyFixIt.csproj -Launch
デプロイが完了すると、Fix It が実行されている Azure がブラウザーで開きます。
Windows PowerShell スクリプトのトラブルシューティング
これらのスクリプトを実行する際に発生する最も一般的なエラーは、アクセス許可に関連しています。 Add-AzureAccount
と Import-AzurePublishSettingsFile
が成功していること、およびそれらを同じ Azure サブスクリプションに使用していることを確認するようにしてください。 Add-AzureAccount
が成功した場合でも、再度実行する必要があるかもしれません。 Add-AzureAccount
によって追加された権限は 12 時間で失効します。
オブジェクト参照がオブジェクト インスタンスに設定されていません。
スクリプトから "オブジェクト参照がオブジェクトのインスタンスに設定されていません" といったエラーが返される場合は、Windows PowerShell で処理するオブジェクトが見つからないことを意味します (これは null 参照の例外です)。Add-AzureAccount
コマンドレットを実行して、スクリプトをもう一度試してください。
New-AzureSqlDatabaseServer : Object reference not set to an instance of an object.
At C:\ps-test\azure-powershell-samples-master\WebSite\create-azure-sql.ps1:80 char:19
+ $databaseServer = New-AzureSqlDatabaseServer -AdministratorLogin $UserName -Admi ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [New-AzureSqlDatabaseServer], NullReferenceException
+ FullyQualifiedErrorId :
Microsoft.WindowsAzure.Commands.SqlDatabase.Server.Cmdlet.NewAzureSqlDatabaseServer
InternalError: サーバーで内部エラーが発生しました。
New-AzureWebsite
コマンドレットは、azurewebsites.net ドメイン内で名前が一意でない場合に内部エラーを返します。 このエラーを解決するには、New-AzureWebsiteEnv.ps1 の Name パラメーターにある値に別の名前を使用します。
New-AzureWebsite : InternalError: The server encountered an internal error.
Please retry the request.
At line:1 char:1
+ New-AzureWebsite -Name fixitdemo
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo
: CloseError: (:) [New-AzureWebsite], Exception
+ FullyQualifiedErrorId :
Microsoft.WindowsAzure.Commands.Websites.NewAzureWebsiteCommand
スクリプトの再起動
New-AzureWebsiteEnv.ps1 スクリプトが「スクリプトが完了しました」というメッセージを出力する前に失敗したため、スクリプトを再起動する必要がある場合は、そのスクリプトが停止するまでに作成されたリソースを削除することをおすすめします。 たとえば、スクリプトによって ContosoFixItDemo Web アプリが既に作成されている状態で、同じ名前でスクリプトを再度実行した場合、その名前が使用中であるため、スクリプトは失敗します。
スクリプトが停止する前に作成したリソースを確認するには、次のコマンドレットを使用します。
Get-AzureWebsite
Get-AzureSqlDatabaseServer
Get-AzureSqlDatabase
: このコマンドレットを実行するには、データベース サーバー名をGet-AzureSqlDatabase
:Get-AzureSqlDatabaseServer | Get-AzureSqlDatabase.
に渡します。
これらのリソースを削除するには、次のコマンドを使用します。 データベース サーバーを削除すると、サーバーに関連付けられているデータベースが自動的に削除されることに注意してください。
Get-AzureWebsite -Name <WebsiteName> | Remove-AzureWebsite
Get-AzureSqlDatabase -Name <DatabaseName> -ServerName <DatabaseServerName> | Remove-SqlAzureDatabase
Get-AzureSqlDatabaseServer | Remove-AzureSqlDatabaseServer
キュー処理を使用してアプリを Azure App Service Web Apps と Azure Cloud Service にデプロイする方法
キューを有効にするには、MyFixIt\Web.config ファイルで次の変更を行います。 appSettings
で、UseQueues
の値を "true" に変更します。
<appSettings>
<!-- Other settings not shown -->
<add key="UseQueues" value="true"/>
</appSettings>
次に、前述のように、MVC アプリケーションを Azure App Service の Web アプリにデプロイします。
次に、新しい Azure クラウド サービスを作成します。 Fix It アプリに含まれているスクリプトではクラウド サービスの作成やデプロイは行えないため、これには Azure portal を使用する必要があります。 ポータルで、[新規] -- [コンピューティング] - [クラウド サービス] -- [クイック作成] の順にクリックし、URL とデータ センターの場所を入力します。 Web アプリのデプロイ先と同じデータ センターを使用します。
クラウド サービスをデプロイする前に、構成ファイルの一部を更新する必要があります。
MyFixIt.WorkerRole\app.config の connectionStrings
で、appdb
接続文字列の値を SQL Database の実際の接続文字列に置き換えます。 接続文字列はポータルで取得できます。 ポータルで、[SQL Database] - [appdb] - [ADO.Net、ODBC、PHP、および JDBC の SQL データベース接続文字列を表示する] の順に選択します。 ADO.NET 接続文字列をコピーし、app.config ファイルに値を貼り付けます。 "{your_password_here}" を実際のデータベース パスワードに置き換えます。 (スクリプトを使用して MVC アプリをデプロイしてあれば、データベースのパスワードは SqlDatabasePassword
スクリプト パラメーターで指定してあります)。
結果は次のようになります。
<add name="appdb" connectionString="Server=tcp:####.database.windows.net,1433;Database=appdb;User ID=####;Password=####;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;" providerName="System.Data.SqlClient" />
同じ MyFixIt.WorkerRole\app.config ファイルの appSettings
の下で、Azure ストレージ アカウントの 2 つのプレースホルダー値を置き換えます。
<appSettings>
<add key="StorageAccountName" value="{StorageAccountName}" />
<add key="StorageAccountAccessKey" value="{StorageAccountAccessKey}" />
</appSettings>
アクセス キーはポータルで取得できます。 詳しくは、ストレージ アカウント を管理する方法に関するページを参照してください。
MyFixItCloudService\ServiceConfiguration.Cloud.cscfg で、Azure ストレージ アカウントの同じ 2 つのプレースホルダー値を置き換えます。
<ConfigurationSettings>
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"
value="DefaultEndpointsProtocol=https;AccountName={StorageAccountName};AccountKey={StorageAccountAccessKey}" />
</ConfigurationSettings>
これで、クラウド サービスをデプロイする準備ができました。 ソリューション エクスプローラーで MyFixItCloudService プロジェクトを右クリックし、[発行] を選択します。 詳細については、こちらのチュートリアルのパート 2 である「アプリケーションを Azure にデプロイする」を参照してください。