23 listopada 2008, 13:46 dario Komentarze (0)

Wykorzystanie ActionSelectionAttribute w ASP.NET MVC

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":

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Web.Mvc;
 
namespace Softio.Web.MVC.Filters
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class AcceptInputAttribute : ActionSelectionAttribute
    {
 
        public AcceptInputAttribute()
        {
            Names = new List();
        }
 
        public AcceptInputAttribute(string name)
            : this()
        {
            Names.Add(name);
        }
 
        public AcceptInputAttribute(params string[] name)
            : this()
        {
            Names.AddRange(name);
        }
 
        public List Names { get; private set; }
 
        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            if (controllerContext.HttpContext.Request.HttpMethod.Equals("POST", StringComparison.InvariantCultureIgnoreCase))
            {
                foreach (string n in Names)
                {
                    if (!controllerContext.HttpContext.Request.Form[n].IsNullOrEmpty())
                    {
                        return true;
                    }
                }
            }
            return false;
        }
    }
}

Atrybut ten nadany metodzie "Save" zbada, czy został przesłany zdefiniowany element formy.

[AcceptInput("Save", "SaveAndStay")]
public ActionResult Save(
    int id,
    string saveandstay)
{
    // Zapisz dane

    if (saveandstay != null)
    {
        return Edit(id);
    }
    return RedirectToAction("Index");
}

[AcceptInput("DeletePermanently")]
public ActionResult Save(int id)
{
    // Usuń z bazy
    return RedirectToAction("Index");
}

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 name="Save" type="submit" value="Zapisz" />
<input name="SaveAndStay" type="submit" value="Zapisz i zostań" />
<input name="DeletePermanently" type="submit" 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.  

Tagi:

Asp.net-mvc

Komentarze zablokowane

O autorze

Dariusz Gil - projektant i programista aplikacji internetowych budowanych na platformie Microsoft w technologii ASP.NET (C#) oraz MS SQL Server. Obecnie właściciel (narazie :)) jednoosobowej firmy Softio.

Filtruj używając APML