このテキストではデプロイしたWebアプリのコードを書き加えて、メッセージの作成、更新、削除が行えるようにします。
コードを書く前にデータベースの準備をします。 データのやりとりができるようにデータベースをAzure上に構築します。
-
SQL デプロイ オプションの選択 ページを参照します。
-
[SQL データベースの作成] フォームの [基本] タブにある [プロジェクトの詳細] で、目的の Azure [サブスクリプション] を選択します。
-
[リソース グループ] で、 [タブ] を開き、ハンズオンで使用しているリソースグループを、 選択します。
-
[データベース名] に任意のデータベース名を入力します。
-
[サーバー] で、 [新規作成] を選択し、 [新しいサーバー] フォームに次の値を入力します。
- [サーバー名] : 「hol-line-bot-db-」と入力し、一意にするためにいくつかの文字を追加します。 サーバー名は、サブスクリプション内で一意ではなく、Azure のすべてのサーバーに対してグローバルに一意である必要があるため、正確なサーバー名をここに示すことはできません。 hoi-line-bot-db-12345 のように入力してから、利用可能かどうかをポータルで確認できます。
- サーバー管理者ログイン:「azureuser」と入力します。
- パスワード:要件を満たすパスワード(例:Passw0rd!)を入力し、 [パスワードの確認入力] フィールドにもう一度入力します。
- [場所] :ドロップダウン リストから東日本を選択します。
- [OK] を選択します。
-
[SQL エラスティック プールを使用しますか?] を [いいえ] に設定したままにします。
-
[コンピューティングとストレージ] で、 [データベースの構成] を選択します。
-
ハンズオンでは[サーバーレス] を選択します。
-
[ネットワーク] タブの [接続方法] で、 [パブリック エンドポイント] を選択します。
-
[ファイアウォール規則] で、 [現在のクライアント IP アドレスを追加する] を [はい] に設定します。 [Azure サービスおよびリソースにこのサーバー グループへのアクセスを許可する] を [はい] に設定します。
-
[確認と作成] ページで、確認後、 [作成] を選択します。
- デプロイが完了したら、「リソースに移動]を選択します。
- 画面右の[データベース接続文字列の表示]を選択します。
- 画面に表示された接続文字列をメモ帳などに控えます。
- 接続文字列の途中にある[{your_password}]をサーバー作成時に設定したパスワードに書き換えます。(例:Pasword='Passw0rd!')
Webフォルダ直下にあるappsettings.jsonの[WebContext]の値を先ほど控えた接続文字列に置き換えます。
"ConnectionStrings": {
"WebContext": "{Azure上のDBの接続文字列}"
}
次のセクションではコードでマイグレーションの準備を行います。
Webフォルダ直下に[Data]フォルダを作成し、[WebContext.cs]を[Data]フォルダに追加します。
[WebContext.cs]に以下のコードを追加します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using ApplicationCore.Entities;
namespace Web.Data
{
public class WebContext : DbContext
{
public WebContext (DbContextOptions<WebContext> options)
: base(options)
{
}
public DbSet<ApplicationCore.Entities.Message> Message { get; set; }
}
}
Webアプリとデータベースが接続できるように、 [Startup.cs]を更新します。
usingに Web.Data
を追加します。
using Web.Data;
ConfigureServices内に下記の通りコードを追加します。
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
// ↓を追加する
services.AddDbContext<WebContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("WebContext")));
}
マイグレーションはEntity Framework CoreのCLIツールを使用します。このツールでデータベースの移行作業をを行うことができます。次のコマンドでツールのインストールします。
dotnet tool install --global dotnet-ef
次のコマンドを実行して EF Core CLI ツールが正しくインストールされていることを確認します。
dotnet ef
正常にインストールされていたら、インストール完了です。
次のコマンドを実行してマイグレーションを行います。
cd ./Web
dotnet build
dotnet ef migrations add InitialCreate
dotnet ef database update
成功するとAzure上で正常にDBが作成されていることが確認できます。
メッセージの作成、更新、削除を行えるようにコードを追加します。
作成ページを追加します。
@page
@model Web.Pages.hands_on.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Message</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Message.Text" class="control-label"></label>
<input asp-for="Message.Text" class="form-control" />
<span asp-validation-for="Message.Text" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using ApplicationCore.Entities;
using Web.Data;
namespace Web.Pages.hands_on
{
public class CreateModel : PageModel
{
private readonly Web.Data.WebContext _context;
public CreateModel(Web.Data.WebContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Message Message { get; set; }
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Message.Add(Message);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
- [Index.cshtml.cs]に表示処理を追加します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using ApplicationCore.Entities;
using Web.Data;
namespace Web.Pages.hands_on
{
public class IndexModel : PageModel
{
private readonly Web.Data.WebContext _context;
public IndexModel(Web.Data.WebContext context)
{
_context = context;
}
public IList<Message> Message { get;set; }
public async Task OnGetAsync()
{
Message = await _context.Message.ToListAsync();
}
}
}
- [Index.cshtml]を編集してメッセージが表示できるようにします。
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Message[0].Text)
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Message) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Text)
</td>
</tr>
}
</tbody>
</table>
削除ページを追加します。
@page
@model Web.Pages.hands_on.DeleteModel
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Message</h4>
<hr />
<dl class="row">
<dt class="col-sm-2">
@Html.DisplayNameFor(model => model.Message.Text)
</dt>
<dd class="col-sm-10">
@Html.DisplayFor(model => model.Message.Text)
</dd>
</dl>
<form method="post">
<input type="hidden" asp-for="Message.Id" />
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-page="./Index">Back to List</a>
</form>
</div>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using ApplicationCore.Entities;
using Web.Data;
namespace Web.Pages.hands_on
{
public class DeleteModel : PageModel
{
private readonly Web.Data.WebContext _context;
public DeleteModel(Web.Data.WebContext context)
{
_context = context;
}
[BindProperty]
public Message Message { get; set; }
public async Task<IActionResult> OnGetAsync(Guid? id)
{
if (id == null)
{
return NotFound();
}
Message = await _context.Message.FirstOrDefaultAsync(m => m.Id == id);
if (Message == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(Guid? id)
{
if (id == null)
{
return NotFound();
}
Message = await _context.Message.FindAsync(id);
if (Message != null)
{
_context.Message.Remove(Message);
await _context.SaveChangesAsync();
}
return RedirectToPage("./Index");
}
}
}
- Index ページに削除ボタンを追加します。
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Message[0].Text)
</th>
<!-- thを追加 -->
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Message) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Text)
</td>
<!-- ボタンを追加 -->
<td>
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
編集ページを追加します。
@page
@model Web.Pages.hands_on.EditModel
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Message</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Message.Id" />
<div class="form-group">
<label asp-for="Message.Text" class="control-label"></label>
<input asp-for="Message.Text" class="form-control" />
<span asp-validation-for="Message.Text" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="./Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using ApplicationCore.Entities;
using Web.Data;
namespace Web.Pages.hands_on
{
public class EditModel : PageModel
{
private readonly Web.Data.WebContext _context;
public EditModel(Web.Data.WebContext context)
{
_context = context;
}
[BindProperty]
public Message Message { get; set; }
public async Task<IActionResult> OnGetAsync(Guid? id)
{
if (id == null)
{
return NotFound();
}
Message = await _context.Message.FirstOrDefaultAsync(m => m.Id == id);
if (Message == null)
{
return NotFound();
}
return Page();
}
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Message).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MessageExists(Message.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
private bool MessageExists(Guid id)
{
return _context.Message.Any(e => e.Id == id);
}
}
}
- Index ページに編集ボタンを追加します。
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
Web AppsからDBに接続するために、作成したWeb Appsリソースの[アプリケーション設定]を行います。
- Azure Portalを開き、画面上部の検索に[azure-handson-app]と入力し、表示された[azure-handson-app]を選択します。
- ページ右側の[設定]>[構成]を選択します。
- ページ下部の[新しい接続文字列]を選択します。
- ページ上部の[保存]を選択します。
- [続行]を選択します。
- VS Codeの[表示]>[コマンドパレット]を開きます。
- [deploy]と入力し、[Azure App Service: Deploy to Web App]を選択します。
- [Browse]を選択し、[Web]フォルダを選択します。
- ハンズオンのサブスクリプションを選択します。
- [azure-handson-app]を選択します。
- 警告が表示されたら、[Deploy]を選択します。
- 「Browse Website」を選択し、アプリが表示されたらデプロイ完了です。
デプロイ後、表示されたサイトからメッセージの作成、編集、削除ができることを確認します。
確認できたら、次のステップ「Functionsの更新」へ進みます。