ASP.NET MVC Routing - Thousands of URL's - performance

My ecommerce application stores URL's for item pages in the database. There are thousands of these URL's, which are all root level (i.e. domain-name.com/{item-page-url}).
If I add all of these URL's to the route table by using a simple for loop to call RouteCollection.MapRoute for each URL site performance degrades exponentially. Why? The reason for this is here.
How should I properly handle this situation? Adding all of the routes to the route table doesn't seem right (not to mention the performance pretty much confirms that). I've seen a few ideas about inspecting all incoming URL's and then trying to match that to the URL's in the database but don't fully understand how I'd implement that, nor am I sure if it's the best approach.
Any ideas or suggestions? This seems like it would be not so uncommon, but I haven't found a concrete way to handle it.

If you can change your route to
mycreativeshop.com/product/my-product-name then adding following route to the top of your route config file can help you.
routes.MapRoute(
"CustomRouteProduct",
"product/{id}",
new { controller = "yourcontrollername", action = "Index" }
);
and in the action map the parameter value with name of your product name
public ActionResult Index(string id)
{
//var prdName = id.Replace("-", " ");
//look up prdName in database
return View();
}
Update
Added following as a top route
routes.MapRoute(
"CustomRouteProductZX",
"{id}",
new { controller = "Content", action = "Index" }
);
and by accessing http://localhost:12025/Car-Paint I was directed to Index action of ContentController where I accessed "Car-Paint" in parameter id
But, above having above blocks patterns like http://localhost:12025/Home/ (here Home is also treated as a product)

Related

Dynamic Controllers in CodeIgniter

I am in the process of creating a new website which loads all master and child categories from the database. I have tested the navigation as well, i.e., if I click any master category, it perfectly loads all the respective child categories without any issue. However, at present, I am doing this by passing query string in the URL. For instance
http://localhost/MyController?id=32145
Let's assume that the id, 32145, represents a master category namely 'About us'. My question is how can I change the above URL to something like:
http://localhost/Aboutus
and if there is any child category under About us than it should display as:
http://localhost/Aboutus/Mission
Please help me out as I am really stuck with this problem.
by default CodeIgniter uses a segment-based approach, you can do URL routing in way like your second part of the question - "and if there is any child category under About us"
$route['product/(:any)'] = "catalog/product_lookup";
more here: https://ellislab.com/codeigniter/user-guide/general/routing.html
but if you want to rewrite complete URL than you should probably check .htaccess rewriting
It is not easy, do once for migration.
In database you can store the New controller/url for products (if it is not have yet)
Create new Controllers
Route controller which redirect the old Url to the New Url
controllers
Route old urls to Route controller
Route controller something like this:
public function old_url($aProdId) {
if (is_null($aProdId)) {
// error cannot be null
}
$NewUrl = $this->new_url_model->getNewUrl($aProdId);
if (!$NewUrl) {
// error new url not exist
return;
}
redirect(base_url($NewUrl), 'refresh');
}

MVC 3 - multiple controllers or controller with multiple actions plus routing

I'm putting together a simple enough brochure site and decided to use MVC3 as a learning opportunity. Content of certain sections of the website will be stored in a DB and can be updated by an admin via a simple GUI. I decided not to use a prebuilt CMS again to learn how to do database operations in this language which is new to me.
I want a very simple URL structure:
foo.com (home)
foo.com/bio
foo.com/news
foo.com/about
foo.com/events
etc
The straightforward way to achieve that is to have a controller for each page, and use the Index() ActionResult of each controller.
Is it OK / best practice to have a controller for each of these pages of the site? News and Events won't have subpages, but might have paging, with the URL looking something like
foo.com/news/
foo.com/news/page2
foo.com/news/page3
foo.com/news/page4
If I had a single controller, and used multiple actions, the URLs by default look like
foo.com (home)
foo.com/home/bio
foo.com/home/news
foo.com/home/about
foo.com/home/events
Which would then have me updating the routing to achieve what I want.
With respect to the use of controllers, I think the best practice is to have a particular controller for a domain of action or domain of content, not by the hierarchy of your main menu.
For example:
Your main page:
foo.com
Controller -> Home
Method -> Index
Parameter -> null
foo.com/news/2
Controller -> news
Method -> Index
Parameter -> 2
But Home and News are two different "equal" controllers, it just happens that the first controller the user interacts with is the Home controller.
In the case you want to use a single controller, you might try,
routes.MapRoute(
name: "Default",
url: "{action}/{page}",
defaults: new { controller = "Home", action = "Index", page = UrlParameter.Optional },
constraints: new { page = new PagingConstraint() }
);
as route defination. And to only allow paging for "news" and "events", use a custom route constraint as,
public class PagingConstraint : IRouteConstraint
{
private static readonly string[] PagingEnabledActions = new string[] { "news", "events" };
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return string.IsNullOrEmpty(values[parameterName].ToString()) || new Regex(#"^[Pp][Aa][Gg][Ee][0-9]+$", RegexOptions.Compiled).IsMatch(values[parameterName].ToString())
&& PagingEnabledActions.Contains(values["action"].ToString().ToLower());
}
}
Hope this helps.

How can I specify the name of the controller in ASP.NET Web API?

I have an ApiController, quite simple, like this:
public class AssetController : ApiController
{
// removed for brevity
}
When I insert a route to it from a view, the url created is something like:
http://host/Asset
but I would like to customize the name, so that it becomes this:
http://host/assets
How can I specify a custom name for my controller, without resorting to a complete custom routing table?
When I insert a route to it from a view, the url created is something like: http://host/Asset
You haven't really shown how you are doing this inserting but the following should work fine:
#Url.RouteUrl("DefaultApi", new { httproute = "false", controller = "assets" })
and if you want an absolute url you could specify the protocol scheme as third argument:
#Url.RouteUrl("DefaultApi", new { httproute = "false", controller = "assets" }, "http")
And in order to obey RESTFul conventions you should rename your controller to AssetsController.
I'd recommend looking at the https://github.com/mccalltd/AttributeRouting library. It handles this aspect quite well by putting an attribute right on each function and giving it a specific route (which can be anything).
I've had to resolve this issue so I've opted to adjust my routing table to reflect the API that I really want.

MVC3 MapRoute to convert aspx query params into the route

I'm working on a project to rewrite an aspx site as MVC3. I want to make the old URLs work on the new site. I have named my controllers and actions such that the URLs actually contain enough info in the query string to route correctly but I'm having trouble getting the routing to work since it doesn't like the ? in the URL.
Basically I have old URLs like this:
www.example.com/Something/SomethingElse/MyPage.aspx?Section=DetailSection&TaskId=abcdef
I tried to create a route using:
routes.MapRoute(
"OldSite",
"Something/SomethingElse/MyPage.aspx?Section={action}Section&Id={id}",
new { controller = "Task", action = "Index", id = UrlParameter.Optional }
);
I want it to route to the correct new URL which is:
www.example.com/Task/Detail/abcdef
I know that all traffic to the MyPage.aspx page should go to my new Task controller and the beginning of the Section parameter always matches one of a few corresponding actions on that controller.
Unfortunately I have found that I get an error that a route can't contain a question marks. How should I handle this? Would it be better to use URL rewriting? Because this is a private site I'm not concerned with returning permanent redirects or anything - no search engine will have links to the site anyway. I just want to make sure that customers that have a URL in an old email will get to the right page in the new site.
In this one case I think the simplest way would be to have your old page mapped to a route:
routes.MapRoute(
"MyPage",
"Something/SomethingElse/MyPage.aspx",
new { controller = "Task", action = "MyPageHandler" }
);
And have this route mapped to an action method in TaskController:
public ActionResult MyPageHandler(string section, string taskId)
{
if (section.Contains("Detail"))
{
// execute section
}
}
This way you're treating your old site's query string for what it is: a query string. Passing those parameters straight into an action method is the most MVC-y way to interpret your old site.

Delete Action not working MVC 3

Route I have defined is:
map.Route(new Route("Cars/{id}/Delete",
new RouteValueDictionary(new { controller = "Car", action = "Delete"}),
new MvcRouteHandler()));
In my view I've got:
Delete
Which when run tries to send a request to http://oursite/Car/122/Delete
My delete action in this Car controller looks like this:
public ActionResult Delete(int id)
{
//code is here
}
I noticed a couple things:
If I run this same code locally via my PC, the delete works flawlessly and is able to get to my action method. I'm running this over IIS 7 / Win 7
On our dev server, it's setup obviously via IIS7 but this route fails and says it can't find the route on our route table. But this is the SAME route table class I am using locally...so why would I get this:
No route in the route table matches the supplied values.
But why would that not work on a dev server? I see the setup identical in IIS for the most part as far as I can see when I compare my local setup to the server's.
I noticed that also whether localhost or server, if I try and put an [HttpDelete] attribute on my delete action, it doesn't find my action method and I get an error saying it can't find that method. So not sure why when I take that off, the delete works (localhost only)
Use a helper to generate your link:
#Html.ActionLink("Delete", "Delete", "Car");
The first parameter is your link text, the second is your Action method name, and the third is your Controller name.
See this MSDN Reference on ActionLink().
Could you please share code for the View. How do you build the 'a' tag in the view?
Regarding the [HttpDelete] attribute, it means that the method needs the HTTP 'DELETE' request. The 'a' tag always has a GET request.
Please refer this link
I think you answered your own question. There is no route in the route table that matches your supplied values. You could write that route to do that by writing this in your Global.asax.cs file:
public class Global : System.Web.HttpApplication
{
protected void Application_Start()
{
// Specify routes
RouteTable.Routes.Add(new Route
{
Url = "[controller]/[id]/[action]",
Default = new { controller = "Car" },
RouterHandler = typeof(MvcRouteHandler)
});
}
}
Or, you can use existing routes (my personal recommendation) to use the Delete function in your Car controller. To do that, try switching your code to this:
Delete
First name that route
map.Route("DeleteCar",new Route("Cars/{id}/Delete",
new RouteValueDictionary(new { controller = "Car", action = "Delete"}),
new MvcRouteHandler()));
Then
Delete
Unless that link goes to a warning screen, I strongly suggest that a delete should be a POST or even a DELETE(I think it can be set via ajax)
There's likely a difference in the URL paths between localhost and oursite. The path "/Car/#Model.Id/Delete" is hard-coded, not resolved and may not work in all environments. As suggested in other answers, use an MVC helper like #Html.ActionLink or #Url.RouteUrl to resolve the path for the local environment.

Resources