Based on my SEO team's recommendation i am trying to generate SEO friendly urls. For some static pages i have done that easily using RouteCollection.MapRoute() like -
//Home/Solutions
routes.MapRoute("Solutions", "Solutions", new { controller = "Home", action = "Solutions" }, new[] { "MyAuction.Controllers" });
//Home/SolutionOfferings
routes.MapRoute("Offerings", "Offerings", new { controller = "Home", action = "SolutionOfferings" }, new[] { "MyAuction.Controllers" });
//Home/Pricing
routes.MapRoute("Pricing", "Pricing", new { controller = "Home", action = "Pricing" }, new[] { "MyAuction.Controllers" });
I was then trying to generate SEO friendly routes for my dynamic routes. For example there are several auctions scheduled for a day which contains hundreds of vehicles scheduled within the auction. To show details of that scheduled vehicle within the auction the actual URL is somewhat -
http://example.com/Auction/VehicleDetails?AuctionId=42&VehicleId=101
Please note that VehicleId represents the Identity within AuctionVehicles table which also contains other details of the vehicle like Make, Model, Year and VIN etc.
What i want to achieve is to generate a dynamic URL like -
http://example.com/42/honda-civic-2010-123456
where 42 is the auction id while honda is the make, civic is the model, 2010 is the year and 123456 is the last 6 digits of the VIN number.
Not sure how to achieve this.
I tried using this link -
Dynamic Routes from database for ASP.NET MVC CMS
Any help would be greatly appreciated.
Routing is one of the most difficult things to grasp in mvc. The best way i have found is MVC attribute routings in ASP.NET MVC 5. (P.s. i'm typing on a phone)
you simply include this line in your RouteConfig
routes.MapMvcAttributeRoutes();
And then you can set optional parameters and default values and map urls in your actual controllers like this:
[Route("books/{bookName?}")]
public ActionResult View(string bookName)
{
if (!String.IsNullOrEmpty(bookName)
{
return View("OneBooks"), GetBooks(bookName));
}
return View("AllBooks"), GetBooks());
}
Your url will look like www.example.com/books/jungle-book
there are many more things you can do. Please read the following article:
https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/
I also found this links and the sublinks on this page to be helpfull to get a proper understanding of mvc routing (lots of reading!!):
https://www.codeproject.com/Articles/641783/Customizing-Routes-in-ASP-NET-MVC
As I said I think attribute routing is your best bet!
Related
I need to build a CMS like website.
I have a Backend (admin website) where users can create or update pages for the Frontend (it will be 2 differents websites but both are .Net Core 6 MVC)
I've already done that with Asp.Net MVC by directly manipulating the RouteCollection of the Front. The Backend was calling an action on the Front that was creating/updating the needed route for the purpose of url rewriting)
Here how I define Route url of all Pages in Front :
var pages = _pageService.GetAll();
foreach (CmsPage page in pages)
{
routeCollection.MapRoute(
name: $"page-{page.PageId}",
url: page.url,
defaults: new
{
controller = "PageController",
action = "Detail",
id = page.PageId,
}
);
}
This way, in Razor, I can easily list all page's link like this :
#foreach (CmsPage page in Pages)
{
#page.Title
}
If Users in Backend want to change the slug of a Page, the Backend call the Front so he can change the needed entry in the RouteCollection and update the slug :
protected void UpdateRouteFromRouteTable(string routeName, string newUrl)
{
// Get the route by name
var route = RouteTable.Routes[routeName];
using (RouteTable.Routes.GetWriteLock())
{
((Route)(route)).Url = newUrl;
}
}
By doing this the slug of the page is updated on the Front.
THIS is no more possible in .Net Core (can't access routeTable) but I need to achieve the same goal maybe with some kind of dynamics routing.
Where should I look ? I read about DynamicRouteValueTransformer but it doesn't seems to be what I'm looking for, neither seems to be Microsoft.AspNetCore.Rewrite.RewriteContext...
Any hints ?
Thx a lot
Working on a MVC Application that basically is a front end database of my City's listings/Directory.
Registered Listings are called like the following:
something.com/Listings/View/{some-guid}
Is it possible to display in this format:
something.com/{slug version of the destination name}
or
something.com/kfc-arabia
This would be of great ease to share the links with clients, also SEO Friendly.
I think it would be difficult to match your slug at the root of your application as this would not allow for other routes in your application. However if you can achieve something like what you want by doing the following
something.com/directory/{slug}
With this you would just need a simply rule to match this to a suitable action that takes your slug as a parameter.
e.g.
context.MapRoute("Listings_by_slug",
"directory/{slug}",
new { controller = "Listings",
action = "ViewBySlug" });
and your action would be something like this
public ActionResult ViewBySlug(string slug){
var listingGuid = _service.GetGuidFromSlug(slug);
return RedirectToAction("View", "Listing", new { id = listingGuid);
}
UPDATE
If you really want that then you could have a route like
context.MapRoute("Listings_by_slug",
"{slug}",
new { controller = "Listings",
action = "ViewBySlug" });
You'd want to put this after other routes you need as this route matches anything to your application. In effect it should be your last declared route. Also you could not have a controlller with the same name as a slug
I have a Controller with the name "Hem" and Action name is "Om".
And default language i have set Swedish.
So route will be on Swedish site, it's
/sv/Hem/Om
Now I want to change language to "en" by clicking English in language section.
So route will be set automatically like this way :
/en/Home/About
But functionality should be work of /sv/Hem/Om and In address bar should be display as /en/Home/About
Experts can you please help me out.
You can do this way.
routes.MapRoute(
"English route",
"en/{controller}/{action}/{id}"
new { controller = "Home", action = "Index", language = "en" },
);
routes.MapRoute(
"FrenchHome",
"/sv/Hem/Om",
new { controller = "Home", action = "Index", language = "fr" }
);
or you can do that way:
public class GenericRoutes
{
public string Controller {get;set;}
public string Action {get;set;}
public string Url{get;set;}
public string RouteName{get;set;}
}
public List<GenericRoutes> Routes = new List<GenericRoutes>();
Routes.Add(new GenericRoutes{Cotroller="bl",Action="cl",Url="bl/cl"})
for(int i=0;i<Routes.count();i++)
{
routes.MapRoute(
Routes[i].RouteName,
Routes[i].Url,
new { controller = Routes[i].Controller, action = Routes[i].Action },
);
}
I personally would avoid this approach for multilingual sites. Yes it is technically possible to do what you are asking but most sites do not handle multiple languages in this way. ASP.net has had ability to localize pages for a long time and I would recommend this approach instead.
Localization involves putting resource keys in your view template instead of hard coding your strings. Then you would set the culture of your thread, usually by the http accept-language header and the site would chose the appropriate strings for that culture to put into the page view. The only thing you need to maintain then is sets of strings for each language.
The benefit for this approach is that you write your views only once. When you have 2 or even 3 sets of views you run the risk of having those versions of your site diverge. I personally have seen this happen and its a hard problem to get back from. Also you get to separate your "language problem" from whatever problem your website is solving, meaning your domain isn't cluttered with boilerplate code to maintain a fancy language switching technique, instead of going with the solution that's included with the platform.
If you are interested in doing multi-language sites in .net the right way I would recommend learning about Localization and Globalization, here is a good place to start :)
Beginners Tutorial
Scott Hanselman tutorial - MVC 3 + Jquery version
First of all, I am not an expert. But in order to route user to different controller you can implement custom routing and configure routes dynamically.
To understand how routing works you may consider checking this link out.
Here is a quick trick to do that:
Here is RegisterRoutes method which register all routes for application
public static void RegisterRoutes(RouteCollection routes)
{}
now get current language from url(get first segment of url (en in your case))
query your data source for current language
add your routes here from database or any other source using foreach.
.
foreach (var route in RouteValues)
{
route.UniqueName,
routes.MapRoute("prefix/{controller}/{action}/{id},
new { controller = route.Controller , action = route.Action , id = route.Id });
}
I am using ASP.Net web form Routing for my website but i want to make it more structure & hide all the Querystring ID's with proper Structure like Language/Category/PageName-Title
example: www.abc.com/en/sports/cricket-world-cup
but with my current routing technique i am able to make it work as
www.abc.com/en/1/13/cricket-world-cup
domain/english-folder/language-id/page-id/page-title
How can i make it more structured as `www.abc.com/en/sports/cricket-world-cup
Since i have few Query-string i designed it this way
//For Page.aspx
routes.MapPageRoute("Page_Route", "en/page/{LID}/{PID}/{PageName}", "~/en/Page.aspx", false,
new RouteValueDictionary {
{ "LID", "0"},
{ "PID", "0" },
{ "PageName", "Page-not-found" }},
new RouteValueDictionary {
{ "LID", "[0-9]{1,8}" },
{ "PID", "[0-9]{1,8}" },
});
Result of above Routing get me Friendly URL like this
www.abc.com/en/1/13/cricket-world-cup
But i want to further structure the URL like the one in example.
www.abc.com/en/sports/cricket-world-cup
Example: This url i found is more structure/
http://www.thenational.ae/news/world/europe/turkey-providing-jobs-a-future-for-more-greeks
How can i implement the same structure are they passing querystrings as hiddenfields. Please suggest best approach for such url.
another example is http://mashreqbank.com/uae/en/corporate/lending/trade-finance.aspx
they are using asp.net but i am not sure if it is ASP.Net MVC or ASP.Net webform.
I have been struggling with this kind of routing for quite long and even i cant find a complete example which can take into consideration more than one query-string as most of the example are based on one query-string.
Any help from coding gurus with example would be highly appreciated.
UPDATE:
Let us take this Table into consideration which i use to store page name, title, handler, language regions etc.. This is just a demo table & doesnt resemble the actual website which i am refering to for sample structured url. I am not even sure if they are going it using URL routing or these are actual physical folder & files like old style website where you create actual folder and place files in their etc..
Page_ID Page_Name Page_Title Page_Handler Parent_Page_ID Language_ID Region_ID
1 Home Home index.aspx 0 1 uae
2 Personal Personal index.aspx 0 1 uae
3 Accounts & Deposits Accounts & Deposits index.aspx 2 1 uae
4 Current Account Current Account current-account.aspx 3 1 uae
5 Current Gold Accounts gold Account gold-account.aspx 3 1 uae
6 Easy Saver Easy Saver Account saver-account.aspx 3 1 uae
7 Fixed Deposits Fixed Account fixed-account.aspx 3 1 uae
8 Loans Loans index.aspx 2 1 uae
9 Personal Loans Personal Loans index.aspx 8 1 uae
10 car Loans car Loans car-loan.aspx 8 1 uae
website example for above structure http://mashreqbank.com/
We can use a common page handler if the page design is same this is what i am assuming let us say page.aspx,
Pleae feel to make changes to structure and data inorder to achieve the desired result.
You could simply have something like:
routes.MapPageRoute(
"article-route",
"en/{category}/{pageName}",
"~/en/page.aspx");
And then on en/page.aspx you can access the category and pageName, assuming you have a query to find the correct article based on those two variables:
string category = Page.RouteData.Values["category"] as string;
string pageName = Page.RouteData.Values["pageName"] as string;
Though, if you can't identify a page simply by category and pageName (which seems true per your updated question), you may need the id in the route. In this case, you can ignore the category and pageName route values as they are only there for a nice-looking URL. The only parameter we care about is the id since that is how you identify an article. For example, here are three examples of various routes
routes.MapPageRoute(
"uae-route",
"uae/en/{category}/{id}/{pageName}",
"~/en/index.aspx");
routes.MapPageRoute(
"gbr-route",
"gbr/en/{category}/{id}/{pageName}",
"~/en/index.aspx");
routes.MapPageRoute(
"account-route",
"en/{id}/{pageName}",
"~/en/current-account.aspx");
//then on en/index.aspx and current-account.aspx
int pageId= 0;
if (Int32.TryParse(Page.RouteData.Values["id"] as string, out pageId)) {
// get the page details (including parent page id and language id if needed)
// where Page_ID=pageId.
}
From the sounds of it though, you want to do the first example above, meaning you'll need a way to pull articles by simply category and pageName and not any type of id.
UPDATE: You don't need to create a route for each path... that's the whole point of routing. If you have multiple handlers, then you'll at least need a path for each handler (.aspx page).
It'd be easiest to use an id in the URL, because according to your data structure, that is the only way to identify the page you want to pull. So let's use your example, using these routes:
www.abc.com/en/personal
www.abc.com/en/personal/acounts-deposits/
www.abc.com/en/personal/acounts-deposits/current-account
www.abc.com/en/personal/acounts-deposits/current-gold-account
www.abc.com/en/personal/acounts-deposits/easy-saver
You have one route:
routes.MapPageRoute(
"personal_route",
"en/personal/{category}/{pageName}",
"~/personal.aspx",
false,
new RouteValueDictionary { { "category", string.Empty }, {"pageName", string.Empty}}); //allow for no values
And the personal.aspx has the following code:
protected void Page_Load(object sender, EventArgs e)
{
string category = Page.RouteData.Values["category"] as string;
string pageName = Page.RouteData.Values["pageName"] as string;
if (String.IsNullOrEmpty(category)) {
//no category... must be the /personal route. handle that
}
else if (String.IsNullOrEmpty(pageName)) {
//no page name, just load the category page content
//Psuedo query against your non-existant data schema
//SELECT * FROM SiteContent WHERE Page_Handler='Personal' AND Page_Category=category && Page_URL=""
}
else {
//SELECT * FROM SiteContent WHERE Page_Handler='Personal' AND Page_Category=category && Page_URL=pageName
}
}
As you can see, your problem is you have no way to identify pages without the IDs. You'd need to replace all those IDs in your table with unique URLs. It's doable.
I have the basic Master / Detail Views working great with the default ASP.NET MVC Route; however I would like to build some URLs like this:
/Class/Details/5 -- General Detail view [Working]
What I'm not sure about (and I'm not tied to this URL format, just something roughly equalivent.)
/Class/5/Details/Logs -- Detail View with Logs
/Class/5/Details/Status -- Detail View with current Status
Another way to put this, is like this:
/{controller}/{id}/{controllerSpecificMaster}/{action}/
What I'm trying to avoid, is cluttering up my Views\Class directory with a bunch of Views, which are all basically derivatives of the Details view.
I'm on ASP.NET MVC 1 and .NET 3.5 SP1.
The first thing you need to get down are your routes. You may have already done this, but in case you haven't, here's a route entry that will handle your custom route needs:
routes.MapRoute("Master_Detail",
"{controller}/{id}/{controllerSpecificMaster}/{action}",
new { controller = "Class",
action = "Index",
id = UrlParameter.Optional,
controllerSpecificMaster = "Details"
});
Then, in your action methods where you want to use the route-specified master page, just include the route key in your method arguments, and then pass it to the view:
public ActionResult Logs(int id, string controllerSpecificMaster)
{
//do something
//return view with master name as argument
return View("Logs", controllerSpecificMaster);
}
If you have to do this a lot, I would suggest creating a custom view engine and override the FindView() method.