MVC Routing

Vote:
 

I'm trying to wrap my head around how EPi7 using MVC handles custom routing.  I have a custom data search page (not content. data is managed in a seperate system) where I want to pull two paramenters from the url.

My url is something like http://mydomain.com/find-data/results/texas/green/

"find-data" is a page that collects the search parameters. "results" is a page that processes the request. "texas" and "green" are the two parameters. If I navigate to http://mydomain.com/find-data/results/ it loads correctly but with no search data. What I'm hoping will happen is when /find-data/results/texas/green/ is requested, I can pass "texas" and "green" into my code and display the results for the "results" page.

I can't seem to figure out how make the routing work. I've done similar things plenty of times with plain MVC apps and I can get the data I need from teh ViewContext.RouteData. Granted that was MVC 3, but I can't imagine it's that much different in 4. I have the route registered in my Global.ascx. When I debug through VS, it hits the RegisterRoutes method. I'm get a 404 every time I run the page request with parameters. I know I could do a query string but I'm really trying to stay away from that. I like my urls to be descriptive.

#65320
Jan 26, 2013 0:26
Vote:
 

Could you post the code where you´re registering the route and the code for your controller (just the method signatures).


Cheers

Frederik

#65326
Jan 26, 2013 12:00
Vote:
 

public class Global : EPiServer.Global
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
        }

        protected override void RegisterRoutes(System.Web.Routing.RouteCollection routes)
        {
            base.RegisterRoutes(routes);

            RouteTable.Routes.MapContentRoute(name: "FindData",
            url: "find-data/results/{state}/{color}/",
            defaults: new { action = "index" });

        }
    }

 

controller: // no controller for partial view. Do I need one?

public class InteriorController : PageController<InteriorPage>
    {
        public ActionResult Index(InteriorPage currentPage)
        {
            /* Implementation of action. You can create your own view model class that you pass to the view or
             * you can pass the page type for simpler templates */

            return View(currentPage);
        }
    }

 

I'm trying to get my page to run a partial view only if there are parameters present. If not, then, it will display content

View:

@model Models.Pages.InteriorPage

@{
    Layout = "~/Views/Layouts/_Layout.cshtml";

   var data = ???? // ViewContext.RouteData.Values
}

<div class="article-gen" role="main">
        <article>
            @if (data != null) { // data would be a dictionary with the parameters - texas and green in this case
               Html.RenderPartial("~/Views/Shared/FindDataResults.cshtml", data.ToDictionary<string, string>());
            } else {
                <h1 @Html.EditAttributes(x => x.Title)>@Model.Title</h1>
                @Html.PropertyFor(m => m.MainBody) // probably some default message pulled from CMS.
            }
       </article>
    </div>

 

 Update.

I've modified the route a bit to use

defaults: new { controller = "Interior",
                            action = "Index",
                            state = UrlParameter.Optional,
                            color = UrlParameter.Optional });

I no longer get a 404 but I do get this message, when I'm running on Cassini. If I use my IIS, it gives a 404.

The provided content link does not have a value

[ArgumentNullException: The provided content link does not have a value. Parameter name: contentLink] EPiServer.DataFactory.Get(ContentReference contentLink, ILanguageSelector languageSelector) +161 EPiServer.Web.Routing.MultiplexingRouteHandler.GetRoutedData(RequestContext requestContext, String language) +225 EPiServer.Web.Routing.MultiplexingRouteHandler.GetRouteHandler(RequestContext requestContext) +82 EPiServer.Web.Routing.MultiplexingRouteHandler.GetHttpHandler(RequestContext requestContext) +44 System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context) +8913000 System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +86 System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +148 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +

 


I'm on the right track but I'm obviously missing something.

 

 

 

#65382
Edited, Jan 28, 2013 16:16
Vote:
 

Hello,

I’m not really sure what you want to do here, if you want to route to a CMS page or not.

Routing to a CMS page

If you want to route to a CMS page, which you have specified in your controller, you should register a route like: RouteTable.Routes.MapContentRoute(name: "FindData", url: "{node}/{action}/{state}/{color}/", defaults: new { action = "index" }); This route will route to a page in the page tree. If you have created a page with the name “find-data” and goes to http://mydomain.com/find-data/results/texas/green/ it will go to the controller that handles the pagetype the “find-data” have been created with. It will then use the “results” action in that controller. To use the index action you have to go to http://mydomain.com/find-data/index/results/texas/green/

If you want to go to a page called “results”, you have to create a subpage to “find-data” called “results”, which you now can reach with the url: http://mydomain.com/find-data /results/index/texas/green/

What I don’t understand is that you are saying that it’s not content data. If that’s true, this is not what you want, and then you shouldn’t even involve EPiServer MVC in this.

Routing with plain MVC, not EPiServer

In this case, you should add a route like: RouteTable.Routes.MapContentRoute(name: "FindData", url: "find-data/results/{action}/{state}/{color}/", defaults: new { controller = “interior”, action = "index" });

Now, you cannot use the PageController<T> base class, because you haven’t specified that any content from EPiServer should be loaded. If you want that, you need to use the {node} in the pattern. Now you can use the url http://mydomain.com/find-data /results/index/texas/green/ which will go to the controller “interior” that cannot use PageController as base class. Base class should be “Controller” here. Now you can have two inparameters, state and color:

Public class InteriorController : Controller

{

Public ActionResult Index(string state, string color)

{

}

}

Something in between

Maby you want something in between those alternatives, like http://mydomain.com/find-data /results/MYPAGE/index/texas/green/. Now you can create a page called MYPAGE and register a route like: RouteTable.Routes.MapContentRoute(name: "FindData", url: " find-data/results /{node}/{action}/{state}/{color}/", defaults: new { action = "index" });

Your controller can now look like (InteriorPage must inherit from PageData):

Public class InteriorController : PageController<InteriorPage>

{

Public ActionResult Index(InteriorPage currentPage, string state, string color)

{

}

}

Summarising

I need more info of what you are trying to do. I’m very confused about the code you posted.

Regards, Jonas

#65920
Feb 14, 2013 10:12
This thread is locked and should be used for reference only. Please use the Episerver CMS 7 and earlier versions forum to open new discussions.