2

I'm trying to set up my MVC project to have URLs so that I can go to:

/Groups/

/Groups/Register

/Groups/Whatever

But in my controller, I can also flag some actions as admin only, so that they are accessed at:

/Admin/Groups/Delete/{id}

I would like to keep one GroupController, and have actions so that:

public class GroupController : Controller
{
    public ActionResult Index(){
        return View();
    }
    [AdminAction]
    public ActionResult Delete(int id){
        ...
        return View();
    }
}

Allows:

/Groups is a valid URL.

/Admin/Groups is a valid URL (but would call some other action besides Index - maybe)

/Admin/Groups/Delete/{id} is a valid URL (post only, whatever)

/Groups/Delete is an INVALID url.

I realize this is probably a pretty broad question, but I'm new to MVC and I'm not really sure where to start looking, so if you could just point me in the right direction that would be hugely appreciated.

Community
  • 1
  • 1
Aaron
  • 670
  • 5
  • 17
  • 2
    Why not just set up an admin controller? If i get correctly what you want to do is to have some public group-releated features, and some admin-only. Set up a separate admin controller that cares about administration, and set authorization on that controller level. Don't mix up not related functions, if possible. Separation of concerns and things like that, if you want to say buzzwords, but really simpler on the long run. – Akos Lukacs Sep 08 '11 at 22:15
  • For smaller sites I would agree, but Group is only one of several controllers, and I don't want my admin controller growing to be dozens of actions. – Aaron Sep 09 '11 at 11:57
  • @Valamas It isn't yet, but I don't know enough about areas to know if it should be. I'm very much a beginner when it comes to MVC3. – Aaron Sep 09 '11 at 12:01

1 Answers1

2

As we discussed in the comments below, while it is possible to use my original answer below to achieve the routing solution you requested, a better solution is to use Areas, establish an Admin area, and create controllers in your Admin area to handle the administrative tasks for different objects, such as Group, User, etc. This allows you to set up restricted administrative functions more easily, and is both a better design and a better security model.

ORIGINAL ANSWER

What you want can be accomplished by using the following routes:

public static void RegisterRoutes(RouteCollection routes) 
{ 
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 

    routes.MapRoute( 
        "Admin", // Route name 
        "admin/{controller}/{action}/{id}", // URL with parameters 
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults

    routes.MapRoute( 
        "Default", // Route name 
        "{controller}/{action}/{id}", // URL with parameters 
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 
    ); 
} 

However, as Akos said in the comments, it is a much better design to separate the administrative functions into a different controller. While this is possible, I would recommend against using this design.

UPDATE

It is possible to use a RouteConstraint on your Default route to make it fail if Admin actions are requested. The Default route would look like this:

    routes.MapRoute( 
        "Default", // Route name 
        "{controller}/{action}/{id}", // URL with parameters 
        new { controller = "Home", action = "Index", id = UrlParameter.Optional, // Parameter defaults 
        new { action = IsNotAdminAction() } // route constraint
    ); 

The RouteConstraint would look like this:

public class IsNotAdminAction : IRouteConstraint 
{
    private string adminActions = "create~delete~edit";

    public IsNotAdminAction()
    { }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        // return false if there is a match
        return !adminActions.Contains(values[parameterName].ToString().ToLowerInvariant());
    }
}
counsellorben
  • 10,924
  • 3
  • 40
  • 38
  • How would this prevent Groups/Delete/{id} from being a valid URL? I need to isolate some actions to be admin only. – Aaron Sep 09 '11 at 11:58
  • It will be a good route, but your `AdminAction` attribute should throw a 403 error if the user is not in the proper role. Be aware the you can add a `RouteConstraint` to make the Default route fail under certain circumstances, as I show above. However, it is still a better idea to separate the admin actions into a separate controller. – counsellorben Sep 09 '11 at 14:02
  • I'd rather not have an Admin controller because there are going to be quite a few "Group" type controllers, and I don't want to have admin actions for each of them lumped into one massive controller. I just did a little bit of reading into areas, and I think maybe I want to have an "Admin" area, with separate controllers and views for each "Normal" controller and view that will need admin functionality. Does this seem like a reasonable route to take? – Aaron Sep 09 '11 at 18:03
  • 1
    I would highly recommend using an Admin area for your different admin functions. It is a much better solution than using routing and RouteConstraints. – counsellorben Sep 09 '11 at 18:37
  • Put that in an answer and I'll mark it as correct. Thanks a ton! – Aaron Sep 09 '11 at 19:57
  • Updated my answer to reflect our discusiion in the comments. Best of luck! – counsellorben Sep 10 '11 at 03:52