Im new to MVC and I would like to ask about routing and controllers.
I have a controller called an LprController
public ActionResult Index()
{
return View();
}
and I have a view called ScanPage
#model FCoai.FCWCF.PCSResult
#{
ViewBag.Title = "ScanPage";
}
<h2>ScanPage</h2>
and here's my routeconfig
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I'm trying to directly display the scanpage screen instead of the regular MVC about page but I'm having no success. I'm using a service reference that's why I have no model class, please give me some tips on how to do response.redirects like how I'm used to doing with regular asp web programming.
To display the scan page as a default page in your web app, you need to do three things:
Add the following action to your controller "it should match the view name":
public ActionResult ScanPage()
{
return View();
}
Make sure your scanpage.chtml is placed in the following path "views/Lpr/scanpage.cshtml". Note that Lpr in the path is the name of your controller "without the Controller suffix".
Make your page the default page in the following routing line:
So, you need to change this:
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
into this:
defaults: new { controller = "Lpr", action = "ScanPage", id = UrlParameter.Optional}
That's it. Hoping this would help you.
Related
How can I replicate this default MVC route code below but to work with multiple ActionResults that are in the home controller. I want them to work just like Index where you do not need /Home/Index in the url to hit example.com/index
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I would like to hit example.com/about and example.com/contact without needing the the controller name in the beginning.
I have tried adding that same code but replaced Index with another action method and it works but it doesn't allow you to have more than 1 existing in this structure at the same time.
Solution?
Ok so I think I got it to work after reading this thread:
ASP.NET MVC - Removing controller name from URL
In the RouteConfig I added the following right before the default route:
routes.MapRoute(
"Root",
"{action}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { isMethodInHomeController = new RootRouteConstraint<HomeController>() }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Then inside of the Controller whos name you are trying to remove from the URL you need to add this:
public class RootRouteConstraint<T> : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var rootMethodNames = typeof(T).GetMethods().Select(x => x.Name.ToLower());
return rootMethodNames.Contains(values["action"].ToString().ToLower());
}
}
Now if I go to example.com/about , it works and I don't have to use example.com/Home/About
On each index view page which contain list, I'm using ASP.NET MVC AJAX to sort and filter the list. The list is in the partial view. Everything looks so fine until I have a view with a parameter (reference key/FK)
I don't add any routes, just using the default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
so the url is http://localhost:49458/TimeKeeper/New?billingID=7. If the url in that format, the AJAX sort and filter are not working. I tried to add a new route:
routes.MapRoute(
name: "TimeKeeperNew",
url: "TimeKeeper/New/{billingID}",
defaults: new { controller = "TimeKeeper", action = "New", billingID = "" }
);
so the url become: http://localhost:49458/TimeKeeper/New/7.
Now, the ajax sort and filter are working.
Is there anyone can explain me, what's the problem? Did I use the correct way (by adding a new route) or is there any other way?
I don't even understand why you are saying primary key as MVC has no concept of this.
With only (assuming for the duration of this answer until the break):
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home",
action = "Index",
id = UrlParameter.Optional }
);
Any route that does not define id will be appended to the url with the value.
Url.Action("New", "TimeKeeper", new { billingID = 7 })
Always will produce
http://localhost:49458/TimeKeeper/New?billingID=7
Because "billingID" != "id"
So your options are another MapRoute which I would not recommend, or use Id:
Url.Action("New", "TimeKeeper", new { id = 7 })
which always produces:
http://localhost:49458/TimeKeeper/New/7
Optionally:
public class TimerKeeperController
{
public ActionResult New(string id)
{
int billingId;
if (!string.TryParse(id, out billingId)
{
return RedirectToAction("BadBillingId")
}
....
}
}
BREAK
What about if there are 2 parameters, let's say billingID and clientGroupID? I don't quite understand routing in depth, could you help me to explain this in the answer?
Now you need another MapRoute:
routes.MapRoute(
name: "Default2",
url: "{controller}/{action}/{id}/{id2}",
defaults: new { controller = "Home",
action = "Index",
id = UrlParameter.Optional,
{id2} = UrlParameter.Optional }
);
And it is required to be before or after the previous MapRoute because anything that would work for this route will work for the previous route, thus this route will never be called. I can't exactly remember which way it goes at the moment, but if you test it, you'll figure it out quickly.
Then you can have:
http://localhost:49458/TimeKeeper/Copy/7/8
with:
public ActionResult Copy(string id, string id2)
{
....
}
notes
Yes you don't have to use a string and parse the values, you could use constraints on the MapRoute or just use Int and throw errors if someone manually types http://localhost:49458/TimeKeeper/New/Bacon.
I have a the following default route set up and it works fine:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Here is an example of successful route for me: "/PositionDetail/Candidates/2"
This is all fine and dandy, but the issue I have is that I want to set up a route that goes deeper. i.e. "/PositionDetail/Candidates/2/GetMoreCandidates" and "/PositionDetail/Candidates/2/Resume/3" where the Resume would be another action that I want to perform, and 3 would be ID. Note: Each of these route will load a new page, and not some partial view.
How do I set something up like this, and what would the 'PositionDetail' Controller Look like?
For example, for second task it may be as follows:
public ActionResult Resume(int CandidateID, int ResumeID)
{
return View();
}
In your Routing:
routes.MapRoute(
"Resume", // Route name
"{controller}/Candidates/{CandidateID}/{action}/{ResumeID}", // URL with parameters
new { controller = "PositionDetail", action = "Resume", CandidateID = UrlParameter.Optional, ResumeID= UrlParameter.Optional }
);
For fist task - the same logic
I don't find how I can create a "fake" subfolder in MVC4.
I want that an URL like
AREA/CONTROLLERNAME/FAKEFOLDER/ACTION/
goes to
AREA/CONTROLLERNAME/ACTION
Is it possibile? Any suggestions?
Thanks!
Have you tried using routing? For example assuming you have an Admin area:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/FAKEFOLDER/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
Now when you request /admin/home/fakefolder/index the Index action of HomeController within the Admin are will be executed.
You could add a MapRoute that expects an extra parameter in your route (fakefolder in the example below). Then, the routing occurs as usual, where the controller's action serves the page. Example:
routes.MapRoute(
name: "FakeFolder",
url: "{controller}/{fakefolder}/{action}",
defaults: new { controller = "home", action = "index", fakefolder = UrlParameter.Optional}
);
Notice that with this routing you can use any "folder name" since it is just a placeholder.
Url example:
myController/SomeFakeFolder/someAction will execute the action someAction in myController
I have a problem. I have a area in MVC 3 called Page that works as it should.
I just added a new Area called Media and now I get "the resource cannot be found" for that new area. I am going crazy, since it looks exactly like the PageArea that works.
Here is the MediaAreaRegistration.cs
public override string AreaName
{
get
{
return "Media";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Media_default",
"{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
Here is my global.asax
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
I am trying to access via localhost/media/, but I am just getting "the resource cannot be found".
Any ideas?
Check the Namespace of the Controller;
In my case; the default route was:
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
defaults: new {controller = "Home", action = "Index", AreaName="Admin", id = UrlParameter.Optional },
namespaces: new[] { "MyApp.Admin.Controllers"}
);
But when I was create the controller, the MVC automatically set "MyApp.WebUI.Areas.Admin.Controllers" as the namespace of the new Controller; I Changed the namespace to what I defined in default route as "MyApp.Admin.Controllers" and application works fine.
Typically, when you create an area, you will get a somewhat different default route than what is in global.asax. For example, I created a Media area in an MVC3 project, and the default route looks like this:
context.MapRoute(
"Media_default",
"Media/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
Routes in areas are really no different than routes defined in your global asax, except that they look for controllers in a different namespace. Also, they are loaded before the routes in your global.asax. You can see this because in Application_Start, RegisterAllAreas is invoked before RegisterRoutes.
Typically, this is the URL schema for root controllers with routes defined in your global.asax:
base/ControllerAName/Action1Name
base/ControllerAName/Action2Name
base/ControllerBName/Action6Name
...and so on. This is the "convention" you get with MVC out of the box. Look closely, and you will see that this pattern matches the base route definition in your global asax:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index",
id = UrlParameter.Optional } // Parameter defaults
);
On the other hand, the convention when you use areas is that your "conventional" URL schema will look like this:
base/AreaName/ControllerAName/Action1Name
base/AreaName/ControllerAName/Action2Name
base/AreaName/ControllerBName/Action6Name
Notice the difference? This is why your default route definition in the area registration looks like this: "Media/{controller}/{action}/{id}"
With all of this said, there is nothing stopping you from deviating from the conventions. It sounds like you want to have an area named Media, and a URL base/media that goes to some action method on some controller in the area. If that is correct, try this -- remembering to put your more specific route before the default route generated by MVC:
context.MapRoute(null,
"media",
new { action = "Index", controller = "Media" }
);
context.MapRoute(
"Media_default",
"Media/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
This means that MVC will match base/media to the Index action method on the MediaController in your Media area, since that route is defined first.
Also, when you create a new area, don't change any namespaces. This will only cause you problems.
Another tip is to not give route names to your routes. Notice how I passed null as the first argument. This is considered good practice -- accessing routes by name can get very messy.
I suggest you try starting a new project, or creating a new area, and trying these suggestions. Grasping routes coming from webforms can be tricky, but once you get a handle on it, I think you will find it superior to the URL-TO-FILE mapping in webforms.
In my case, someone added routes.Clear() in RouteConfig.cs, before any area ever existed. But now I added an area, this was erasing all its routes.