Does any body knows how to hide some parameters in url?
For example you have a url parameter "culture". It can be "en, fr, it".
By default your site renders in "en" culture and we don't wont to show default culture in the URL but in cases of other cultures parameter "culture" must appear in URL.
http://myrendersite.net/barbikueue
http://myrendersite.net/fr/barbikueue
This is same pages in different cultures.
How to do what basing on default asp.net mvc routing system?
This will help:
ASP.NET mvc, localized routes and the default language for the user
asp.net mvc localization
Set Culture in an ASP.Net MVC app
You have to register two routes:
routes.MapRoute(
name: "DefaultLang",
url: "{language}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { language = "[a-z]{2}"}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Create an Attribute that inherits ActionFilterAttribute:
public class LanguageActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var routeDataKey = "language";
var defaultLang = "en";
var defaultCulture = "EN";
// if no language route param received
if (filterContext.RouteData.Values[routeDataKey] == null /* && currentCulture != "en-EN" */)
{
// change culture to en-EN
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", defaultLang, defaultCulture));
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", defaultLang, defaultCulture));
}
else
{
/*if (currentCulture != "whatever")
{
//set culture to whatever
}*/
}
base.OnActionExecuting(filterContext);
}
}
After that create a BaseController with the previous created attribute:
[LanguageActionFilter]
public abstract class BaseController : Controller
{
}
And all your Controllers will inherit BaseController now, instead of Controller
The following RouteConstraint might help,
public class CultureConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
if (routeDirection == RouteDirection.UrlGeneration)
{
return values[parameterName] != null &&
(route.Defaults[parameterName] == null ||
values[parameterName].ToString().ToLower() != route.Defaults[parameterName].ToString().ToLower());
}
return true;
}
}
Use it as,
routes.MapRoute(
name: "Culture",
url: "{culture}/{controller}/{action}/{id}",
defaults: new {culture = "en", controller = "Home", action = "Index", id = UrlParameter.Optional},
constraints: new {culture = new CultureConstraint()}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional}
);
Here the constraint only works on outbound url and discard the route for candidacy when 'culture' in route information equals to default.
I used the simplest implementation because you have not posted your route code, but the idea should work.
hope this helps.
Related
We're currently making a small CMS module for our application where existing routes and controllers are highly prioritize, while dynamically created pages through the CMS will only be loaded if the provided URL does not exists in the default route.
I already looked at this one: Dynamic Routes from database for ASP.NET MVC CMS
but it prioritizes the dynamically created page before the routes.
This is our default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Store", action = "Index", id = UrlParameter.Optional }
);
And aside from the default route, we have other routes that are using prefixes like this one:
routes.MapRoute(
name: "Media",
url: "m/{*url}",
defaults: new { controller = "Content", action = "GetContent", contentlibrary = "Media" },
constraints: new { url = #"(.*?)\.(png|jpg|pdf|mpeg|mp3|mp4)" }
);
UPDATE 1:
I created an IRouteConstraint for validating if the Controller exists for the default route. Here is my code:
public class ControllerValidatorConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var tempRequestContext = httpContext.Request.RequestContext;
IController controller = null;
try
{
controller = ControllerBuilder.Current.GetControllerFactory().CreateController(httpContext.Request.RequestContext, values["controller"].ToString());
}
catch (Exception ex)
{
}
return controller != null;
}
}
then on routing:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Store", action = "Index", id = UrlParameter.Optional },
constraints: new { url = new ControllerValidatorConstraint() }
);
routes.MapRoute(
name: "Page",
url: "{*url}",
defaults: new { controller = "Content", action = "GetPage" },
constraints: new { url = #"(.*?)(|.cshtml)" },
namespaces: new[] { "AppCore.Controllers" }
);
This already works as what I intend. The only remaining issue is the Match() method. The Match() method is currently creating an instance of the controller, I wrapped it with a Try-Catch block because it throws an error related to the provided path that does not exists as temporary solution but this is still wrong.
I'm almost there, I just have to find a proper way to check if the controller exists. Is reflection a bad choice? Any lighter way to check them? Thanks!
On the Index.cshtml view of EuroController i have an ActionLink that i want to use the "IndexByYear" action of Euro controller:
#Html.ActionLink("Year 2006", "IndexByYear","Euro", new { id = "", year = 2006 }, null)
But the problem is that it goes to the Index() method, even though it's everything set on RouteConfig:
routes.MapRoute(
name: "Default",
url: "{controller}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Euro",
url: "{controller}/{year}/{id}",
defaults: new { controller = "Euro", action = "IndexByYear", year = DateTime.Now.Year, id = UrlParameter.Optional }
);
Here's the EuroController:
public ActionResult Index(int? id)
{
...
}
public ActionResult IndexByYear(int? id, int year)
{
...
}
Also this don't work, as it also goes to Index() method:
#Html.RouteLink("Ano 2006","Euro",new { id = "", year = 2006 },null)
If i manually navigate to domain/Euro/2016/1, then it uses the correct route. Seems like with no parameters it goes through the Default route.
My question is, why does the ActionLink don't use the IndexByYear as specified, or the RouteLink use the specified default (Euro) route?
If you want just the EuroController to have a "special" routing, you would want to do something like:
routes.MapRoute(
name: "Euro",
url: "euro/{year}/{id}",
defaults: new { controller = "Euro", action = "IndexByYear", year = DateTime.Now.Year, id = UrlParameter.Optional }
);
routes.MapRoute(
name: "DefaultNoController",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { isMethodInHomeController = new RootRouteConstraint<Controllers.HomeController>() }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Where the constraint is defined like so:
public class RootRouteConstraint<T> : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var rootMethodNames = typeof(T).GetMethods().Select(x => x.Name.ToLower());
return rootMethodNames.Contains(values["action"].ToString().ToLower());
}
}
This will match
domain/euro/1 to the Index action on EuroController
domain/euro/2008/1 to the IndexByYear action on EuroController
domain/ to the Index action on HomeController
domain/about to the About action on HomeController
domain/someothercontroller to the Index action on whatever other controllers you define
You may want to read https://msdn.microsoft.com/en-us/library/cc668201.aspx and https://www.asp.net/mvc/overview/older-versions-1/controllers-and-routing/creating-a-custom-route-constraint-cs
I believe this has to be very easy but I just cant figure it out.
I have custom route
routes.MapRoute(
name: "DefaultLocalized",
url: "{language}/{controller}/{action}/{id}",
defaults: new { language = "EN", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
In the controller i have
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
ViewBag.language = Internationalization.SetCultureFromUrl(requestContext, "EN");
}
and the question is, how to specify language attribute in #Html.ActionLink ?
I have a route configured like
routes.MapRoute(
name: "Default",
url: "TEST/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
It works fine to redirect to respective controller and actions.
I want to add another redirection on TEST so that if somebody uses www.mysite.com/TEST, it should redirect www.mysite.com/Test/Home instead of giving 403- Forbidden: Access is denied error.
I'm trying like this but could not achieve it.
routes.MapRoute(
name: "AnotherDefault",
url: "TEST",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Basically, what I'm trying to do is to redirect from www.mysite.com or www.mysite.com/TEST to www.mysite.com/TEST/Home
To add to the confusion, I also had a physical folder TEST in my application root. Just wondering if keeping another web.config in there would solve? I tried but of no luck
Please advise what i'm missing here. Thanks
After some experiment I have found that the physical folder TEST is causing redirection rule to fail. I changed my route to TEST1 in URL instead of TEST, it worked. But, I can't rename TEST folder. Please advise
Please set the property RouteExistingFiles to true above the Route configurations
public static void RegisterRoutes(RouteCollection routes)
{
routes.RouteExistingFiles = true;
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "TEST/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
This should allow you to keep the name of folder and also the route name to be "TEST". Let me know how it works out for you
Keep using the first route:
routes.MapRoute(
name: "Default",
url: "TEST/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
and add this in your Web.config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"></modules>
<handlers>
<remove name="UrlRoutingHandler"/>
</handlers>
</system.webServer>
We Can manage url routing by validate from database.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// here i pass my parameter like wwww.abc.com/country-state-city
routes.MapLocalizedRoute("SeoFriendlyUrl",
"{SeoFriendlyName}",
new { controller = "Company", action = "Index" },
new[] { "MigrationTest.Controllers" });
// it is default
routes.MapRoute( name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
public static class LocalizedRouteExtensionMethod
{
public static Route MapLocalizedRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
{
return MapLocalizedRoute(routes, name, url, defaults, null /* constraints */, namespaces);
}
public static Route MapLocalizedRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
if (url == null)
{
throw new ArgumentNullException("url");
}
var route = new clsRouteData(url, new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0))
{
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
}
public class clsRouteData : Route
{
public clsRouteData(string url, IRouteHandler routeHandler)
: base(url, routeHandler)
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData data = base.GetRouteData(httpContext);
if (data != null)
{
var SeoFriendliyName = data.Values["SeoFriendlyName"] as string;
if (SeoFriendliyName=="india-raj-jaipur")
{
data.Values["controller"] = "City";
data.Values["action"] = "Index";
// Can be send parameter
//data.Values["Id"] = Resutls.Id;
}
}
else
{
data.Values["controller"] = "Norecord";
data.Values["action"] = "Index";
// Can be send parameter
//data.Values["Id"] = Resutls.Id;
}
return data;
}
}
Is it possible to create a different default route for a different user role?
e.g.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Admin", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "totalrewardstatement", action = "Details", id = UrlParameter.Optional } // Parameter defaults
);
}
Have the default route above for normal users but use the admin one if an admin user logs in?
Role based routing is not supported in MVC. What you do is have default controller which checks for the roles and redirect to that controller
public ActionResult Index()
{
if (User.IsInRole("Supervisor"))
{
return RedirectToAction("Index", "InvitationS");
}
return View();
}
http://forums.asp.net/t/1994888.aspx?role+based+routing+asp+net+mvc
Using a custom RouteConstraint did the trick for me on mvc 5.
public class RoleConstraint : IRouteConstraint
{
public bool Match
(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)
{
return httpContext.User.IsInRole(parameterName) ;
}
}
RouteConfig.cs
routes.MapRoute(
name: "Reader_Home",
url: "",
defaults: new { controller = "Reader", action = "Index", id = UrlParameter.Optional },
constraints: new { reader_role = new RoleConstraint() }
);
routes.MapRoute(
name: "Author_Home",
url: "",
defaults: new { controller = "Publication", action = "Index", id = UrlParameter.Optional },
constraints: new { author_role = new RoleConstraint() }
);
I'm using the parameterName (author_role and reader_role) as the role name to check for simplification.