I'm having problems with routing. I have News controller and I can read the details of a news from url http://localhost/News/Details/1/news-title(slug). Here is no problem for now. But I created a controller called Services with Index action. Route config:
routes.MapRoute(
"Services",
"Services/{id}",
new { controller = "Services", action = "Index" }
);
When my Index Action is
public ActionResult Index(string title)
{
return View(title);
}
I write localhost:5454/Services/sometext by hand in browser it works.
But when change my index action to
public ActionResult Index(string title)
{
Service service = _myService.Find(title);
ServiceViewModel = Mapper.Map<Service , ServiceViewModel >(service );
if (service == null)
{
return HttpNotFound();
}
return View(serviceViewModel);
}
I get Http Error 404 Not Found for Url localhost/Services/ITServices.
I can add this services from admin page with it's title (ITServices for example).
Then I do foreach in my Home Page for the services links
#foreach (var service Model.Services)
{
<div class="btn btn-success btn-sm btn-block">
#Html.ActionLink(service.Title, "Index", new { controller = "Services", id = service.Title })
</div>
}
But I can't show the page in localhost/Services/ITServices.
When I click on the link I want to go to page localhost/Services/ITServices and it has to show the content(which can be added from admin page) like in the news. But I don't want to use it with action name and ids like in the news. How can I achieve this?
EDIT
Ok. I add FindByTitle(string title) in repository. I changed the id to title in RouteConfig and in the link in Home Page View. Then in my domain model deleted Id and updated Title as [Key]. Now it works. Only have to check with remote validation for possible duplicates of Title when adding new from admin page.
The parameter name in the URL template does not match the argument on the Action (Index).
So you can do one of two things.
Change the template parameter to match the argument of the Action
routes.MapRoute(
name: "Services",
url: "Services/{title}",
defaults: new { controller = "Services", action = "Index" }
);
Where Action Index is
public ActionResult Index(string title) { ... }
or you change the argument of the Action Index to match the paramater in the url template
public ActionResult Index(string id) { ... }
Where the route mapping is
routes.MapRoute(
name: "Services",
url: "Services/{id}",
defaults: new { controller = "Services", action = "Index" }
);
But either way the route is not finding route because it cannot match the parameters.
In fact if the intention is to use the title as a slug you could go so far as to use a catch all route for services like
routes.MapRoute(
name: "Services",
url: "Services/{*title}",
defaults: new { controller = "Services", action = "Index" }
);
Take a look at the answers provided here
how to route using slugs?
Dynamic routing action name in ASP.NET MVC
Try this:
public ActionResult Index(string id)
Related
I have created a controller and I don't want my default Action or View to be named Index. I created Action in TopicsController as below
[ActionName("Index")]
public ActionResult Topics()
{
var topic = new Topic();
return View("Topics", topic.GetTopics());
}
and it mached to URL xyz.com/Topics.
I tried to apply same philosophy to another controller, named, ModulesController but now I have got parameter.
[ActionName("Index")]
public ActionResult Modules(string id)
{
var topic = new Topic();
return View("Modules", topic.GetTopics());
}
but now it is saying
The resource cannot be found.
what I can do so that this action matches URL like xyz.com/Modules/aaaa?
To access the Url xyz.com/Modules/aaaa change the Action name for the Modules action to aaaa like this:
[ActionName("aaaa")]
public ActionResult Modules(string id)
{
var topic = new Topic();
return View("Modules", topic.GetTopics());
}
FYI - It would be better to avoid naming each action with the ActionName filter. At some point it would become difficult to manage. Instead manage the routes in the RouteConfig like this:
routes.MapRoute(
name: "Modules",
url: "{controller}/{action}/{id}",
defaults: new { controller="Modules", action="Modules", id=UrlParameter.Optional }
);
The following Urls will work for the above route:
xyz.com/Modules/aaaa
xyz.com/Modules/aaaa/123
xyz.com/Modules/aaaa?id=123
Update:
If you want 'aaaa' to be the parameter and want to access the action with xyz.com/Modules/aaaa (where 'aaaa' will be bound as the value to the Id variable) then add the following Route to the route table:
routes.MapRoute(
name: "Modules",
url: "Modules/{id}",
defaults: new { controller="Modules", action="Modules", id=UrlParameter.Optional }
);
Note the value of the Url above.
after I had added the Product route in my RouteConfig, my default homepage changed to Product page. How can I setup my home controller as my default homepage again.
routes.MapRoute(
name: "Product",
url: "{controller}/{action}",
defaults: new { controller = "Product", action = "Index" }
);
routes.MapRoute(
name: "Products",
url: "products/{categoryName}/{Id}",
defaults: new { controller = "Products", action = "Index", categoryName = "", Id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{action}",
defaults: new { controller = "Home", action = "Index"}
);
This is my route table. It doesn't use the route I marked on the table by default.
Screenshot of the route table
I think the first and last will act the same way.The program will pick the first route it matches so you should hard code the first route like this.
routes.MapRoute(
name: "Product",
url: "Product/{action}",
defaults: new { controller = "Product", action = "Index" }
);
or you should remove the first route. i think that you should go with this approach.
routes.MapRoute(
name: "Products",
url: "products/{categoryName}/{Id}",
defaults: new { controller = "Products", action = "Index", categoryName = "", Id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Explanation:
from a stephen walter's post
The default route table contains a single route (named Default). The Default route maps the first segment of a URL to a controller name, the second segment of a URL to a controller action, and the third segment to a parameter named id.
Imagine that you enter the following URL into your web browser's address bar:
/Home/Index/3
The Default route maps this URL to the following parameters:
controller = Home
action = Index
id = 3
When you request the URL /Home/Index/3, the following code is executed:
HomeController.Index(3)
The Default route includes defaults for all three parameters. If you don't supply a controller, then the controller parameter defaults to the value Home. If you don't supply an action, the action parameter defaults to the value Index. Finally, if you don't supply an id, the id parameter defaults to an empty string.
Let's look at a few examples of how the Default route maps URLs to controller actions. Imagine that you enter the following URL into your browser address bar:
/Home
Because of the Default route parameter defaults, entering this URL will cause the Index() method of the HomeController class in Listing 2 to be called.
Listing 2 - HomeController.cs
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
[HandleError]
public class HomeController : Controller
{
public ActionResult Index(string id)
{
return View();
}
}
}
In Listing 2, the HomeController class includes a method named Index() that accepts a single parameter named Id. The URL /Home causes the Index() method to be called with an empty string as the value of the Id parameter.
Because of the way that the MVC framework invokes controller actions, the URL /Home also matches the Index() method of the HomeController class in Listing 3.
Listing 3 - HomeController.cs (Index action with no parameter)
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
}
The Index() method in Listing 3 does not accept any parameters. The URL /Home will cause this Index() method to be called. The URL /Home/Index/3 also invokes this method (the Id is ignored).
The URL /Home also matches the Index() method of the HomeController class in Listing 4.
Listing 4 - HomeController.cs (Index action with nullable parameter)
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
[HandleError]
public class HomeController : Controller
{
public ActionResult Index(int? id)
{
return View();
}
}
}
In Listing 4, the Index() method has one Integer parameter. Because the parameter is a nullable parameter (can have the value Null), the Index() can be called without raising an error.
Finally, invoking the Index() method in Listing 5 with the URL /Home causes an exception since the Id parameter is not a nullable parameter. If you attempt to invoke the Index() method then you get the error displayed in Figure 1.
Listing 5 - HomeController.cs (Index action with Id parameter)
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
[HandleError]
public class HomeController : Controller
{
public ActionResult Index(int id)
{
return View();
}
}
}
I have an asp.net MVC site and i would like to go to a controller without an action, but i would also like to be able to give an action on the same or other controllers.
So lets say i have Page.
I would like to be able to access the following urls
MY_URL (nothing else) - This would get another page with id = 1, or name = Home (business logic doesnt matter)
MY_URL/Page/id - This will get a page with a particular Id
MY_URL/Page/Create - Create a new page
MY_URL/Page/Delete - Delete a page
MY_URL/Page/Edit - Edit a page
I thought this would do it, but Create/Delete/Edit dont work (they just go to MY_URL/page with no id)
routes.MapRoute(
name: "PageWithId",
url: "Page/{id}",
defaults: new { controller = "Page", action = "Index" }
);
routes.MapRoute(
name: "default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Page", action = "Index", id = UrlParameter.Optional }
);
Here is my controller
public class PageController : Controller
{
private PageService _service;
public PageController(PageService service)
{
_service = service;
}
public async Task<ActionResult> Index(int? id)
{
... code to get page if id <> null
... code to get home page id id = null
// return view
return View(model);
}
public ActionResult Create()
{
return View();
}
... Delete, Edit methods implemented
}
Any help would be appreciated
My MVC4 website shows items from a database The user can 'refine' their search from within a web form. After this, they click the search button and their results are shown.
At this stage, I only have 1 route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/",
defaults: new { controller = "Home", action = "Index" }
);
When I load the page for the first time, the address is www.mydomain.com/products/connectors/, after I make a search it appends my querystring
www.mydomain.com/products/connectors/?Gender=1
Now, I'm adding pagination and would like the user to be able to select Next page. I've used Marc's answer from How do I do pagination in ASP.NET MVC? to do this. Pagination works great.
This is the routeconfig.cs
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "AllRefineSearch",
url: "{controller}/{action}/{startIndex}/",
defaults: new { controller = "Products", action = "Connectors", startIndex = 0, pageSize = 10 }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/",
defaults: new { controller = "Home", action = "Index" }
);
}
}
The issue though is now when I click the search button, my Controller and Action are removed from the address. In other words, the address is www.mydomain.com/?Gender=1
I don't know how to keep the controller and action in the URL as I thought the route was specifying this!
My form is
#using (Html.BeginForm("Connectors", "Products", FormMethod.Get))
{
#Html.DropDownListFor(a => a.Gender, Model.ConnectorRefineSearch.Gender, "---Select---")
<input type="submit" value="Search" class="searchButton" />
}
And my controller
[HttpGet]
public ActionResult Connectors(ConnectorVm connector, int startIndex, int pageSize)
{
connector.UpdateSearch();
return View(connector);
}
The problem is your AllRefineSearch route with its default values: "Products" controller, "Connectors" action and "0" startIndex.
Providing default values in a route also means that those segments are optional. In your case the url "/" will match that route, and each segment will take its default value.
A similar process is followed when generating a Url for a link,form, etc. You are providing "Products" as controller and "Connectors" as action, so the AllRefineSearch will be used. Because they are the default values, it will simplify the url for the form tag as "/". Finally on submit the inuput values are added in the query string.
Try without providing default values in the search route for the controller and action segments:
routes.MapRoute(
name: "AllRefineSearch",
url: "{controller}/{action}/{startIndex}/",
defaults: new { startIndex = 0, pageSize = 10 }
);
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 }
);