5 votes

.NET MVC Routing - lier 2 paramètres routeMap

J'ai besoin d'analyser une url comme la suivante

/controller/action/subaction/id

Pour le moment, j'utilise un interrupteur sur une sous-action pour voir ce qui doit être fait. EG :

    public ActionResult Members(string subaction, long id=0)
    {
        switch (subaction)
        {
            case "Details":
                var member = _payment.GetMember(id);
                return View("Members_details", member);
            default:
                var members = _payment.GetMembers().ToList();
                return View("Members_list", members);
        }
    }

Cela fonctionne, mais je préférerais avoir des actions séparées pour chaque événement, directement accessibles depuis l'itinéraire. Si possible, je voudrais combiner l'action et la sous-action dans la feuille de route pour accéder à la bonne action.

  • /controller/action/ appellerait action()
  • /controller/action/subaction appellerait action_subaction()
  • /controller/action/subaction/id appellerait action_subaction(id)

Est-ce possible directement à partir de la carte routière ?

2voto

Robert Koritnik Points 45499

Classe de sélecteur de méthode d'action personnalisée

Si j'étais vous, j'écrirais un sélecteur de méthode d'action et utiliser cela pour éviter les ramifications dans vos actions. J'en ai écrit un qui sépare les actions qui prennent des paramètres optionnels (évitant ainsi le code ramifié dans l'action - simplifiant les tests unitaires). La route par défaut définie par Asp.net MVC possède un paramètre optionnel id paramètre

{controller}/{action}/{id}
id = UrlParameter.Optional

Il est donc logique de disposer de ces deux méthodes d'action :

public ActionResult Index() { ... }
public ActionResult Index(int id) { ... }

C'est ce que j'ai fait en écrivant un filtre sélecteur d'action personnalisé. Voici un article de blog détaillé qui décrit l'ensemble et fournit du code que vous pouvez consulter.

Que diriez-vous d'une solution à votre problème

Dans votre cas, cela signifie que vous devez écrire une classe de sélecteur de méthode d'action personnalisée appelée SubactionAttribute et ensuite simplement décorer vos actions avec :

[Subaction("Details")]
public ActionResult Members(long id)
{
    var member = _payment.GetMember(id);
    return View("Members.Details", member);
}

[Subaction] // no name would mean default subaction (when not provided)
public ActionResult Members()
{
    var members = _payment.GetMembers().ToList();
    return View("Members.List", members);
}

Je ne vais pas écrire tout le cours pour vous, mais je vais seulement vous indiquer la bonne direction pour que vous puissiez suivre le même chemin pour arriver là où vous allez :

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class SubactionAttribute : ActionMethodSelectorAttribute
{
    #region Properties

    /// <summary>
    /// Gets subaction name.
    /// </summary>
    public string Name { get; private set; }

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="SubactionAttribute"/> class.
    /// </summary>
    public SubactionAttribute()
        : this(null)
    {
        // does nothing
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SubactionAttribute"/> class.
    /// </summary>
    /// <param name="subactionName">Sub-action name</param>
    public SubactionAttribute(string subactionName)
    {
        this.Name = subactionName;
    }

    #endregion

    #region ActionMethodSelectorAttribute implementation

    /// <summary>
    /// Determines whether the action method selection is valid for the specified controller context.
    /// </summary>
    /// <param name="controllerContext">The controller context.</param>
    /// <param name="methodInfo">Information about the action method.</param>
    /// <returns>
    /// true if the action method selection is valid for the specified controller context; otherwise, false.
    /// </returns>
    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
    {
        if (controllerContext == null)
        {
            throw new ArgumentNullException("controllerContext");
        }

        // get the value of subaction here
        string subName = /* this part you'll have to write */

        // determine whether subaction matches
        return this.Name == subName;
    }

    #endregion
}

0voto

musefan Points 23208

Voulez-vous dire que vous voulez effectivement utiliser plusieurs actions "Détails" dans le même contrôleur ? Si c'est le cas, je pense que c'est une bonne raison pour commencer à diviser vos contrôleurs.

Vous devriez probablement commencer par un contrôleur appelé Membres avec les actions Détails et Liste (ou Index).

/Members/Details/ID
/Members/List/

Avez-vous une bonne raison logique de les avoir tous dans le même contrôleur ?

Sinon, vous pourriez appeler vos actions MemberDetails et MemberList et URL comme...

/Controller/MemberDetails/ID
/Controller/MemberList/

Essayez le code :

[ActionName("Member/Details")]
public ActionResult Members_Details(int id){
    return View();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X