I feel like I'm re-inventing the wheel here, but I need to find a way of taking a URL from a catchall,and redirecting that to another route.
The reason for this is because I need to do some things like adding session cookies for certain urls, and then pass them on to their relevant action.
What's the best way of implementing this?
Thanks in advance for any help!
You can try changing the master page at runtime. It's not the most beautiful solution though.
Theming Support
If I understand question...
Looking at your previous question (redirect-to-controller-but-with-a-different-master-using-a-catchall-wildcard) you want to take the wildcard from:
routes.MapRoute(
"Partner",
"partners/{partner}/{*wildcard}",
new { controller = "Partners", action = "PartnerRedirect" }
);
And in the Partners/PartnerRedirect action, send it to the right controller/action specified in the wildcard?
I have no idea the best way to do this, but looking at ways to unit test url routing brought up this:
http://weblogs.asp.net/stephenwalther/archive/2008/07/02/asp-net-mvc-tip-13-unit-test-your-custom-routes.aspx
I'm not sure if it is an exact fit (ie. might not have to mock stuff), but it looks like all the data is returned from GetRouteData to pass to RedirectToAction method.
Oh, so you don't want a redirect? You want the URL to stay:
mysite.com/partners/pepsi/products/cola.htm
but serve up:
mysite.com/products/cola.htm
I don't have MVC at home, but couldn't you instead define your route differently?
Instead of:
routes.MapRoute(
"Partner",
"partners/{partner}/{*wildcard}",
new { controller = "Partners", action = "PartnerRedirect" }
);
do:
routes.MapRoute(
"Partner",
"partners/{partner}/{controller}/{action}/{other stuff you need}",
new { /* whatever defaults you want */ }
);
The action now has the partner variable to do whatever with, and you could add route constraints to partner so only valid ones match.
(I think) you could then use an action filter on your actions/controllers to do appropriate action based on the partner paramter (it should be in httpcontext of the filter, again I think!) so that you don't have to repeat code in every action if you want to do some basic checks/actions on partner.
Here is a decent write up on a lot of ways to skin that cat:
http://weblogs.asp.net/stephenwalther/archive/2008/08/12/asp-net-mvc-tip-31-passing-data-to-master-pages-and-user-controls.aspx
No, it is effectively a redirect, but the redirect is not visible to the user (in much the same way as a Server.Transfer() is done in Web Forms.
The link you pointed at only uses one master page, whereas I have many master pages (close to 200).
I have thought of having separate route handlers for these partners, but the master page choice came into the equation.
I think I'm going to have to create a ViewExtension to overcome these problems...
Related
I'm digging into ASP.NET MVC from classic asp, and have completed some tutorials. I understand the concept now, but I have a main question about the controller. How are you able to control the url structure if you are getting your url's (with params) from a sql database?
Example: /custom-url-1 or /custom-url-23423411
(Returns params accordingly to feed the code)
I'm guessing it would have to do with ActionResult Index() , but not sure where to go after that. Any idea's where to look or is this even possible? Does MVC even allow this?
One Way you can approach this is to have everything go to one action in one controller and resolve the content in the view.
This is useful only if you have one type of view.
Second way is to have route constraint or a custom route constraint for each type of content you have
say : Galleries, Blog, Pages
and in each constraint check if the given url is of this type ( by db call), if the constraint returns true, it will point the request to the given controller and action.
The third way is to have a custom route handler that does the checking and routing (mind you this is probably the hardest task but works best if you have complex system, if your is simple try using method 1 or 2
P.S. if you want your urls separataed by "-" instead of "/" you can do just this
routes.MapRoute(
"Default", // Route name
"{controller}-{action}-{id}",// URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
i'd like to forward a request to a controller to some specific action without redirecting to another url.
so, for example, the following url:
/home/peter
should internally become
/home/people/peter
i know i could catch the action name ('peter') in the 'init' function, then do a Controller::redirect, but i'd like to stay on the same url, just have the request internally forwarded to the 'people' action.
2 things to note:
'peter' is a dynamic string, so i can't just hardcode a route for this
any other action of the controller shall still work, so only a couple of strings should get forwared (eg. 'peter', 'ann' get forwarded to the 'people' action, whereas 'otherAction' is still callable)
i already found the 'handleAction' and 'handleRequest' methods in the Controller class, but just can't imagine how make use of them for my task.
SilverStripe version: 3.0.3
I suggest the use of static $url_handlers described here, that allows you to define specific routes to actions. Your use case could be achieved by using a catch-all url-handler.
But therefore we have to pay attention to the order of each route. The catch-all route has to be defined at the end. All other actions need a seperate url handler before:
public static $url_handlers = array(
'otherAction' => 'otherAction',
// ...
'people/$Name' => 'people',
'$Name' => 'people' // catch-all
);
This should fit to your explanation. The last route catches all dynamic routes which weren't handled before.
But as Ingo mentioned, both routes would deliver the same content and that could be bad for SEO. You could target the second route people/$Name to a different action which does a 301 redirect to the url with $Name only. I would recommend this if you already have public content and you want to replace the existing URLs with the short version.
I hope this solves your problem (temporarily).
First of all, I assume you have good reasons for making duplicate URLs (bad for SEO) :)
I've tried around a bit with Director::direct(), which would be the cleanest, but didn't get anywhere. Director::test() resets most request state, so doesn't qualify either.
Calling handleRequest() or handleAction() on a new controller instance is tricky, because the Director has built up a lot of state by that time already (for example pushed to the controller stack).
So, unfortunately the SilverStripe routing isn't that flexible, anything you do will go deep into system internals, and potentially break with the next release.
I have a controller that creates a news article. I want to redirect the user to the article's page, something like: "/article/1". Normally I could just throw in return View("MyAction") but I need to pass the integer along in this case. There are overloads for adding a model to the View method call but I don't see anything that will let me accomplish my goal.
What's the best way to do this?
Also, I used ViewData for my success message... if I use a redirect message it isn't going to function so is there a better way to do that too?
I think this is what you might be looking for.
RedirectToAction(new {controller="controllerName", action="article", id=1});
Hope this helps
now this is probably an stupid question but i'm new to mvc and can't seem to get it working.
Here is what i would like to be able to do with the urls/routes:
1) www.domain.com/name/home/index
2) www.domain.com/home/index
where both the home controllers are seperate controllers and the name part will very but all must go to the same controller and the name should be an param for all the actions in there.
Is this at all possible? Thanks for your help.
This might not be the answer you're looking for, but I think that it would be more usual to see
www.domain.com/home/index
www.domain.com/home/index/name
My initial thinking was that an overloaded Index action method would make sense, but Daniel pointed out that this not allowed (at least not in the manner I suggested).
Updated answer...
Your Index action method could take a string name argument, and your routes would need to contain something like
routes.MapRoute(
"Default",
"{controller}/{action}/{name}",
new { controller = "Home", action = "Index", name = "" }
In your action method a quick null check will tell you whether a name was included in the URL or not.
I would like to create routing rules like the following:
www.app.com/project/35/search/89/edit/48 ---> action is edit in the project controller
The passed variables should be project# (35), search# (89), and edit#(48)
Can someone help me structure a routes.MapRout() for this.
I want to use:
routes.MapRoute(
"Default",
"{controller}/{projectid}/search/{searchid}/{action}/{actionid}",
new { controller = "Home", action = "Edit", projectid = "", actionid = "" }
);
But from previous experience, this type of MapRoute will fail... I've only gotten something in the following format to work:
{controller}/{action}/{variable}
Can anyone give me any advice on this? Thanks.
Honestly, it sounds like you need to make you URL's look like this:
www.app.com/project/35?search=89&edit=48&flag=63
It would make your like much simpler.
Grouping Controllers with ASP.NET MVC
A question that often comes up is how do you group controllers when building a large application with ASP.NET MVC. Often, the question is phrased as whether or not ASP.NET MVC supports “Areas”, a feature of Monorail. According to the Monorail documentation,
MonoRail supports the concept of areas, which are logical groups of controllers. All controllers belong to an area. The default area is an empty (unnamed) one
While there’s no out of the box support for this in ASP.NET MVC, the extensibility model allows building something pretty close.
Registering Routes
The first thing we do is call two new extension methods I wrote to register routes for the areas. This call is made in the RegisterRoutes method in Global.asax.cs.
routes.MapAreas("{controller}/{action}/{id}",
"AreasDemo",
new[]{ "Blogs", "Forums" });
routes.MapRootArea("{controller}/{action}/{id}",
"AreasDemo",
new { controller = "Home", action = "Index", id = "" });The first argument to the MapAreas method is the Routing URL pattern you know and love. We will prepend an area to that URL. The second argument is a root namespace. By convention, we will append “.Areas.AreaName.Controllers” to the provided root namespace and use that as the namespace in which we lookup controller types.
http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx
Why did this format fail for you? What do you mean by "failed"? If it just didn't work, try placing your new MapRoute above the default commands - the Routes collection is working in a FIFO manner.
#Robert Harvey - Take a look at Basecamp for example - they are using a very similar approach in their URI's. I think it's a much cleaner and better approach than what you're suggesting. It's not even "Simpler" once you get the hang of routing.