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.
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 two different Areas (User & Report) and they have two views (Login & Index) respectively.
What I am trying to do is on successful login user should be redirected to Report/Index page but its not working.
Its always inside User area only. Can some one point out what needs to be corrected here. Thanks!!! Help will be appreciated...
public class UserController : Controller
{
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(Models.User user)
{
if (ModelState.IsValid)
{
if (user.IsValid(user.UserName, user.Password))
{
return RedirectToAction("Report/Report/Index");
}
else
{
ModelState.AddModelError("", "Login data is incorrect!");
}
}
return View(user);
}
}
public class ReportController : Controller
{
// GET: Report/Report
public ActionResult Index()
{
return View();
}
}
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 = "User", action = "Login", id = UrlParameter.Optional },
namespaces: new[] { "DWP_MVC.Areas.User.Controllers" }
).DataTokens.Add("area", "User");
routes.MapRoute(
name: "Report",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Report", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "DWP_MVC.Areas.Report.Controllers" }
).DataTokens.Add("area", "Report");
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"User_default",
"User/{controller}/{action}/{id}",
new { action = "Login", id = UrlParameter.Optional }
);
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Report_default",
"Report/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
Your RedirectToAction() call must include the area name if you are using areas in your MVC structure.
In your example the following code would work:
return RedirectToAction("Index", "Report", new { area = "Report" });
As an aside, if you wish to redirect from one area to a controller/view which is not within the Area folder, you can utilize area = ""
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
}
I'm currently developing Edit page for one of the models, so I've set Edit page as default in Route Config. Problem is, that for some reason it's triggering Post event instead of Get. Example is very simple:
[HttpGet]
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
JobLine jobLine = db.JobLines.Find(id);
if (jobLine == null)
{
return HttpNotFound();
}
Mapper.CreateMap<JobLine, JobLineDTO>();
JobLineDTO joblineDTO = Mapper.Map<JobLine, JobLineDTO>(jobLine);
return View("Create",joblineDTO);
}
[HttpPost]
public ActionResult Edit(JobLineDTO jobLineDTO)
{
return View();
}
What could possibly be a reason for such behavior?
Route Config
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Joblines", action = "Edit", id = 1 /*UrlParameter.Optional*/ }
);
}