I'm just starting out with .NET, and am building a test application. I currently have the homepage set using a DefaultController, and an Index() action method. This works as expected, and the homepage is simple www.domain.com.
I have created 2 new pages (Terms and Privacy) under the same DefaultController, using Terms() and Privacy() action methods.
I want to be able to browse to these with the URL as www.domain.com/terms and www.domain.com/privacy.
When i use a <li>#Html.ActionLink("Terms of Service", "Terms", "Default")</li> it works, but it takes me to the URL at www.domain.com/Default/privacy.
Should i be creating seperate controllers for each of these pages, or am I using the #html.ActionLink helper incorrectly? I have previously used <li>Privacy Policy</li> but I understand this isn't best practice?
Also, is there a way to force links as lowercase?
My Controller Code:
public class DefaultController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Terms()
{
return View();
}
public ActionResult Privacy()
{
return View();
}
}
If these were in the HomeController I don't believe you'd have the same problem. However, I think you can get around this by using the RouteConfig file:
routes.MapRoute(
name: "Default",
url: "{Action}/{Id}",
defaults: new { controller = "Default", Action = "Index", Id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Generic",
url: "{controller}/{Action}/{Id}",
defaults: new { Action = "Index", Id = UrlParameter.Optional }
);
I believe that what you want to do is hide the controller name in the url. If that is the case, your question is answered here:
ASP.NET MVC - Removing controller name from URL
You can use Attribute routing to give specific routes to endpoints.
[Route("terms")]
public ActionResult Terms()
{
return View();
}
[Route("privacy")]
public ActionResult Privacy()
{
return View();
}
In your RouteConfig.cs you must enable attribute routing with the following line of code: routes.MapMvcAttributeRoutes();
Now any urls generated with #Url.Action() or #Html.ActionLink should generate URLS as domain.com/privacy and domain.com/terms
Related
I m using attribute routing feature of Asp .Net Mvc.
My first action is like below which is placed in SurveyController
[Route("{surveyName}")]
public ActionResult SurveyIndex()
{
return View();
}
And my second action is like below which is placed in MainCategoryController
[Route("{categoryUrlKey}")]
public ActionResult Index(string categoryUrlKey)
{
return View();
}
I'm not using convention based routing.
Below is my RouteConfig.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
routes.MapAttributeRoutes();
}
Now the problem is when i click to a survey it redirects to the MainCategory/Index route. I know it is because of same route pattern but i cant change this into another thing.
how can I handle this situation?
Thanks
You should prefix the routes on your MainCaregoryController, either at the controller level like this:
[RoutePrefix("category")]
public class MainCategoryController : Controller {
or at the action level like this:
[Route("category/{categoryUrlKey}")]
public ActionResult Index(string categoryUrlKey)
{
return View();
}
Routes should not clash. This route:
[Route("{categoryUrlKey}")]
public ActionResult Index(string categoryUrlKey)
{
return View();
}
matches any string and passes that string value into the action, so without a prefix it will match:
http://localhost/validcategorykey
and
http://localhost/something/id/isthispointmakingsense
and your categoryUrlKey parameter would equal "validcategorykey" in the first instance and "something/id/isthispointmakingsense" in the second.
Now as for this route:
[Route("{surveyName}")]
public ActionResult SurveyIndex()
{
return View();
}
This just won't work period. This needs to be changed to:
[Route("survey/{surveyName}")]
public ActionResult SurveyIndex(string surveyName)
{
return View();
}
I'm trying to use a Kendo Grid for a list of objects on my model, but the url's generated by the .Create() etc. methods are not generating the url correctly.
It doesn't appear to be just Kendo though because even in my controller using Url.Action() generates the wrong url.
// POST: Assessment/Create
[HttpPost]
[ValidateAntiForgeryToken]
[Route("eForms/Assessment/Create")] // <-- Tried with and without this
public ActionResult Create(AssessmentPoco model)
{
var x = Url.Action(("Allergy_Read", "Assessment");
}
//POST: Assessment/Allergy_Read
[HttpPost, ActionName("Allergy_Read")]
[Route("AllergyRead", Name = "Allergy_Read")]
public ActionResult Allergy_Read([DataSourceRequest] DataSourceRequest request, AssessmentAllergiesSection model) //, int id)
{
return Json(new[] { model }.ToDataSourceResult(request, ModelState));
}
Expected: eForms/Assessment/Allergy_Read
Actual: /?action=Allergy_Read&controller=Assessment
Route config:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("");
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//web forms default
routes.MapPageRoute(
routeName: "WebFormDefault",
routeUrl: "",
physicalFile:"~/default.aspx");
routes.MapRoute(
name: "API",
url: "eforms/api/{controller}/{action}/{id}",
defaults: new {controller="Customer", action="GetCustomers", id = UrlParameter.Optional}
);
////mvc default
routes.MapRoute(
name: "Default",
url: "eforms/{controller}/{action}/{id}",
defaults: new { controller = "IncidentReports", action = "Search", id = UrlParameter.Optional }
);
}
Not sure what else could be at fault here (besides my brain), any ideas?
Clarifications (from comments):
We are using Areas
Global.asax is calling RegisterRoutes (also tried turning it off no change)
Update:
This project is a newly added MVC project to an existing ASP.Net WebForms app. I updated the Route config because I was using looking at the wrong one.
You're using routeAttribute, so put a name inside it and use Html.RouteLink or Url.RouteUrl instead of Url.Action().
Example:
[Route("menu", Name = "mainmenu")]
public ActionResult MainMenu() { ... }
Usage in View:
Main menu
I tried this code in controller:
public class HomeController : Controller
{
[Route("AllergyRead", Name = "Allergy_Read")]
public ActionResult Allergy_Read()
{
return View();
}
}
And:
#Html.RouteLink("Allergy Read", "Allergy_Read")
Give me the right route to action. I can't figure out why your implementation isn't working.
I searched longer than I care to admit for a solution, but cannot find one.
My site has hundreds of static pages.
It is very tedious to add a single ActionResult per View.
Especially because I have to stop debugging to edit the code.
So for example, if I want to add an About page I have to add...
public ActionResult About()
{
return View();
}
It seems to me that I should be able to make this dynamic and pass the view in via the route.
I mean, as long as I have a file called About.cshtml, then why do I need to add a custom ActionResult.
I'd rather do something like this, but it doesn't work.
public ActionResult Index(_ViewName)
{
return View(_ViewName);
}
Is it possible to have a generic ActionResult and pass the name of the view in via the URL Route?
With your default route you can edit index method as below and get it done.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
public ActionResult Index(string id)
{
return View(id);
}
What you have to do is add the view according to the name you are parsing.
Example
/home/index/about
/home/index/contact
(About.cshtml and Contact.cshtml views should be in /Views/Home/ folder)
Thanks!
In ASP.NET MVC 4 I wonder about the behavior, how links are generated for me.
Imagine a simple controller with 3 actions, each taking an integer parameter "requestId", for example:
public class HomeController : Controller
{
public ActionResult Index(int requestId)
{
return View();
}
public ActionResult About(int requestId)
{
return View();
}
public ActionResult Contact(int requestId)
{
return View();
}
}
and this registered route (before the default route):
routes.MapRoute(
name: "Testroute",
url: "home/{action}/{requestId}",
defaults: new { controller = "Home", action = "Index" }
);
I call my index-view using http://localhost:123/home/index/8
On this view, I render links for the other two actions:
#Html.ActionLink("LinkText1", "About")
#Html.ActionLink("LinkText2", "Contact")
Now I expect MVC to render this links including the current route-value for "requestId", like this:
http://localhost:123/home/about/8
http://localhost:123/home/contact/8
But i get these links (without the paramter):
http://localhost:123/home/about
http://localhost:123/home/contact
...but not for the index-action if i would specify one:
#Html.ActionLink("LinkText3", "Index")
What I want to avoid is to explicitly specify the parameters in this manner:
#Html.ActionLink("LinkText1", "Contact", new { requestId = ViewContext.RouteData.Values["requestId"] })
When I move the requestId parameter before the action paramter it works like I expect it, but I don't want to move it:
routes.MapRoute(
name: "Testroute",
url: "home/{requestId}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
Can someone explain me this behavior? How can I get this to work without specifying the parameter explicitly?
InController:
Replace the int to nullable int
For Routing:
set requestId as optional in routing
routes.MapRoute(
name: "Testroute",
url: "home/{action}/{requestId}",
defaults: new { controller = "Home", action = "Index" ,requestId=RouteParameter.Optional }
);
So i'm trying to employ the use of hyphens in my URLs for readability but so far haven't found a way to make it work with mvc4.
I'll start with the code in the controller:
public ViewResult Index()
{
ViewBag.URL = Functions.fetchURL();
return View();
}
[HttpPost]
public ActionResult Index(LogonModel model, string returnUrl)
{
//omitted to save space
return View(model);
}
public ActionResult Forgot_Login_Info()
{
return View();
}
[HttpPost]
public ActionResult Forgot_Login_Info(RetrievePasswordViewModel model)
{
//omitted to save space
return View();
}
So I'm using underscores for the name of the actions as seen with "Forgot_Login_Info" and that is the name of the view as well. For testing I also manually created a view called "Forgot-Login-Info"
In my global.asax.cs file i simply have this line for routes
RouteConfig.RegisterRoutes(RouteTable.Routes);
which is the standard routing line with new projects for MVC4 and this is hooked to the "RouteConfig.cs" file and in that file here is the code I have, which I found in another question on this site.
public class RouteConfig
{
public class HyphenatedRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.RouteData.Values["controller"] = requestContext.RouteData.Values["controller"].ToString().Replace("-","_");
requestContext.RouteData.Values["action"] = requestContext.RouteData.Values["action"].ToString().Replace("-", "_");
return base.GetHttpHandler(requestContext);
}
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.Add(
new Route("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Default", action = "Index", id = UrlParameter.Optional }),
new HyphenatedRouteHandler())
);
}
}
Lastly here is the code for the "Index" view, which is where I have a link to the "Forgot_Login_Info".
<div class="centerBlockItem" style="width:450px; text-align:center">
#Html.ActionLink("Forgot Password?", "Forgot-Login-Info")
#Html.ActionLink("Forgot Password?", "Forgot_Login_Info")
</div>
Now I have the link 2 ways, 1 using underscore and the other using hyphen. According to what i've read in regards to the code I found for this purpose, Both links should open the "Forgot_Login_Info" view and not the "Forgot-Login-Info" view. But what I'm getting instead is the 2nd link works fine and the action name matches the view files name. But when I click on the first link, I get a 404 error because the system can't find the "Forgot-Login-Info" view file, even though I had manually created a file with that name for testing.
One more thing to note, the code in my routeconfig file, In the answer I had found it suggested I comment out the default route code lines and just leave:
routes.Add(
new Route("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Default", action = "Index", id = UrlParameter.Optional }),
new HyphenatedRouteHandler())
);
I had done this too and got the same results. Any ideas where I'm screwing things up?
Ok I figured out what I was doing wrong, I had this listed under the root routebundle.cs file but i was trying to make this work in an area, once I moved this code to the area registration file, it worked like a charm. If anyone needs my full code listing just ask and i'll post it all up.
How is this helping SEO when the crawlers can still access the underscore version of the controller, thereby duplicating content. Struggling with this right now.