I have a web page www.example.com which points to a HomeController index. When I run the website I get the HomeView.
Now the requirement is when I type www.example.com/Japan I need to run a different view.
What I did:
public ActionResult Index(string country)
{
ViewBag.Message = "my country=" + country;
return View();
}
But it gives me an error:
The current request for action 'Index' on controller type 'HomeController'
is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Index() on type MvcApplication_2.Controllers.HomeController
System.Web.Mvc.ActionResult Index(System.String) on type MvcApplication_2.Controllers.HomeController
What should I be doing to achieve this one?
I do not want to use http://example.com/country/japan.
I want to use http://example.com/japan.
my code:
RouteConfig.cs
namespace MvcApplication_2
{
public class 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.MapRoute(
name: "ByCountry",
url: "{country}",
defaults: new { controller = "Home", action = "IndexByCountry" }
);
}
}
}
Homecontroller.cs
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
[ActionName("IndexByCountry")]
public ActionResult Index(string country)
{
ViewBag.Message = "Japan man.";
return View("Index");
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
You can't have the same HTTP verb for the same action name. In other words, having HttpGet for the same action name, even an overload, isn't possible.
You have three options:
Change one or your action methods to a different HTTP action verb...
[HttpGet]
public ActionResult Index()
{
//..
}
[HttpPost]
public ActionResult Index(string country)
{
//..
}
Or, change the name of your action method...
public ActionResult CountryIndex(string country)
{
ViewBag.Message = "my country=" + country;
return View();
}
Or, you can change the action name from the overloaded method...
public ActionResult Index()
{
//..
}
[ActionName("IndexByCountryName")]
public ActionResult Index(string country)
{
//..
}
Working example
This uses the last option, keeping the method name overloaded but specify the ActionNameAttribute for the overload
Actions
public ActionResult Index()
{
ViewBag.Message = "no country selected!";
return View();
}
[ActionName("IndexByCountry")]
public ActionResult Index(string country)
{
ViewBag.Message = string.Format("County selected :: {0}", country);
// the below ActionResult reuses the Index view but
// here you could have a separate view for the country
// selection if you like
//
return View("Index");
}
Routes
routes.MapRoute(
name: "ByCountry",
url: "{country}",
defaults: new { controller = "Home", action = "IndexByCountry" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
You can use AttributeRouting.
[Route("Home/Index/{country}")
public ActionResult Index(string country)
{
ViewBag.Message = "my country=" + country;
switch(country)
{
case "Country1":
return View("ViewName")
}
// To do
}
Related
I have a requirement where the resources on the home controller should be accessed without the need to enter the name of the controller in the URL. For instance, index action should be loaded when I navigate to mysite.com/ and contact page should be loaded using mysite.com/contact and so on.
The controller below satisfies this requirement but I wonder if there is a way to remove Route attributes that have the same name as the controller action?
For example, using [Route("contact")] for action contact does not make sense. When I remove this route attribute, the URL is generated as mysite.com/home/contact whereas I want this to be mysite.com/contact.
[RoutePrefix("")] // Remove the name of the controller from the URL
public class HomeController : Controller
{
public ViewResult Index()
{
return View("Index");
}
[Route("contact")]
public ViewResult Contact()
{
return View("Contact");
}
[Route("about")]
public ViewResult About()
{
return View("About");
}
[Route("terms-and-conditions")]
public ViewResult TermsAndConditions()
{
return View("TermsAndConditions");
}
}
FYI, here is my route config:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.LowercaseUrls = true;
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
and the Application_Start event:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Instead of using an empty value as the route prefix, I ended up using the route attribute on specific controller actions like the following:
public class HomeController : Controller
{
public ViewResult Index()
{
return View("Index");
}
[Route("contact-us")]
public ViewResult Contact()
{
return View("Contact");
}
[Route("about-us")]
public ViewResult About()
{
return View("About");
}
[Route("terms-and-conditions")]
public ViewResult TermsAndConditions()
{
return View("TermsAndConditions");
}
}
This ensures that each defined route is accessed from the root of the site.
Consider my route setting:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Question",
url: "{number}",
defaults: new { controller = "Home", action = "ViewQuestion" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { id = "\\d+" }
);
}
What I want is:
1) If a url like myserver/123, then call Home.ViewQuestion(string number).
2) Otherwise, search in controllers and actions, with Home/Index default action
What I am getting now when requesting myserver/123 is:
The view '123' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Home/123.aspx
~/Views/Home/123.ascx
~/Views/Shared/123.aspx
~/Views/Shared/123.ascx
~/Views/Home/123.cshtml
~/Views/Home/123.vbhtml
~/Views/Shared/123.cshtml
~/Views/Shared/123.vbhtml
My Action and View:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace AdvancedWebApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult ViewQuestion(int? number)
{
return View(number + "");
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
ViewQuestion.cshtml:
#model string
#{
ViewBag.Title = "ViewQuestion";
}
<h2>ViewQuestion: #Model</h2>
Instead of url: "{number}" , use url: "ViewQuestion/{number}" and your action code:
public ActionResult ViewQuestion(int? number)
{
//your code
}
From your controller's action, it's seems like you are returning the view name as the number passed to it. So MVC runtime is looking for 123.html or 123.aspx while you have defined your view as ViewQuestion.cshtml.
public ActionResult ViewQuestion(int? number)
{
return View(number + "");
}
You need to return the correct view name as following
public ActionResult ViewQuestion(int? number)
{
return View("ViewQuestion",number);
}
Turned out that I was calling controller helper method View(string viewName), as if it is View(object model) !!!
public ActionResult ViewQuestion(string questionNumber)
{
return View((object)questionNumber);
}
I have an existing Controller
public class HomeController : Controller
{
public ActionResult Index()
{
return Redirect("/Scorecard");
}
[OutputCache(Duration = 18000)]
public ActionResult Scorecard()
{
return View();
}
}
This currently Maps to http://siteurl/Home/Scorecard . I wanted to the segment http://siteurl/scorecard to redirect to this Controller Action . What would the best wayt to do this . I tried checking the RequestUrl in Session_Start in Global.aspx but the redirects dont seem to be happening . The other alternative I thought of was using a Different Controller like "ScorecardController" and then having a RedirectToAction("Scorecard","Home") in the Index view there.
you could add a FilterAccess class on your App_Start folder to do something like this:
public class FilterAcess : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
//Redirect
if (HttpContext.Current.Request.Url=="http://siteurl/scorecard"){
context.HttpContext.Response.Redirect("~/Home/Scorecard");
}
}
}
RedirectToAction is better way to do it, because, in case you change routing table later, redirect URL will be in adapted.
public class HomeController: Controller
{
public ActionResult Index()
{
return RedirectToAction("Scorecard");
}
[OutputCache(Duration = 18000)]
public ActionResult Scorecard()
{
return View();
}
}
You should also update RouteTable with additional route, before "Default" route:
public static void RegisterRoutes(RouteCollection routes)
{
routes.LowercaseUrls = true;
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "NoHomeSegmentInUrl",
url: "{action}/{id}",
defaults: new { controller = "Home", id = UrlParameter.Optional });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
And, for lower case routes you need line routes.LowercaseUrls = true;
Trying to add a MVC controller with read/write action using EntityFramework. My controller name is UsersController. When i hit add, VS creates a folder named Users and subdirectories like Create, Edit, Index etc.
My Entity-Model table name is Users.
When i try to reach them with links below, i got "The resource cannot be found 404" error.
http://localhost:64871/Users <br>
http://localhost:64871/Users/Index<br>
http://localhost:64871/Users/Create
I can reach links which i created with empty MVC controller option.
http://localhost:64871/Home<br>
http://localhost:64871/Home/Test
What can be wrong? Should i add some values to my RouteConfig file?
My RouteConfig.cs
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 }
);
}
My userscontroller look like;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Aplatform.Controllers
{
public class UsersController : Controller
{
private dbEntities db = new dbEntities();
//
// GET: /Users/
public ActionResult Index()
{
return View(db.Users.ToList());
}
//
// GET: /Users/Details/5
public ActionResult Details(Guid id = null)
{
Users users = db.Users.Find(id);
if (users == null)
{
return HttpNotFound();
}
return View(users);
}
//
// GET: /Users/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Users/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Users users)
{
if (ModelState.IsValid)
{
users.ID = Guid.NewGuid();
db.Users.Add(users);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(users);
}
//
// GET: /Users/Edit/5
public ActionResult Edit(Guid id = null)
{
Users users = db.Users.Find(id);
if (users == null)
{
return HttpNotFound();
}
return View(users);
}
//
// POST: /Users/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Users users)
{
if (ModelState.IsValid)
{
db.Entry(users).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(users);
}
//
// GET: /Users/Delete/5
public ActionResult Delete(Guid id = null)
{
Users users = db.Users.Find(id);
if (users == null)
{
return HttpNotFound();
}
return View(users);
}
//
// POST: /Users/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(Guid id)
{
Users users = db.Users.Find(id);
db.Users.Remove(users);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
Thank you!
I've run into similar situations where the default route doesn't handle a path. I've added fallback routes to handle these cases. Try this:
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.MapRoute(
name: "Users",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Users", action = "Index", id = UrlParameter.Optional }
);
}
After a while a figure out something new. If you have errors in your controller (syntax error.. etc) you can get 404 error. If you clear that errors, 404 will be automatically disappear.
I have the following action. I can hit this with
/basket/address?addressId=123
However i wonder how i can hit it with
/basket/address/123
public ActionResult Address(int addressId)
{
return RedirectToAction("Index");
}
my routes
routes.MapRoute(
"Default", // Route name
"{controller}.aspx/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
Change:
public ActionResult Address(int addressId)
to
public ActionResult Address(int id)