- Create a 'delicious' user interface for entering tags using ASP.NET MVC Razor and jQuery
- Pass an Array of Integers to a Controller Action in ASP.NET MVC
As you can probably tell from these titles, the application that I'm developing is centered around the principle of tag-based metadata. One of the important features in this application is that I want users to be able to use multiple tags to narrow results - similar to how Delicious does it. For example, the following URL will return MVC articles written by 'The Gu':
http://www.delicious.com/tag/aspnetmvc+scottgu
I wanted to have a similar experience and so I factored this in when I sat down to design my URL routing scheme. In the initial cut, I identified the following routes:
Path | Details |
---|---|
/groupA | Displays all data for "Group A" |
/groupA/cricket | Displays all data tagged as 'cricket' for "Group A" |
/groupA/cricket+batting | Displays all data tagged as 'cricket' and 'batting' for "Group A" |
/tags/cricket | Displays all data tagged as 'cricket' from any Group |
Based on these requirements, I decided to implement the following two actions:
And I wired those up by using the following Routing configuration:ContentController.Group(string groupName, IEnumerabletagValues) ; ContentController.Tags(IEnumerable tagValues) ;
routes.MapRoute("1", "tags/{tagValues}", new { controller = "Content", action = "Tags" });
routes.MapRoute("2", "{groupName}/{tagValues}", new { controller = "Content", action = "Group", tagValues = ""});
So now, when users enter the URL's that I have in my example table above, they will successfully be routed to the correct Controller Action's, but there's still one step to go before it will work as desired. As things currently stand, if the user passes through multiple tag values to one of these actions, they will be received only as a single value and we will have to parse them into their separate tag values. For convenience, it would better if that parsing had already occurred and we could work direct with the individual tags by the time they reached our controller Actions. The trick is of course to combine what I showed in the previous article and to implement a custom ActionFilter on the controller. In this case, the custom ActionFilter will look like this:
public class TagValuesFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.RouteData.Values["tagValues"] == null)
return;
var list = new List<string>();
var tagValues = filterContext.RouteData.Values["tagValues"].ToString()
.Split("+".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var tagValue in tagValues)
{
list.Add(tagValue);
}
filterContext.ActionParameters["tagValues"] = list;
}
}
And now all that is left is to simply apply that attribute to the ContentController like so:Now every request will be correctly routed through to the right controller Action's and the tag values will be already nicely split out for us, making the handling code nice and simple and free of any parsing code.[TagValuesFilter] public class ActivitiesController : Controller
No comments:
Post a Comment