2

I've reorganized my project into a more logical hierarchy:

-Controllers  
  -Accounts  
    -CustomersController  
  -Setup  
    -SystemDefaultsController
    -SettingsController
  -HomeController

At the moment, I'm just trying to set up my URLs to match this structure. So valid example URLs would be:

localhost:1234/Home/Index
localhost:1234/Setup/SystemDefaults/Index
localhost:1234/Setup/Settings/Index
localhost:1234/CustomerAccounts/Index

So I added a route on top of the default route in RouteConfig.cs:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.MapMvcAttributeRoutes();

    //AreaRegistration.RegisterAllAreas();

    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Setup",
        url: "Setup/{controller}/{action}/{id}",
        defaults: new { controller = "Setup", action = "Index", id = UrlParameter.Optional },
        namespaces: new[] { "MVCWeb.Controllers.Setup" }
    );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        namespaces: new[] { "MVCWeb.Controllers" }
    );
}

This does make the above URLs work, but it has no constraints so these URLs work when I want them to be invalid:

localhost:1234/Setup/CustomerAccounts/Index localhost:1234/SystemDefaults/Index

Additionally, since the Setup route matches everything, if I do either of these:

@Html.ActionLink("Customer Accounts", "Index", "CustomerAccounts")
@Url.Action("Index", "CustomerAccounts")

It generates the URL as /Setup/CustomerAccounts/Index instead of /CustomerAccounts/Index.

Is there a way to do accomplish this without using an Area while still using {controller} in the route URL? Or would I have to add a route specifically for each controller under Setup?

1 Answer 1

2

Have you ever evaluated Attribute Routing in MVC 5? It seems like you're starting a new project, so this could be a good new start. With the [RoutePrefix] attribute, you could probably enforce what you want to achieve easily:

[RoutePrefix("accounts")]
public class CustomersController : Controller
{
    // ...
}

We don't use Attribute Routing yet so I can't speak from own experience but it looks very flexible and promising.

UPDATE

  1. I created a GIST for you where I explain how you could validate your Attributes, not during compile time, but with Unit Tests. This is a simple code snipped designed for MS Test. The validation possibilities are very broad.

  2. Custom Logic we might add to a custom RoutePrefixAttribute? For example, the RoutePrefixAttribute allows a string as a parameter. You could rewrite it to allow only a specific Enum as parameter, which lists only possible values, and internally set the Prefix string.

Sign up to request clarification or add additional context in comments.

4 Comments

I was actually just considering that. One thing that I have experienced with attribute routing is it can be very difficult to keep track of. For instance if someone puts in an erroneous route that is handling URLs it shouldn't it can be very difficult to troubleshoot when your routing is defined all over the place as attributes rather than in a single spot.
I agree. You can reduce the effect a bit by using Constants for your routes, e.g. [RoutePrefix(RouteAreas.Accounts)], override the RoutePrefixAttribute to extend with custom logic, and also, in a similar case, we unit-test such Attribute usage with a (gated check-in) Unit Test which uses reflection. So for example, you could verify if the Controller Type Namespace is matching your Attribute (If you're interested in that, I can give you an example code).
Great ideas! I should've thought of the constants - I used to do that for event brokering. What type of custom logic might you add to RoutePrefixAttribute? Yes, I'd love to see your test implementation if you'd care to share.
@xr280xr updated my answer as a reply to your questions

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.