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 });
}
Related
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
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!
TL;DR
I need a way to programtically choose which RoutePrefix is chosen when generating URLs based on the properties of a user in my MVC app
Not TL;DR
I have an MVC 4 app (with the AttributeRouting NuGet package)
Due to the requirements of the hosting environment I have to have two routes for a lot of my actions so that the hosting environment can have different permissions for access.
I am solving this by decorating my controller with with [RoutePrefix("full")] [RoutePrefix("lite)]. which allows each action method to be accessed via /full/{action} and /lite/{action}.
This works perfectly.
[RoutePrefix("full")]
[RoutePrefix("lite")]
public class ResultsController : BaseController
{
// Can be accessed via /full/results/your-results and /lite/results/your-results and
[Route("results/your-results")]
public async Task<ActionResult> All()
{
}
}
However, each user should only use either full or lite in their urls, which is determined by some properties of that user.
Obviously when I use RedirectToAction() or #Html.ActionLink() it will just choose the first available route and won't keep the "correct" prefix.
I figured I can override the RedirectToAction() method as well as add my own version of #Html.ActionLink() methods.
This will work, but it will involve some nasty code for me to generate the URLs because all I get is a string representing the action and controllers, but not the reflected types. Also there might be route attributes such as in my example, so I am going to have to replicated a lot of MVCs built in code.
Is there a better solution to the problem I am trying to solve?
How about something like:
[RoutePrefix("{version:regex(^full|lite$)}")]
Then, when you create your links:
#Url.RouteUrl("SomeRoute", new { version = "full" })
Or
#Url.RouteUrl("SomeRoute", new { version = "lite" })
You could even do the following to just keep whatever was already set:
#Url.RouteUrl("SomeRoute", new { version = Request["version"] })
I ended up finding a solution to this
I just overrided the default routes to include this. ASP.Net automatically keeps the usertype value and puts it back in when it regenerates the routes
const string userTypeRegex = "^(full|lite)$";
routes.Add("Default", new Route("{usertype}/{controller}/{action}/{id}",
new { controller = "Sessions", action = "Login", id = UrlParameter.Optional }, new { usertype = userTypeRegex }));
I found that this didn't work with the Route or RoutePrefix attributes, and so I had to remove all of them. Forcing me to add specific routes in these cases
routes.Add("Profile-Simple", new Route("{usertype}/profile/simple",
new { controller = "ProfileSimple", action = "Index" }, new { usertype = userTypeRegex }));
I thought that a half-dozen hard coded routes in my RouteConfig file was a better solution than having to manually add values to each place I generated a URL (as in Chris's solution).
How can I implement solution, where language switcher won't be consisted on session variables or xyz.com/{language} parameters in URL (I have that approach now).
Just en.XYZ.com/Account/Login or for example de.XYZ.com/SomeController/SomeAction (subdomain switch the language variable - that is more friendly for SEO)
How to implement it?
is there any reason why you are using the session variable? a more common solution is to include the language code in the route, i.e. blah.com/en/info or blah.com/jp/info (for english and japanese)
if you did this every page on the site could contain links to each language. if you are writing a publicly accessible site this would also make it easier for google to index all your content.
this article explains how to include the language in the domain, ie. en.blah.com or jp.blah.com: http://blog.maartenballiauw.be/post/2009/05/20/ASPNET-MVC-Domain-Routing.aspx
UPDATED: Here's a simple example of including the language code in the URL route.
Change the default route to include a language parameter:
routes.MapRoute(
"Default",
"{language}/{controller}/{action}/{id}",
new { language = "en", controller = "Home", action = "Index", id = "" }
);
Add links for each language to your masterpage:
<li>#Html.ActionLink(
"Spanish",
ViewContext.RouteData.Values["action"].ToString(),
new { language = "es" })</li>
These will render as links back to the page you are on - only with the language changed.
I've got an ASP.NET MVC app that's working nicely with a handful of controllers, e.g. "Home", "Services" and "Go". The "Go" controller is where all the content is.
Now the marketing folks have come and said they don't want to see the word "go" in the URL. In other words, instead of:
http://mydomain.com/go/geography/africa
they want to have:
http://mydomain.com/geography/africa
I cannot create a controller for every path that they might want... so is there any way of writing my routing in Global.asax.cs in such a way that requests to "services" and "home" will be treated the normal way, but anything else will implicitly be routed to the "go" controller?
Are you on IIS7? It might be easiest to just implement URL rewriting on the server for this, rather than hacking about with your routes in Global.asax.cs.
EDIT: I've only ever done URL rewriting in Apache. For what it's worth that would be done using something like this:
RewriteEngine On
RewriteRule ^go/(.+)$ /$1 [R=301,L]
Have a look at http://learn.iis.net/page.aspx/460/using-the-url-rewrite-module/ and http://learn.iis.net/page.aspx/461/creating-rewrite-rules-for-the-url-rewrite-module/. Hopefully they'll give you enough info to be able to get this working in IIS 7
Hey, I worked it out myself, without URL rewriting!
Inside RegisterRoutes() in Global.asax.cs:
routes.MapRoute("Services", "services/{action}/{*qualifier}",
new { controller = "Services", action = "Index", qualifier = UrlParameter.Optional });
// and other controllers that I want to work the normal way
routes.MapRoute("Default", "{*path}",
new { controller = "Go", action = "Index", path = UrlParameter.Optional });
And in my GoController class
public ActionResult Index(string path) { ... }
Works perfectly!
You could try adding a mapping that does "geography/{country}" and have it specify the controller manually and add the country as a parameter. I've seen it done to prevent things like "Dashboard/Dashboard" etc.
An example can be seen at Kazi Manzur Rashid's Blog - ASP.NET MVC Best Practices (Part 2) #15 for what I am describing.
Have you seen this: http://www.iridescence.no/post/Defining-Routes-using-Regular-Expressions-in-ASPNET-MVC.aspx ?
you could try mapping a route of "{action}/{id}" with a default set for the controller. But that'll also match anything of the form "{controller}/{action}" too - unless you can do some clever constraining.