Route to different controller and action if action does not exist - c#

I currently have 2 controllers, MemberController and Admincontroller, and is working fine if I use it like the below (different actions) :
http://localhost/member/delete/ME222
http://localhost/admin/view/AD321
I have my route config which looks like this :
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home",
action = "Index", id = UrlParameter.Optional }
);
But now I have created a shared action (Detail) for both Member and Admin, which I put in my SharedController, and want to access it like so :
http://localhost/member/detail/ME222
http://localhost/admin/detail/AD321
Ofcourse when I hit the above url's, the action does not exist in the Admin- and MemberController.
How do I route the the above to go to the SharedController's action if the current current action in the controller (member or admin) does not exist? (not just the Detail action, but for all actions that doesn't exist)
Thanks
David

If you have common actions for both controllers you may simply create UserController which will be base class for Member and Admin controllers. Then you may put all common actions inside UserController and it should work.
If you want to override something (or for example put mark actions with different attributes for each role) you may make action virtual and then override it in child class.

You will need to make sure the action always exists... perhaps you can make a base class for your controllers.
Then inside the base action you can simply return:
this.RedirectToAction("action", "controller");
Pointing this at the relevant action on the shared controller.

Related

MVC Attribute Routing RoutePrefix does not work with default routing

I have a work-around, but I'd really like to know why this doesn't appear to work in MVC. (.Net 4.6.1)
I have a controller which I want to use a RoutePrefix:
[RoutePrefix("entry")]
public class DefaultController : Controller
{
[HttpGet]
[Route(), Route("Index")]
public ActionResult Index()
{
// ...
}
}
In the route config:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "entry", action = "index", id = UrlParameter.Optional }
The issue is that with this configuration, running under local IIS to test, navigating to "localhost/testApp/entry" works, "localhost/testApp/entry/index" works, however the default "localhost/testApp/" results in a 404.
This has been doing my head in because on a fresh project with the default controllers and a default set to "home" and "index" the "localhost/testApp" would render Home/Index without an issue.
I narrowed it down to the RoutePrefix being the issue. If I remove the RoutePrefix and change the defaults to: new { controller = "default", action = "index", id = UrlParameter.Optional }
Then "localhost/testApp" works, but obviously this requires using /default for other routes rather than /entry.
Also, if I leave the prefix in (switching the default controller back to "entry") and add Route("~/") to the Index method, then "localhost/testApp" also works as according to the doco that a ~ route overrides the route prefix.
I'd like to know if there is an explanation why RoutePrefix doesn't seem to play nice with default routing? I'm fine with adding a ~/ route for that default action, but it seems I'm missing some understanding on how RoutePrefix is intended to be used.
Action attribute routing has the highest priority. If you use it only route attributes will be working, everything else will be ignored. You can to one action as many routes as you need.
Since you have 2 variants - Route() and Route("Index") it works only for 2 urls -"localhost/testApp/entry" and "localhost/testApp/entry/index".
if you remove Route() it will work only for one url-lcalhost/testApp/entry/index".
If you add 3rd Route("~/") it will work for 3rd url "localhost/testApp"
Sign ~ means that any prefixes should be ignored, it starts from root.
So you can not use default conventional routing on Index action since it is only obeys routing attributes.
Also, you have a controller [RoutePrefix("entry")] attribute routing too and it that next highest priority and because of this it overrides your convention routing in the config file. This is why default routing doesn't work for this controller and it doesn't go to Index automaticaly. To make default route work you need to remove route prefix and fix web config
defaults: new { controller = "default", action = "index", id = UrlParameter.Optional }
Current default controller = "entry" doesn't exist at all.
So you have two choices to have Index as default route action - remove all attribute routing and lost all another extra routes or add one more.
Thanks to Serge for helping point out a bad assumption I had about [RoutePrefix]. The problem here turns out that [RoutePrefix] is not a substitute name for a controller, (though that is how it behaves on the surface) but rather a prefix to each individual action. While the mapping in the URL will be identical:
Example 1:
public class EntryController
{
public ActionResult Index() { ... }
}
Example 2:
[RoutePrefix("Entry")]
public class DefaultController
{
[Route("Index")]
public ActionResult Index() { ... }
}
Both of these examples would resolve "localhost/testApp/entry/index", however only the first mapping would be considered as a match for {controller}/{action} and resolve a "defaults" mapping of "entry/index".
So if an action /w Attribute-based routing needs to be made a root default you need to explicitly declare it as the root using [Route()] if there is no [RoutePrefix], or [Route("~/")] if there is a [RoutePrefix]. since it won't be included in the {controller}/{action} routing. (Verified by removing the Default {controller}/{action} routing entirely).

How can I add an alternative route to a controller method in MVC Core to support a legacy endpoint

The following code I am trying is changing the route so that it is only accessible via [Area]/[Controller]/DailyStatusSummary - is there any way to just add it as an alternative route?
[HttpGet("[Area]/[Controller]/DailyStatusSummary")]
public async Task<IActionResult> CompanyStatusSummary()
{
... etc.
Background:
I used to have a controller action named DailyStatusSummary. I have refactored my code to give better names to actions, and this means this action in particular is now called CompanyStatusSummary. I am wary some users have bookmarks to the old DailyStatusSummary endpoint as it's a popular page, so I am trying to add this as an alternative route (so if you navigate to either the old or new endpoint, it hits the CompanyStatusSummary action.)
In App_Start\RouteConfig.cs you can create a specific route. Assuming your area is "areaABC" and your controller is "controllerXYZ", and only the action changes, something like this may work:
routes.MapRoute(
name: "Alternate",
url: "areaABC/controllerXYZ/DailyStatusSummary",
defaults: new { area = "areaABC", controller = "controllerXYZ", action = "CompanyStatusSummary"}
);
And the action in the controller should keep the CompanyStatusSummary (or remove if catched with generic route):
[HttpGet("[Area]/[Controller]/CompanyStatusSummary")]
public async Task<IActionResult> CompanyStatusSummary()
{
For .Net Core 3.1, the route mapping should be done in app.UseEndpoints, mapping the controller route:
endpoints.MapControllerRoute(
name: "Alternate",
pattern: "areaABC/controllerXYZ/DailyStatusSummary",
defaults: new { area = "areaABC", controller = "controllerXYZ", action = "CompanyStatusSummary" });

How to MapRoute to a sub controller

I have a file, AdminController.cs, that currently holds the controllers for every action in the admin section of my site. Obviously, this is getting huge, and I'd like to delegate control to a different controller for each application.
For instance:
www.mysite.com/Admin/Car currently looks to AdminController.cs to decide what to do. So when a user adds a car, there is an ActionResult in AdminController.cs called AddCar(). I would like this instead to look to CarController.cs to find AddCar().
So I after some research, I added this to my RouteConfig file:
routes.MapRoute(
name: "/Admin/Car"
url: "{parent}/{controller}/{action}",
defaults: new { parent = "Admin", action = "Index" },
constraints: new { controller = "Car"}
);
I commented out the ActionResults related to 'Car' in AdminController, and added them to CarController.
However, I'm getting "The resource cannot be found." when I navigate to www.mysite.com/Admin/Car.
How can I use a different controller, but with the URL still in the Admin realm?
You could add a controller action 'Car' to the Admin controller which redirects to the relevant action in the Car controller. But, Areas are probably what you want.

adding custom view name in asp.net mvc4

I am building an application in .net mvc4 that is based on business promotion and sales store.
User on this web application would be able to use product and access his/her personal business page also, that page can be promoted in future.
So I added one controller- Mypanel and a view of user's personal or professional business page _Mypanel.
Now the url access to this page is Bizcopter.com/Mypanel/_Mypanel
I want a custom user defined page name-
i.e. If a business name is - BookStore
Then I want to add a view in this same controller with the name of BookStore, So URL of personal business page would be-
Bizcopter.com/Mypanel/BookStore/ and this business holder can promote his business page with this URL.
Let me know if these are possible-
Replacing the view's name of user's choice
Add a view from client side in this same controller
I don't have any idea how to make it happen so don't have any trying code.
Site URL- http://bizcopter.com/Mypanel/_Mypanel
You don't need a separate view and controller action for each business.
I would create a controller and view called MyPanel. The controller takes a parameter called something like businessName that will load data related to the parameter.
By default you'll have a route in your AppStart/RouteConfig.cs which may look like this:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
The default URL structure might look something similar to: http://localhost:{PortNumber}/{Controller}/{Action}
Where we can attribute the following:
Controller = Home
Action = Index
Now if you want something similar to how you have it, you'd want something along the lines of:
http://testing.com/Fruits/Apples
Controller = Fruits
Action = Apples
By default, a URL pattern will match any URL that has the correct number of segments, in this case {controller}/{action}
Overall you should just need the MyPanel controller, and a controller taking a parameter of string which loads the correct Object/Model into the view.
Source: Pro ASP.NET MVC 4 - Adam Freeman
As the others said you can add a new route.Consider this code:
routes.MapRoute(
name: "MyCustomRoute",
url: "MyPanel/{name}"
defaults: new { controller = "MyPanel", action = "MyAction", name="" }
);
In this route if user type this URL:
Bizcopter.com/Mypanel/
Then it goes to your MyAction in your MyPanel Controller by default.Actually it will always go to MyAction, and in your MyAction, you must take the name parameter and redirect to user to the Relevant Action like this:
public ActionResult MyAction()
{
var name = RouteDate.Values["name"];
// check the name and redirect user to another action if it necessary
if(name == "BookStore") return RedirectToAction("BookStore","Mypanel");
}

URL routing in asp.net mvc

i have a ApplicationController class with an action called Admin
so my url is www.mysite.com/Application/Admin
is there anyway i can have the routing be www.mysite.com/Admin and go to this method.
i know i can do this by creating an AdminController but for this one function i thought it was easier to just put in another controller
Put this above your default route:
routes.MapRoute(
"ShortRoute",
"{action}",
new { controller = "Application", action = "Index"}
);
You can set the Application controller and the Admin method as the default controller and action, using parameter defaults:
routes.MapRoute(
"Default", // Route name
"{action}", // URL with parameters
new { controller = "Application", action = "Admin" }
);
If this is your last route, it will match any request that does not have a controller name and an action name in it. In this particular example, even a request without an action will execute your Admin action, since it's the default action.
Note that routes with parameter defaults can create strange behavior in your existing routes, if you have any. You can always use the ASP.NET MVC Routing Debugger to test which routes match a given URL.

Categories

Resources