ASP.NETでControllerにActionLinkを使って引数を渡す方法

みなさんこんにちは

ひろぽんです!

ASP.NETでWEB開発をしていて、ViewからControllerにModel以外の引数を渡したい!って思うことありませんか?

私は割とあります。

例えば、記事一覧ページからコメントを投稿する場合等、リレーションの設定をしたい場合に!

上記のように記事一覧ページからコメントを投稿する場合、Controllerはあくまでもコメントになり、メソッドはCreateになります。

ですが普通にModelだけ投げてしまうと、コメントと記事が紐づきません。

そんな時に、Modelと記事のIdを投げてあげると、コメントのController内でコメントと記事の紐づけができますよね!

今回はそんな場合等に使える、ASP.NETでViewからControllerにActionLinkを使ってModel以外の値を投げる方法について書いていきます!

目次

前提となるMODEL

💡 Controller の役割や Form_Load 的な理解については別記事 Controller は WinForms の Form_Load 拡張版 で WinForms 経験者向けに書いてます。

    public class Article
    {
        public int id { get; set; }
        public string title { get; set; }
        public string body { get; set; }
        public DateTime created { get; set; }
        public DateTime updated { get; set; }

    public virtual ICollection<Comment> Comments { get; set; }
}</code></pre></div>

記事のModelはこんな感じですね!

    public class Comment
    {
        public int id { get; set; }
        public string title { get; set; }
        public string body { get; set; }
        public DateTime created { get; set; }
        public DateTime updated { get; set; }

    public virtual Article Article { get; set; }
}</code></pre></div>

コメントのModelも記事と同じです。

基本的にタイトルがあって本文がある。といった形です。

記事1対コメント多になっているのが特徴ですかね!

では続いてスキャフォールドですが今回必要なのは、CommentのControllerのCreateとArticlesのDetailsのViewなので、その部分のみ書いていきます!

まずはCommentのCreateメソッドから!

        // POST: Comments/Create
        // 過多ポスティング攻撃を防止するには、バインド先とする特定のプロパティを有効にしてください。
        // 詳細については、https://go.microsoft.com/fwlink/?LinkId=317598 を参照してください。
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "id,title,body,created,updated")] Comment comment)
        {
            if (ModelState.IsValid)
            {
                db.Comments.Add(comment);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

        return View(comment);
    }</code></pre></div>

このCreateメソッドにArticleIdを引数に受け取るようにして、Create実行時に記事と紐づくようにすると以下のようになります。

        // POST: Comments/Create
        // 過多ポスティング攻撃を防止するには、バインド先とする特定のプロパティを有効にしてください。
        // 詳細については、https://go.microsoft.com/fwlink/?LinkId=317598 を参照してください。
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "id,title,body,created,updated")] Comment comment,int articleId)
        {
            var article = db.Articles.FirstOrDefault(a => a.id == articleId);
            if (ModelState.IsValid)
            {
                comment.Article = article;
                db.Comments.Add(comment);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

        return View(comment);
    }</code></pre></div>

引数にarticleIdを設定して、Create実行時にデータベースから引数のarticleIdの記事を取得し、CommentのArticleにセットする。

これだけで、リレーションが登録されるってめちゃくちゃ便利ですね。

SQLならなかなかややこしいことを書かないといけないのに、Asp.Netではその辺はあまり意識することないので、便利ですね!!!

では続いて、ArticleのDetailsのViewからCommentのCreateを呼び出し引数articleIdを渡す作業!

@model WebApplication1.Models.Article

@{ ViewBag.Title = "Details"; }

<h2>Details</h2>

<div> <h4>Article</h4> <hr /> <dl class="dl-horizontal"> <dt> @Html.DisplayNameFor(model => model.title) </dt>

    &lt;dd&gt;
        @Html.DisplayFor(model =&gt; model.title)
    &lt;/dd&gt;

    &lt;dt&gt;
        @Html.DisplayNameFor(model =&gt; model.body)
    &lt;/dt&gt;

    &lt;dd&gt;
        @Html.DisplayFor(model =&gt; model.body)
    &lt;/dd&gt;

    &lt;dt&gt;
        @Html.DisplayNameFor(model =&gt; model.created)
    &lt;/dt&gt;

    &lt;dd&gt;
        @Html.DisplayFor(model =&gt; model.created)
    &lt;/dd&gt;

    &lt;dt&gt;
        @Html.DisplayNameFor(model =&gt; model.updated)
    &lt;/dt&gt;

    &lt;dd&gt;
        @Html.DisplayFor(model =&gt; model.updated)
    &lt;/dd&gt;

&lt;/dl&gt;

</div>
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.id }) |
@Html.ActionLink("Back to List", "Index")
</p>

なんの変哲もないArticleのDetailsのViewにコメント追加リンクを追加します!

@model WebApplication1.Models.Article

@{ ViewBag.Title = "Details"; }

<h2>Details</h2>

<div> <h4>Article</h4> <hr /> <dl class="dl-horizontal"> <dt> @Html.DisplayNameFor(model => model.title) </dt>

    &lt;dd&gt;
        @Html.DisplayFor(model =&gt; model.title)
    &lt;/dd&gt;

    &lt;dt&gt;
        @Html.DisplayNameFor(model =&gt; model.body)
    &lt;/dt&gt;

    &lt;dd&gt;
        @Html.DisplayFor(model =&gt; model.body)
    &lt;/dd&gt;

    &lt;dt&gt;
        @Html.DisplayNameFor(model =&gt; model.created)
    &lt;/dt&gt;

    &lt;dd&gt;
        @Html.DisplayFor(model =&gt; model.created)
    &lt;/dd&gt;

    &lt;dt&gt;
        @Html.DisplayNameFor(model =&gt; model.updated)
    &lt;/dt&gt;

    &lt;dd&gt;
        @Html.DisplayFor(model =&gt; model.updated)
    &lt;/dd&gt;

&lt;/dl&gt;

</div>
@Html.ActionLink("コメントを追加","Create",new { Controller = "Comments",articleId = Model.id})
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.id }) |
@Html.ActionLink("Back to List", "Index")
</p>

実際に触ってみるとこんな感じになります!

トップ画面には、ArticleのIndexを設定しました!

ArticleのDetailsを見てみると

コメント追加リンクが設定されています!

ここから実際にコメントを追加してみます!

コメントが登録されました!

これでArticleIdが実際に紐づいていたらOKですね!

紐づいている!

OKです!

以上

💡 補足: 業務系の現場でよくハマるパターン

俺もこの ActionLink のリンク生成、過去案件でハマったところを3つ並べておきます。

① ルーティング順序のミスでリンクが効かない

RouteConfig.cs に書いた MapRoute の順序で URL が解決される。デフォルトの {controller}/{action}/{id} より下にカスタムルートを書くと、デフォルトに先に拾われて404。順序めっちゃ大事。

② パラメータ名と Action 引数名の不一致で null

@Html.ActionLink("詳細", "Detail", new { userId = 1 }) で Controller 側が public ActionResult Detail(int id) だと、 userId じゃなくて id を期待してるので null になる。名前を完全一致させる。

③ HTML 属性指定で htmlAttributes に null を渡す罠

ActionLink のオーバーロードは引数順序が紛らわしい。 @Html.ActionLink("text", "action", new { id = 1 }, null) の null 部分が htmlAttributes 指定。 ここを省略すると routeValues として認識されない場合があるので、明示的に null か new {} を渡す。

❓ よくある質問

Q1. ActionLink と Url.Action の違いは?

A. ActionLink は <a> タグまで生成、 Url.Action は URL 文字列だけ返す。 jQuery で動的にリンク作る時は Url.Action。 ビューに直接書くなら ActionLink。

Q2. RouteValueDictionary を使うべきタイミングは?

A. パラメータ名が動的に決まる場合(変数のキー名で渡す)。 静的な場合は匿名型 new { id = 1 } で十分。

Q3. Area ある時の ActionLink の書き方は?

A. routeValuesarea = "AreaName" を入れる。 @Html.ActionLink("text","action","controller",new { area = "Admin", id = 1 }, null) という感じ。

Q4. POST 用のリンクを作るには?

A. ActionLink は GET のみ。 POST したいなら Html.BeginForm() + submit ボタン、または jQuery で form 動的生成。 業務系では POST リンク禁止(CSRF 対策上)。

Q5. ASP.NET Core での書き方は?

A. asp-controller / asp-action / asp-route-id 等の TagHelper で書く。 <a asp-controller="Home" asp-action="Index">Home</a> という感じ。 ActionLink より読みやすい。

📚 関連記事

この記事が気に入ったら
いいねしてね!

どんどんシェア待ってるぜ!!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次