I need to parse an url like the following
/controller/action/subaction/id
At the moment i'm using a switch on subaction to see what actually needs to be done. 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);
}
}
This works, but i'd rather have seperate actions for each event, directly accessed from the route. If possible I would like to combine the action and subaction in the routemap to access the right action.
Is that possible directly from the routemap?
If I were you I'd write an action method selector and use that to avoid branching in your actions. I've written one that separates actions that take optional parameters (thus avoiding branched code within action - simplified unit testing). Default Asp.net MVC defined route has an optional id
parameter
{controller}/{action}/{id}
id = UrlParameter.Optional
So it makes sense to have these two action methods:
public ActionResult Index() { ... }
public ActionResult Index(int id) { ... }
I've accomplished just that by writing a custom action selector filter. Here's a detailed blog post that describes the whole thing and provides some code you can peek at.
In your case this means you'd have to write a custom action method selector class called SubactionAttribute
and then simply decorate your actions with it:
[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);
}
I'm not going to write the whole class for you, but I will only point you in the right direction so you can follow the same path to get where you're headed:
[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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With