前にも、この方法について考えたことがあって、その時はストラテジパターンを使ってDelegateでのコマンド振り分けでの実装をしてたんですが、少し前に違う方法を実装してるのを見て悔い改めたんです。
MVCによく似合う方法は、属性ベースで対象となるアクションを振り分ける(判定する)方法ですよね。
AcceptVerbsでHTTP Method毎に処理を振り分ける事ができるのを上手く利用して、Submitの値毎に処理を振り分けるためにActionMethodSelectorAttributeを派生したSubmitCommandAttributeというのを定義していました。
using System; using System.Reflection; using System.Web.Mvc; namespace MvcApplication2.Controllers { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class SubmitCommandAttribute : ActionMethodSelectorAttribute { private string _submitName; private string _submitValue; private static readonly AcceptVerbsAttribute _innerAttribute =
new AcceptVerbsAttribute(HttpVerbs.Post); public SubmitCommandAttribute(string name) : this(name, string.Empty) { } public SubmitCommandAttribute(string name, string value) { _submitName = name; _submitValue = value; } public override bool IsValidForRequest(ControllerContext controllerContext,
MethodInfo methodInfo) { if (!_innerAttribute.IsValidForRequest(controllerContext, methodInfo)) return false; // Form Value var submitted = controllerContext.RequestContext
.HttpContext
.Request.Form[_submitName]; return string.IsNullOrEmpty(_submitValue) ? !string.IsNullOrEmpty(submitted) : string.Equals(submitted, _submitValue,
StringComparison.InvariantCultureIgnoreCase); } } }
これだけなんですけども...。HttpPostのコードを参考に内部にAcceptVerbsAttributeを保持してPOST時のみをIsValidにしてますが、DeleteとPutも必要なら要修正。
using System.Web.Mvc; namespace MvcApplication2.Controllers { public class HomeController : Controller { // // GET: /Home/ public ActionResult Index() { return View(); } [ActionName("Different")] [SubmitCommand("DoSave")] public ActionResult DifferentSave() { TempData["message"] = "saved! - defferent"; return View("Index"); } [ActionName("Different")] [SubmitCommand("DoDelete")] public ActionResult DifferentDelete() { TempData["message"] = "deleted! - defferent"; return View("Index"); } [ActionName("Same")] [SubmitCommand("DoSubmit","保存")] public ActionResult SameSave() { TempData["message"] = "saved! - same"; return View("Index"); } [ActionName("Same")] [SubmitCommand("DoSubmit","削除")] public ActionResult SameDelete() { TempData["message"] = "deleted! - same"; return View("Index"); } } }
コントローラでこんな感じにアクションを定義しておいて、Viewを以下のようにしておきます。
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Index</title> </head> <body> <h1><%= TempData["message"] ?? "Click some button" %></h1> <h2>異なるnameのsubmit</h2> <% using (Html.BeginForm("Different", "Home")) { %> <input type="submit" name="DoSave" value="保存" /><br /> <input type="submit" name="DoDelete" value="削除" /> <% } %> <h2>同一nameでValueの異なるsubmit</h2> <% using (Html.BeginForm("Same","Home")) { %> <input type="submit" name="DoSubmit" value="保存" /><br /> <input type="submit" name="DoSubmit" value="削除" /> <% } %> </body> </html>
動かしてみると、最初に↓。ボタンが4種類出てきます。上2つはnameとvalueの異なるsubmitで、下2つがnameが同じでvalueが違うsubmit。
上から順にボタンを押したのが↓。
ちゃんとTempDataの値が違うのが確認できますね(ページ上部のH1)。
で、ココまで書いときながら、前にどこで見たのかを検索して探し出してみてショック。
ASP.NET MVC – Multiple buttons in the same form - David Findley's Blog
まんま、同じになるという大失態。やっぱり年始からこんなコードを書いてて先が思いやられる...。