情報応用演習Ⅰ(2024)

【T10b】簡易ブログソフトウェアの作成 Part.Ⅳ ~ ファイルのアップロード/ダウンロード(7/7)

プロジェクトタイプ(注意: 本文参照)
プロジェクト名T10b
ソリューション名PIT10
注意
  • 本ページの作業内容は 前のページまでの続き になっていることに注意せよ.
    • 先に前のページまでをすべて読み,指示されている作業を済ませてから本ページを読むこと.
    • プロジェクトの作成作業については準備作業を参照せよ.

10b-7. 添付ファイルを表示に用いる例

最後に添付ファイルを表示に用いる例を紹介しておこう.ここでは添付ファイルのうち 最後にアップロードした画像ファイル を 特別扱いして,その記事の「代表画像」として記事の個別表示画面(Details)に表示するようにしてみよう. ArticlesコントローラーのDetailsアクションとビューに,それぞれ__に示す内容を追記しよう.

Articlesコントローラーの追記内容(Detailsアクション(GETのみ))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// GET: Articles/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null || _context.Articles == null)
    {
        return NotFound();
    }

    var article = await _context.Articles
        .Include(a => a.BlogUser)
        .Include(a => a.Attachments)
        .FirstOrDefaultAsync(m => m.ArticleId == id);
    if (article == null)
    {
        return NotFound();
    }

    BlogUser? currentUser = await _userManager.GetUserAsync(User);
    if (!await IsReadableAsync(currentUser, article)) return Forbid();

    ViewBag.IsModifiable = currentUser != null && await IsModifiableAsync(currentUser, article);

    ViewBag.RepresentativeImage = (from a in article.Attachments              // その記事の添付ファイルを
                                    orderby a.Uploaded descending              // アップロード日時の降順で並べて,
                                    where a.ContentType.StartsWith("image/")   // 画像ファイルである(=コンテントタイプが"image/"で始まる)
                                    select a).FirstOrDefault();                // 最初の添付ファイルを取得し,ViewDataに格納する.

    return View(article);
}
Views/Articles/Details.cshtmlの内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@model T10b.Models.Article
 
@{
    if (Model is null) throw new ArgumentNullException(nameof(Model)); // ad-hoc! 非null保証のための回避策
 
    ViewData["Title"] = Model.Title; 
 
    var isModifiable = (bool)ViewBag.IsModifiable; 
}

@* 代表画像がある場合にはそれを表示する. *@
@if (ViewBag.RepresentativeImage != null) 
{
    var attachment = (Attachment)ViewBag.RepresentativeImage;

    <img src="@Url.Action("GetAttachment", new { id = attachment.AttachmentId })" class="rep" />    
} 

<p> @(Model.BlogUser?.Nickname ?? Model.BlogUser?.UserName) による投稿</p>
 
<dl>
  <dt>@Html.DisplayNameFor(m => m.Created)</dt>
  <dd>@Html.DisplayFor(m => m.Created)</dd>
 
  <dt>@Html.DisplayNameFor(m => m.Modified)</dt>
  <dd>@Html.DisplayFor(m => m.Modified)</dd>
</dl>
 
<pre class="article">@Model.Body</pre>

@if (Model.Attachments != null && Model.Attachments.Count != 0)
{
    <h5>添付ファイル</h5>
    <ul>
      @foreach(var f in Model.Attachments)
        {
            <li>
              <a asp-action="GetAttachment" asp-route-id="@f.AttachmentId">@f.Filename</a>
            </li>
        }
    </ul>
}

<a asp-action="Index">一覧に戻る</a>
 
@if(isModifiable)
{
    <span>| </span><a asp-action="Edit" asp-route-id="@Model.ArticleId">編集</a>
    <span>| </span><a asp-action="Delete" asp-route-id="@Model.ArticleId">削除</a>
}

_Detailsアクションでは,LINQを用いて 添付ファイルの中から最新の画像ファイルを探してViewDataに格納している(23~26行目).

_のビューでは,ViewBagを調べて代表画像となる添付ファイルオブジェクトが格納されていれば それを img 要素で表示している(16行目).ここで img 要素の src 属性のURLを生成するために,@Url.Action()というURLヘルパーを使用している. これはアクション名やコントローラー名,ルーティングパラメーターを指定することで,このアクション/コントローラーへの URLをベタテキストとして生成してくれるものである.

ここまで書けたら実行してみよう.プロジェクトを起動して「ログイン」のリンクをクリックし適当な通常ユーザー (admin以外のユーザー)としてログインしよう.ログイン中のユーザーが編集可能な記事に 画像ファイルを添付してみよう(__).その記事の個別表示画面(Details)を表示すると タイトルの後に添付した画像ファイルが表示されていることが分かるはずである(__).

実行結果

ここまでを確認できたら今回のチュートリアルは完了である. なお今回は課題が出題されている.忘れずに取り組むこと

Last updated on 2024-06-18
Published on 2024-06-18

Powered by Hugo. Theme by TechDoc. Designed by Thingsym.