web-dev-qa-db-ja.com

ASP.NET Coreでフォームを送信してViewComponentからコントローラーアクションを実行する

ASP.NET 5、MvcコアアプリケーションのViewComponentのフォームからListItemsを追加したいと思います。

コンポーネントビュー(Views\Shared\Components\AddListItem\Default.cshtml):

@model ShoppingList.Models.ListItem
<form asp-action="Create">
    <div class="form-horizontal">
        <hr />
        <div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>
        <!-- some fields omitted for brevity -->
        <div class="form-group">
            <label asp-for="Description" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Description" class="form-control" />
                <span asp-validation-for="Description" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

ViewComponentコントローラ(ViewComponents\AddListItem.cs):

namespace ShoppingList.ViewComponents
{
    public class AddListItem : ViewComponent
    {
        private readonly ApplicationDbContext _context;

        public AddListItem(ApplicationDbContext context)
        {
            _context = context;
        }

        public IViewComponentResult Invoke(string listId)
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IViewComponentResult> Create (ListItem listItem)
        {
            _context.ListItem.Add(listItem);
            await _context.SaveChangesAsync();
            return View(listItem);
        }

    }
}

コンポーネントはhome.cshtmlで呼び出されます。

@{
        ViewData["Title"] = "Home Page";
}

@Component.Invoke("AddListItem", @ViewBag.DefaultListId)

ただし、これを機能させることはできません。何も追加されません。

8

AddListItemの名前をAddListItemViewComponentに変更します。これは、コンポーネントを見つけるためにASP.NETで使用される規則です。つまり、ViewComponentsは、ViewComponentサフィックスで終わる必要があります。このようにしたくない場合は、[ViewComponent]属性を使用してクラスを装飾し、nameプロパティを必要な名前に設定できます。

また、Createメソッドは決して呼び出されず、ViewComponentsはHttPostに応答しません。これは、ビューを表示することだけであり、ポストバックに応答してコードを実行することを目的としないためです。ビューはInvokeまたはその非同期バージョンInvokeAsyncのみを呼び出し、それ以外は何も呼び出しません。

最初は少し混乱しますが、それについて考える簡単な方法は、componentクラスでより多くのことができるという意味で、強力なPartialのようなものです。 DIフレンドリーで、テストも簡単です。

ASP.NETチームには、ViewComponentsについて説明するページがあります here

6
Dealdiane

ご協力ありがとうございます、@ Dealdiane。

誰かが怒った場合のために、ここに作業コードがあります:

Views\Shared\Components\AddListItem\Default.cshtml

<form asp-controller="ListItems" asp-action="QuickCreate">
    <div class="form-horizontal">
        <hr />
        <div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>

        <div class="form-group">
            <label asp-for="No" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="No" class="form-control" />
                <span asp-validation-for="No" class="text-danger" />
            </div>
        </div>
 ...

Controllers\ListItemsController.cs

    // POST: ListItems/QuickCreate
    // Create item without showing view, return to home 
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> QuickCreate(ListItem listItem)
    {
            _context.ListItem.Add(listItem);
            await _context.SaveChangesAsync();
            return Redirect("/"); 
    }

作業中のプロジェクトの完全なソースコードは、次の場所にあります。 GitHub ShoppingList

3