0

I'm not sure if this is possible using mvc routing, I haven't been able to find a similar example.

I have about 5~ controller actions that are the same method, so I'd like to refactor them into a single action. I'd like to pass an enum value to the controller to tell it what path it should pass to lower layers.

Example:

public ActionResult ViewPage(int id, PageEnum page) {
    var model = MyService.GetModelForTemplate(id, page);
    return ("ViewPage", model);
}

Then the user could access this either through /PagesTypeOne/ViewPage/, or /PagesTypeTwo/ViewPage/. Both routes leading to the same endpoint.

Route table attempt:

routes.MapRoute(
            name: "typeOne",
            url: "PagesTypeOne/{action}/{id}",
            defaults: new { controller = "Pages", action = "ViewPage", id = UrlParameter.Optional, page = PageEnum.TypeOne, }
        );

routes.MapRoute(
            name: "typeTwo",
            url: "PagesTypeTwo/{action}/{id}",
            defaults: new { controller = "Pages", action = "ViewPage", id = UrlParameter.Optional, page = PageEnum.TypeTwo, }
        );

This obviously isn't working.

Is there a way I can do something like this? It would make my code much more concise.

2
  • 1
    Why have two different names (typeOne and typeTwo) if you're changing the id value? I only see one argument defined in your routes, but I see the action accepting two arguments. If you're trying to pass the Enum in the global route to the page parameter, why are you calling the parameter in your global id? I'm a bit confused. Commented Oct 13, 2014 at 15:31
  • @xDaevax Hi! I'm sorry my example code is a little sloppy. Id of 0 has a significance in this case, it would pass back the page in a "creation mode" if it is zero, of the specified layout based on the enum. If it has a non-0 value, then it passes back the model with data for the specified layout based on the enum. Commented Oct 13, 2014 at 15:39

2 Answers 2

3

screen != page, so if the property on the anonymous type matches the parameter it will work:

public ActionResult ViewPage(int id, PageEnum screen) {
  var model = MyService.GetModelForTemplate(screen);
  return ("ViewPage", model);
}

Updated: Created a empty application and it work flawlessly:

namespace MvcApplication6
{
    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }

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

            routes.MapRoute(
                "Test1",
                "PagesTypeOne/{action}/{id}", // URL with parameters
                new { controller = "Home", 
                      action = "Index", 
                      id = UrlParameter.Optional, 
                      page = PageEnum.PageOne } // Parameter defaults
            );

            routes.MapRoute(
                "Test2",
                "PagesTypeTwo/{action}/{id}", // URL with parameters
                new { controller = "Home", 
                      action = "Index", 
                      id = UrlParameter.Optional, 
                      page = PageEnum.PageOne } // Parameter defaults
            );

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

        }

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
    }
}

public enum PageEnum
{
    Undefined,
    PageOne,
    PageTwo
}

Controller:

namespace MvcApplication6.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult ViewPage(int id, PageEnum page)
        {
            var debug = 1;  // break point

            return new EmptyResult();
        }

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

5 Comments

Thanks! I missed that in my example posted, however changing it does not seem to have worked; the enum is passed as null :(
Enums as you defined them can't be null (I don't see you using Nullable<T>).
sorry should have clarified, it throws "The parameters dictionary contains a null entry for parameter 'page' of non-nullable type...."
My code works just fine. You may have the incorrect order for adding map routes.
Absolutely right, I had a routing issue with another defined path. Commented out that path and it worked just fine. Marking as accepted answer, thanks!
2

you can make it completely dynamic with one route definition:

   // the route must be defined as the first route
   routes.MapRoute(
        name: "typeTwo",
        url: "{page}/ViewPage/{id}",
        defaults: new { controller = "Pages", action = "ViewPage", id = UrlParameter.Optional },
        new { page= getPageTypes() }
    );

the getPageTypes method:

private static string getPageTypes()
{
     var pageTypes = Enum.GetNames(typeof(PageEnum));
     return string.Join("|", pageTypes );
}

but PagesTypeOne/ViewPage/4 part must match the enum's name.

2 Comments

This is a cool solution. Is there a way I can get that value at the controller action then to see which url the user pointed to? It has implications for my viewmodel.
@SarahBourt yes, use Request.RawUrl or Request.Url

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.