I recently switched my mvc3 localization structure from lang as subdomain (fr.domain.com) to lang as path (domain.com/fr).
Everything works fine but the automatic redirection to account logon.
Let's say I'm not authenticated and I try to access domain.com/fr/test I'm redirected to domain.com/Account/LogOn?ReturnUrl...
How can I configure my site so that I get redirected to /fr/Account/LogOn?ReturnUrl...
edit :
I use route mapping
routes.MapRoute(
"DefaultLocalized", // Route name
"{lang}/{controller}/{action}/{id}", // URL with parameters
new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
, new { lang = "fr" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
SOLUTION :
Here is my solution implementation based on developer10214's suggestion
public ActionResult LogOn()
{
if (System.Web.HttpContext.Current.Request.Url.Query.Contains("%2ffr%2f") && System.Threading.Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName != "fr")
return Redirect("/fr/Account/LogOn" + System.Web.HttpContext.Current.Request.Url.Query);
LogOnModel model = new LogOnModel() { UserName = "", Password = "" };
return View(model);
}
I think the reason why you get redirected to the common account/logon action is, that this path is configured in your memebership section in your web.config. Every request for an action which is protected by the Authorize attribute will end up there, if you are not logged in.
A possible solution could be:
change the logon action, by extracting lang parameter from the return url and redirect to the correct logon action
Related
I have an MVC website which used to use URLs in the standard format of: Controller/Action.
Recently, I have changed it to: Site/Controller/Action.
The problem is, there are several links to my site out there which follow the old format, and I want to redirect them accordingly.
for example: mydomain.com/Home/CustomerSearch now should go to mydomain.com/Online/Home/CustomerSearch
whereas: mydomain.com/AffiliatesHome/CustomerSearch now should go to mydomain.com/Affiliate/AffiliatesHome/CustomerSearch
How can I get it to handle the redirecting by putting in the extra routing, depending on the link they came in by?
The current routing I am using is:
routes.MapRoute(
"Default", // Route name
"{site}/{controller}/{action}/{id}",
new {site="IS", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Since I do not really see an schema in your old to new URL mapping I would suggest to add routes that match the old Controller/Action Schema and map them to the new Site/Controller/Action route schema.
So you could add the following routes
routes.MapRoute(
"LegacyHome",
"Home/{action}/{id}",
new { site="Online", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"LegacyAffiliates",
"AffiliatesHome/{action}/{id}",
new { site="Affiliate", controller = "AffiliatesHome", action = "Index", id = UrlParameter.Optional }
);
From an SEO standpoint this is not ideal because you have different URLs for the same page. A permanent redirect via status code 301 and the new URL passed in the location is better suited.
You could build a redirect controller and use the legacy routes to map legacy URLs to the redirect controller somehow like this
routes.MapRoute(
"LegacyHome",
"Home/{newAction}/{id}",
new { controller = "Redirect", action = "Redirect", newSite = "Online", newController="Home", newAction = "Index", id = UrlParameter.Optional }
);
Code of the redirect controller
public class RedirectController : Controller
{
public ActionResult Redirect(string newSite, string newController, string newAction)
{
var routeValues = new RouteValueDictionary(
new
{
site = newSite,
controller = newController,
action = newAction
});
if (RouteData.Values["id"] != null)
{
routeValues.Add("id", RouteData.Values["id"]);
}
return RedirectToRoutePermanent(routeValues);
}
}
After I run my program which is in MVC, the url it goes is Home/Index. Where to change this?
I want to check if the user is logged in, to redirect so some other page. If he isn't logged in, then the url can be Home/Index.
If you are using MVC you should look at using the Authorize action filter
The url you go to on not being authenticated is set in the web.config if you are using forms authentication.
You sort of asking two things.
You application automatically goes to Home/Index because of this, you'll find the below code if you double click your Global.asax file.
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Change the "Home" and "Index" strings for your custom default.
Now, for your login requirement, you could leave the default route and do this:
public class HomeController
{
public ActionResult Index()
{
if(!Request.IsAuthenticated)//if NOT authenticated
{//go somewhere else
return RedirectToAction(actioName, controllertName);
}
//for logged in users
return View();
}
}
For the first part of your question (the route), check out the default route, its usually set to
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Which is in your Global.asax file in the web application, and this is why you are seeing what you are seeing.
You really need to read up on ASP.Net Routing - http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/asp-net-mvc-routing-overview-cs
I have a seemingly strange problem with ASP.NET MVC.
We built a Website for Customer X and deployed it on their Server. First Problem is that it's behind a Novel Access Manager so all requests to the page go through:
https://portal.customerx.com/intranet/tool/{and here starts my Route for MVC}
For that reason i set up the Globol.asax like this:
routes.MapRoute(
"SubfolderZielsetzung", // Route name
"intranet/tool" + "{controller}/{action}/{objectOneId}", // URL with parameters
new { controller = "Home", action = "Index", objectOneId = "objectOneId" } // Parameter defaults
);
Now the request was that i add on the Homepage a hyperlink to a static Website which is in their Intranet:
https://portal.customerx.com/asdf/foo/bar/1337/test-1
if i simply add to the Homepage following HTML tags:
Support
So and now comes the strange thing. This is what will get rendered from the engine:
<a href="https://portal.customerx.com/intranet/tool/asdf/foo/bar/1337/test-1">
For some reason, and i cannot get the answer why, the routing engine alters my hyperlink even though i don't use any Html Helpers and sets the URL Prefix after "https://portal.customerx.com/"
EDIT
I wrote yesterday that I've found the answer, but as it turns out it wasn't the answer either.
I've put following route at the top of the Global Asax as a hint from this articlte:
Asp.net MVC and redirect to External site
routes.MapRoute(
"RedirectSiteRoute",
"{site}",
new { },
new { site = new SiteRouteConstraint() }
);
and:
public class SiteRouteConstraint : IRouteConstraint
{
public bool Match(System.Web.HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
string[] allowedSites = new[] { "https://portal.customerx.com/intranet/tool/asdf/foo/bar/1337/test-1" };
return allowedSites.Any(x => x == values[parameterName].ToString());
}
}
Then I moved all the routes with the URL Prefix to the bottom of the global asax so now all my Routes without URL_Prefix were at the top.
This is how it looked like:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"RedirectSiteRoute",
"{site}",
new { },
new { site = new SiteRouteConstraint() }
);
routes.MapRoute(
"Grundauftrag", // Route name
"{controller}/{action}/{objectOneId}/{objectTwoId}/{objectThreeId}", // URL with parameters
new { controller = "Home", action = "Index", objectOneId = "objectOneId", objectTwoId = "objectTwoId", objectThreeId = "objectThreeId" } // Parameter defaults
);
routes.MapRoute(
"Zielsetzung", // Route name
"{controller}/{action}/{objectOneId}/{objectTwoId}", // URL with parameters
new { controller = "Home", action = "Index", objectOneId = "objectOneId", objectTwoId = "objectTwoId" } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{objectOneId}", // URL with parameters
new { controller = "Home", action = "Index", objectOneId = "objectOneId" } // Parameter defaults
);
routes.MapRoute(
"SubfolderGrundauftrag", // Route name
Const.URL_PREFIX + "{controller}/{action}/{objectOneId}/{objectTwoId}/{objectThreeId}", // URL with parameters
new { controller = "Home", action = "Index", objectOneId = "objectOneId", objectTwoId = "objectTwoId", objectThreeId = "objectThreeId" } // Parameter defaults
);
routes.MapRoute(
"SubfolderZielsetzung", // Route name
Const.URL_PREFIX + "{controller}/{action}/{objectOneId}/{objectTwoId}", // URL with parameters
new { controller = "Home", action = "Index", objectOneId = "objectOneId", objectTwoId = "objectTwoId" } // Parameter defaults
);
routes.MapRoute(
"Subfolder", // Route name
Const.URL_PREFIX + "{controller}/{action}/{objectOneId}", // URL with parameters
new { controller = "Home", action = "Index", objectOneId = "objectOneId" } // Parameter defaults
);
}
With that on the customer platform the static link worked fine. But now all the other links within my page didn't work anymore...
I had to put the routes with URL_Prefix back to the top for it to work again but now of course the static link does not work anymore.
Any Ideas?
add https:// otherwise IIS looks for this resource from the root foler ot your site
I've had similar issues where I need to bind incoming and outgoing routes in different ways.
I did this by putting my incoming bindings first (as you can't really force a specific route on incoming). For the outgoing link I use Html.RouteLink and I can specify which route I want to use regardless of its position.
I am trying to add support for different languages to existing MVC 3 application. So far my links were
oldUrl -> myapp.com/Item/Details/5/some-title
And there are links to the website from different places on the web. But now I want to change the URL so the language is included:
newUrl -> kmyapp.com/en/Item/Details/5/some-title
However I want the oldUrl links to be valid. And the question is how do I do this... The easiest way would be to add another route, but I already have too many of them and it is getting kind of ugly, and when I create urls from a page that doesn't have the language the links also don't have the language so I have to do something else then.
Another way would be to override something that stands just before MVC tries to map the request to a specific route, but has already parsed the request url and filled the routeValues dictionary. So I can just check for the language and if it is not included in the route parameters I can add it on my own and call the implementation of the parent class to continue. Is that possible? What should I look at - UrlRoutingModule, MvcHttpHandler or something else? What can I override and how to tell MVC to use my version?
Any other ideas would be also appreciated!
There are of course many solutions. I'm going to show you two:
one that you control in your application
one that you control outside of your application (on IIS)
Solution one - Asp.net MVC routing
Provide routing that covers old and new routing:
routes.MapRoute(
"New",
"{lang}/{controller}/{action}/{id}",
new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional },
new { lang = "en|de|it|es|fr" }
);
routes.MapRoute(
"NewEx",
"{lang}/{controller}/{action}/{id}/{title}",
new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional, title = UrlParameter.Optional },
new { lang = "en|de|it|es|fr" }
);
routes.MapRoute(
"Old",
"{controller}/{action}/{id}",
new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"OldEx",
"{controller}/{action}/{id}/{title}",
new { lang = "en", controller = "Home", action = "Index", id = UrlParameter.Optional, title = UrlParameter.Optional }
);
As you can see I've provided language default for the old routes as well since it's not present in the URL. Whether you want that or not is your own decision but this kind of routing makes it possible to not duplicate your controller actions. In any case you'd have to define a default language which can be provided this way.
There's a bigger question whether you still want to support old URLs or you'd rather redirect them (HTTP Redirect Permanent Status 301).
Permanent redirection
Change old routes to:
routes.MapRoute(
"Old",
"{controllerOld}/{actionOld}/{idOld}",
new { controller = "Redirect", action = "Permanent", id = UrlParameter.Optional }
);
routes.MapRoute(
"OldEx",
"{controllerOld}/{actionOld}/{idOld}/{titleOld}",
new { controller = "Redirect", action = "Permanent", id = UrlParameter.Optional, title = UrlParameter.Optional }
);
Then write a controller class that does redirection:
public class RedirectController : Controller
{
public ActionResult Permanent(string controllerOld, string actionOld, string idOld, string titleOld)
{
return RedirectToRoutePermanent(new {
lang = "en",
controller = controllerOld,
action = actionOld,
id = idOld,
title = titleOld
});
}
}
Solution two - IIS URL rewriting module
This solution relies on IIS URL Rewriting module, where you could rewrite any requests without language selection to your preferred default.
I'm not going to wrote how URL Rewriting works here, because there're plenty of web resources with detailed info about that.
Another way would be to override something that stands just before MVC tries to map the request to a specific route, but has already parsed the request url and filled the routeValues dictionary. So I can just check for the language and if it is not included in the route parameters I can add it on my own and call the implementation of the parent class to continue. Is that possible?
Yes It is possible.
You can Override GetRouteData in RouteBase which will have URL details in it.
public override RouteData GetRouteData(HttpContextBase httpContext)
{
string url = httpContext.Request.AppRelativeCurrentExecutionFilePath;
}
and in global.aspx add below code.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(new MyUrlRoute()); // Add before your default Routes
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
For more detailed implementation - refer blog
url-manipulation-implementing-routebase.html
I have MVC3 application, where I want to keep short URL. what is the best or clean way to do this?
Lets say I have two controllers Account and Home. I have all the account related tasks Logon, Logoff, Profile, FAQs etc. in Account controller. All the main tasks in home controller like TaskA, TaskB, and TaskC. I am looking for URL as below:
www.mydomain.com/Logon
www.mydomain.com/Logoff
www.mydomain.com/Profile
www.mydomain.com/FAQs
www.mydomain.com/TaskA
www.mydomain.com/TaskB
when user first come to the website they need to redirect to Logon page. At any time user should also able to switch from once controller action to another controller action (from TaskA to Logoff).
what is the clean way to do this?
You don't need to set a route for each URL. With a little help from route constraints you can do something like this:
routes.MapRoute(
"Home", // Route name
"{action}", // URL with parameters
new { controller = "Home", action = "Index" }, // Parameter defaults
new { action = "TaskA|TaskB|TaskC|etc" } //Route constraints
);
routes.MapRoute(
"Account", // Route name
"{action}", // URL with parameters
new { controller = "Account", action = "Logon" }, // Parameter defaults
new { action = "Logon|Logoff|Profile|FAQs|etc" } //Route constraints
);
You can set a route for the specific urls that do not match the default route. For example:
routes.MapRoute("Logon", "logon/", new { controller = "account", action = "logon" });
routes.MapRoute("TaskA", "TaskA/", new { controller = "home", action = "taska" });
Your default route can define your start page if all other matches for the url are not found.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}/", // URL with parameters
new { controller = "account", action = "logon", id = UrlParameter.Optional } // Parameter defaults