I am calling:
#Html.ActionLink("Register", "Register", "Account", new {area="FrontEnd"})
expecting
www.example.com/Account/Register
but I'm getting
http://www.example.com/?action=Register&controller=Account&area=FrontEnd
I'm a little confused as to why this happening, what can I do to resolve this?
Edit
When I remove the area parameter at the end, it builds the link correctly but to my admin section instead of FrontEnd.
Edit
I've isolated it to a custom route I have setup:
routes.Add("CategoriesRoute", new CategoriesRoute()); //This is breaking ActionLink.
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", area = "FrontEnd", id = UrlParameter.Optional },
new[] { "CC.Web.Areas.FrontEnd.Controllers" }
);
This is the custom route.
public class CategoriesRoute : Route
{
public CategoriesRoute()
: base("{*categories}", new MvcRouteHandler())
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var rd = base.GetRouteData(httpContext);
if (rd == null)
return null;
string categories = rd.Values["categories"] as string;
if (categories.IsEmpty())
return null;
string[] parts = categories.Split('/');
if (not a category) //pseudo code
return null;
rd.Values["controller"] = "Category";
rd.Values["action"] = "Index";
rd.Values["area"] = "FrontEnd";
rd.DataTokens.Add("namespaces", new string[] { "CC.Web.Areas.FrontEnd.Controllers" });
rd.Values["categoryString"] = "/" + categories; //Required to get exact match on the cache.
return rd;
}
}
Try the below. I think you're missing an attribute null at the end
#Html.ActionLink("Register", "Register", "Account", new {area="FrontEnd"}, null)
You need to add null for the 5th parameter (html attributes)
#Html.ActionLink("Register", "Register", "Account", new {area="FrontEnd"}, null)
Related
I have a problem, my url is ugly smth like this:
http://localhost:43547/Admin?id=1&str=wooh
I want see the url like this one
http://localhost:43547/LOL
My routes are:
routes.MapRoute(
"MyRoute",
"LOL",
new { controller = "Admin", action = "Index",
id = UrlParameter.Optional, str = UrlParameter.Optional }
);
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index" }
);
and I have 2 identical views one of them is with such method
#Html.ActionLink("Click me", "Index", "Admin", new { id = 1, str = "wooh" }, null)
which moves the page...
and I have 2 controllers:
public ActionResult Index(int id = 5485, string str = "Default Value")
{
ViewBag.ID = id;
ViewBag.STR = str;
return View();
}
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Controller = "Home";
ViewBag.Action = "Index";
return View();
}
}
So what's wrong? When I type smth like /LOL
It moves me to another page with default values of id and str...
Change your MyRoute definition to include the id and str parameter values.
routes.MapRoute(
"MyRoute",
"LOL",
new { controller = "Admin", action = "Index",
id = 1, str = "wooh" }
);
That way your url will look like /LOL but will pass the values you need.
I was wandering if there is option to do the following
If I call
"admin/Category" - to call "CategoryAdminController"
If I call
"Category" - to call "CategoryController"
It is very easy to do this via routing and custom controller factory. Here is the solution:
// add route
routes.Add(new Route("{culture}/admin/{controller}/{action}/{*id}", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "Home", action = "Index", id = "", culture = LocalizationManager.DefaultCulture.Name, controllerSufix = "Admin" }),
Constraints = new RouteValueDictionary(new { culture = new CultureRouteConstraint() })
});
Than create custom controller factory
public class CmsControllerFactory : DefaultControllerFactory
{
RequestContext _requestContext;
protected override Type GetControllerType(string controllerName)
{
if (_requestContext.RouteData.Values.ContainsKey("controllerSufix"))
{
string sufix = (string)_requestContext.RouteData.Values["controllerSufix"];
Type type = base.GetControllerType(String.Concat(controllerName, sufix));
if (type != null)
return type;
}
return base.GetControllerType(controllerName);
}
public override IController CreateController(RequestContext requestContext, string controllerName)
{
_requestContext = requestContext;
return base.CreateController(requestContext, controllerName);
}
}
I would like if anybody know some different/better solution.
You can do this quite simply with two route handlers:
routes.MapRoute(
"Admin",
"/admin/category/{id}",
new { controller = "CategoryAdminController", action = "Index", id = "" }
);
and then:
routes.MapRoute(
"Standard",
"/category/{id}",
new { controller = "CategoryController", action = "Index", id = "" }
);
My route looks like:
routes.Add(new Route("{companyName}/{action}/{id}", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "CompanyController", action = "Index", id = 1 }),
}
);
my action:
public ActionResult Index(string companyName, string id)
{
Response.Write(companyName);
Response.End();
return ViePage("~/views/company/index.aspx");
}
try this:
routes.Add(new Route("{companyName}/{action}/{id}", new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(new { controller = "Company", action = "Index", id = 1 }),
}
);
when referencing your controllers you don't want to have the "controller" part of the name there.
I need to maintain the querystring in all pages in my asp.net mvc(C#) application.
For ex.:
I will call a page www.example.com?Preview=True. The querystring should be maintained whatever the page i click in www.example.com. i.e. When i click About us page in www.example.com, the url should be www.example.com/AboutUs?Preview=True
How can i achieve this? Whats the best place to do this common operation.?
Maybe you need a custom route?:
public class PreviewRoute : System.Web.Routing.Route
{
...
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var preview = System.Web.HttpContext.Current.Session["Preview"];
if (!values.ContainsKey("Preview"))
values.Add("Preview", preview);
var path = base.GetVirtualPath(requestContext, values);
return path;
}
}
}
Set Session["Preview"] at any time and you will get all your urls with ?Preview=True:
System.Web.HttpContext.Current.Session.Add("Preview", true);
UPDATED:
Use this route in the Global.asax.cs:
routes.Add("Default",
new PreviewRoute("{controller}/{action}/{id}", new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(
new { controller = "Home", action = "Index", id = "" }
)
}
);
instead of:
routes.MapRouteLowercase(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
Also you can try this extension:
public static class CustomRouteExtensions
{
public static void MapPreviewRoute(this RouteCollection routes, string name, string url, object defaults) {
routes.MapPreviewRoute(name, url, defaults, null);
}
public static void MapPreviewRoute(this RouteCollection routes, string name, string url, object defaults, object constraints) {
if (routes == null) {
throw new ArgumentNullException("routes");
}
if (url == null) {
throw new ArgumentNullException("url");
}
var route = new PreviewRoute(url, new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints)
};
if (String.IsNullOrEmpty(name)) {
routes.Add(route);
}
else {
routes.Add(name, route);
}
}
}
In Global.asax.cs:
routes.MapPreviewRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
You could create a view Helper that appends the existing query string onto any links you create with your new helper.
This may help
You might be better storing this information in session.
An excellent direction from #eu-ge-ne.
I have used the idea of custom route from #eu-ge-ne to add the route value to every url and used a basecontroller to handle the Preview key in session.
if ((requestContext.HttpContext.Request.QueryString != null &&
requestContext.HttpContext.Request.QueryString["Preview"] != null &&
requestContext.HttpContext.Request.QueryString["Preview"].ToString() =="True") ||
(requestContext.HttpContext.Request.UrlReferrer != null &&
requestContext.HttpContext.Request.UrlReferrer.ToString().Contains("Preview=True")))
{
//Add the preview key to session
}
else
{
//Remove the preview key to session
}
I have used the above code in the Initialize method of the base controller. This way the preview key will in session if the querystring has Preview, else it removes from the session.
Thanks to #eu-ge-ne once again.
I'm at a loss... here's my route:
routes.MapRoute("LangOnly", "{language}",
new { controller = "Home", action = "Root", language = "en" },
new { language = #"en|ja" });
it matches www.domain.com/en, but does not match www.domain.com/ja.
huh? I've even gone so far as to comment out any other routes... kind of stuck. ;/
Update: Here's the root action on the Home controller.
[CompressFilter]
public ActionResult Root()
{
if (!IsEnglish)
return RedirectToAction("Index", "Biz", new { b = "" });
return Request.IsAuthenticated ? View("LoggedInRoot") : View("Root");
}
It doesn't take a language parameter because it's being set on the base controller in OnActionExecuting, like so:
var l = (RouteData.Values["language"] != null) ? RouteData.Values["language"].ToString() : string.Empty;
if (string.IsNullOrEmpty(l))
l = "en";
if (l.Contains("en"))
{
IsEnglish = true;
l = "en";
}
else
{
IsEnglish = false;
l = "ja";
}
ViewData["lang"] = l.ToLower();
Language = l.ToLower();
Works perfectly for me with your route. Try this simple configuration:
routes.MapRoute("LangOnly", "{language}",
new {controller = "Home", action = "Index", language = "en"},
new {language = #"en|ja"});
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
And your action:
public ActionResult Index(string language)
{
.....
(I am using "Index" as the action here, obviously change it to "Root" if that is in fact your action name.)