views:

83

answers:

2

I'm not really sure how to express this, but one pattern I often see in RoR apps is something like this:

/Post/postid/Comment/commentid

or

/Project/projectid/Tasks/taskid

Essentially in the model since a Project has Tasks you can access the TaskController from within a project resource.

Now I have started using the SimplyRestfulRouting from MVCContrib with ASP.NET MVC, so I have the following format:

Route => Action

/{Controller} => Index()

/{Controller}/{id} => Show()

I won't get into all the details, anyone can google SimplyRestfulRouting to see. I am wondering if there is a consistent way to then allow:

/{Controller}/{id}/{Controller}/{id} type syntax.

Obviously it would be ideal if this was a convention over configuration style rather than just setting up lots of routes.

A: 

I like this concept, I want to go to /Project/ProjectId/Tasks and see a filtered view of tasks for that Project. Personally, I don't mind, however, if the "item specific" views (e.g. details / show / update / etc) are back at /Task/TaskId.

I do, however, see how it could be beneficial for "dependent" types, such as when a task can't exist without a Project, for them to be accessed via /Project/ProjectId/Tasks/TaskId.

To implement my version, I have an Action in the Project controller as follows:

public ActionResult Tasks(string id)
{
    Project projectToDisplay = Repository.GetProject(id);
    ViewModel["Tasks"] = Repository.GetTasksForProject(projectToDispaly);
    return View(projectToDisplay);
}

Obviously, this could be improved with a strongly typed ViewModel.

For reference, my repository (Entity Framework specific) has the following code:

public Project GetProject(int id)
{
    return _entities.Projects.FirstOrDefault(m => m.Id == id);
}

public IList<Task> GetTasksForProject(Project project)
{
    return _entities.Tasks.Where(m => m.Project.Id == project.Id).ToList();
}

Alternatively, with Entity Framework, you could just do the following in the repository:

public Project GetProject(int id)
{
    return _entities.Projects.Include("Tasks").FirstOrDefault(m => m.Id == id);
}

And then the controller would just need:

public ActionResult Tasks(string id)
{
    return View(Repository.GetProject(id));
}

which is a little bit more ViewModel-esque.

(NB: This code has been adapted to your project / task context, so it is not my actual code. If this code doesn't work or has errors, I apologise, I've effectively re-written it so there may be typos / etc.)

Mark van Proctor
I wonder if this starts to violate SRP with respect to the controller though, in that it is responsible for two types of resources.
Chris Nicola
Possibly, but i see it as more of a workaround in an imperfect world than an "ideal solution". I guess it depends on what is more important, achieving your desired outcome or not violating current best practice beliefs. IMHO, sometimes you need to do something "the wrong way" in order to get it done. I guess I prioritise realism over idealism. At the end of the day, if you can't deliver required functionality because "the code is ugly" the bottom line is that you haven't delivered required functionality. Just my 2 cents :P (Let the flaming begin...)
Mark van Proctor
A: 

I have found the answer and it is Steve Hodgekiss' Restful Routes. It is much more flexible than the one that comes with MVCContrib and allows for the sort of thing I am talking about and much, much more.

http://stevehodgkiss.com/2009/10/11/restful-routes-for-asp-net-mvc.html

Chris Nicola