Budując aplikację przy użyciu ASP.NET MVC możemy trafić na następujący problem. Otóż standardowo jedna forma na stronie skojarzona jest z konkretną akcją kontrolera. Na przykład:
<form action="User/Save" />
Często zdarza się jednak, że na takiej formie mamy więcej niż jeden input typu submit. Wciśnięcie któregoś z nich spowoduje wysłanie danych formy zawsze do tej samej metody "Save" zdefiniowanej w kontrolerze "User".
W metodzie "Save" możemy w sumie sprawdzić z jakiego submita wyszła akcja i stosownym if'em zdecydować co ma się dziać dalej. Na szczęście możemy sobie nieco zautomatyzować korzystając z filtru typu "ActionSelectionAttribute". Poniżej prezentuję kod atrybutu "AcceptInputAttribute":
1: using System;
2: using System.Collections.Generic;
3: using System.Reflection;
4: using System.Web.Mvc;
5:
6: namespace Softio.Web.MVC.Filters
7: {
8: [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
9: public class AcceptInputAttribute : ActionSelectionAttribute
10: {
11:
12: public AcceptInputAttribute()
13: {
14: Names = new List<string>();
15: }
16:
17: public AcceptInputAttribute(string name)
18: : this()
19: {
20: Names.Add(name);
21: }
22:
23: public AcceptInputAttribute(params string[] name)
24: : this()
25: {
26: Names.AddRange(name);
27: }
28:
29: public List<string> Names { get; private set; }
30:
31: public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
32: {
33: if (controllerContext.HttpContext.Request.HttpMethod.Equals("POST", StringComparison.InvariantCultureIgnoreCase))
34: {
35: foreach (string n in Names)
36: {
37: if (!controllerContext.HttpContext.Request.Form[n].IsNullOrEmpty())
38: {
39: return true;
40: }
41: }
42: }
43: return false;
44: }
45: }
46: }
Atrybut ten nadany metodzie "Save" zbada, czy został przesłany zdefiniowany element formy.
1: [AcceptInput("Save", "SaveAndStay")]
2: public ActionResult Save(
3: int id,
4: string saveandstay)
5: {
6: // Zapisz dane
7:
8: if (saveandstay != null)
9: {
10: return Edit(id);
11: }
12: return RedirectToAction("Index");
13: }
14:
15: [AcceptInput("DeletePermanently")]
16: public ActionResult Save(int id)
17: {
18: // Usuń z bazy
19: return RedirectToAction("Index");
20: }
W powyższym kodzie mamy dwie metody Save, gdzie jedna z nich zapisuje dane użytkownika do bazy i w zależności od istnienia "SaveAndStay" wychodzi do listy lub zostaje w edycji. Druga metoda ma za zadanie usunięcie użytkownika z bazy.
Do zadziałania potrzebne jest nadanie atrybutu "name" dla "submitów". Odpowiednio dla powyższego przykładu:
<input type="submit" name="Save" value="Zapisz" />
<input type="submit" name="SaveAndStay" value="Zapisz i zostań" />
<input type="submit" name="DeletePermanently" value="Usuń" />
W ten oto prosty sposób uzyskaliśmy elastyczność i zarazem estetyczność kodu.
Słyszałem i czytałem, że problemy takie ludzie rozwiązują za pomocą JavaScryptu i podmieniają atrybut "action". A Wy jak to robicie w swoich aplikacjach z wykorzystaniem MVC? :)
Errata:
W wersji Beta atrybut ten został przemianowany na ActionMethodSelectorAttribute.
Ten artykuł jest widoczny także na:
ZINE.NETJeśli spodobał Ci się ten artykuł, to podziel się tą informacją z innymi.